diff --git a/AndroidKernel.mk b/AndroidKernel.mk index f7e26617f63585d790ace41c5da8dac90339cf74..73a2232be4a2e202f555114185718b662bb5a311 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -10,6 +10,8 @@ ifneq ($(TARGET_KERNEL_APPEND_DTB), true) $(info Using DTB Image) INSTALLED_DTBIMAGE_TARGET := $(PRODUCT_OUT)/dtb.img endif +MAKE_ARGS := $(strip $(TARGET_KERNEL_MAKE_ARGS)) +KERNEL_DISABLE_DEBUGFS := $(TARGET_KERNEL_DISABLE_DEBUGFS) TARGET_KERNEL_MAKE_ENV := $(strip $(TARGET_KERNEL_MAKE_ENV)) ifeq ($(TARGET_KERNEL_MAKE_ENV),) @@ -138,6 +140,7 @@ $(info Using appended DTB) TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb endif +KERNEL_DEBUGFS := $(KERNEL_OUT)/tmp KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr KERNEL_MODULES_INSTALL ?= system KERNEL_MODULES_OUT ?= $(PRODUCT_OUT)/$(KERNEL_MODULES_INSTALL)/lib/modules @@ -162,6 +165,9 @@ mpath=`dirname $$mdpath`; rm -rf $$mpath;\ fi endef +$(KERNEL_OUT): $(KERNEL_DEBUGFS) + mkdir -p $(KERNEL_OUT) + ifneq ($(KERNEL_LEGACY_DIR),true) $(KERNEL_USR): $(KERNEL_HEADERS_INSTALL) rm -rf $(KERNEL_SYMLINK) @@ -170,9 +176,6 @@ $(KERNEL_USR): $(KERNEL_HEADERS_INSTALL) $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_USR) endif -$(KERNEL_OUT): - mkdir -p $(KERNEL_OUT) - $(KERNEL_CONFIG): $(KERNEL_OUT) $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_DEFCONFIG) $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ @@ -206,6 +209,17 @@ $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(clean-module-folder) endif +$(KERNEL_DEBUGFS): + KERNEL_DIR=$(TARGET_KERNEL_SOURCE) \ + DEFCONFIG=$(KERNEL_DEFCONFIG) \ + OUT_DIR=$(KERNEL_OUT) \ + ARCH=$(KERNEL_ARCH) \ + CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) \ + DISABLE_DEBUGFS=$(KERNEL_DISABLE_DEBUGFS) \ + $(TARGET_KERNEL_SOURCE)/disable_dbgfs.sh \ + $(real_cc) \ + $(TARGET_KERNEL_MAKE_ARGS) + $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG) && \ diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index f85ce9e327b98b94ab1f119f9ec15edf6a13ccfa..c1075ecfdb4b53dfdb17a75679114c1f9d94bf87 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -1,3 +1,459 @@ +===== General Properties ===== + +What: /sys/class/power_supply//manufacturer +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the name of the device manufacturer. + + Access: Read + Valid values: Represented as string + +What: /sys/class/power_supply//model_name +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the name of the device model. + + Access: Read + Valid values: Represented as string + +What: /sys/class/power_supply//serial_number +Date: January 2008 +Contact: linux-pm@vger.kernel.org +Description: + Reports the serial number of the device. + + Access: Read + Valid values: Represented as string + +What: /sys/class/power_supply//type +Date: May 2010 +Contact: linux-pm@vger.kernel.org +Description: + Describes the main type of the supply. + + Access: Read + Valid values: "Battery", "UPS", "Mains", "USB" + +===== Battery Properties ===== + +What: /sys/class/power_supply//capacity +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Fine grain representation of battery capacity. + Access: Read + Valid values: 0 - 100 (percent) + +What: /sys/class/power_supply//capacity_alert_max +Date: July 2012 +Contact: linux-pm@vger.kernel.org +Description: + Maximum battery capacity trip-wire value where the supply will + notify user-space of the event. This is normally used for the + battery discharging scenario where user-space needs to know the + battery has dropped to an upper level so it can take + appropriate action (e.g. warning user that battery level is + low). + + Access: Read, Write + Valid values: 0 - 100 (percent) + +What: /sys/class/power_supply//capacity_alert_min +Date: July 2012 +Contact: linux-pm@vger.kernel.org +Description: + Minimum battery capacity trip-wire value where the supply will + notify user-space of the event. This is normally used for the + battery discharging scenario where user-space needs to know the + battery has dropped to a lower level so it can take + appropriate action (e.g. warning user that battery level is + critically low). + + Access: Read, Write + Valid values: 0 - 100 (percent) + +What: /sys/class/power_supply//capacity_level +Date: June 2009 +Contact: linux-pm@vger.kernel.org +Description: + Coarse representation of battery capacity. + + Access: Read + Valid values: "Unknown", "Critical", "Low", "Normal", "High", + "Full" + +What: /sys/class/power_supply//current_avg +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports an average IBAT current reading for the battery, over a + fixed period. Normally devices will provide a fixed interval in + which they average readings to smooth out the reported value. + + Access: Read + Valid values: Represented in microamps + +What: /sys/class/power_supply//current_max +Date: October 2010 +Contact: linux-pm@vger.kernel.org +Description: + Reports the maximum IBAT current allowed into the battery. + + Access: Read + Valid values: Represented in microamps + +What: /sys/class/power_supply//current_now +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports an instant, single IBAT current reading for the battery. + This value is not averaged/smoothed. + + Access: Read + Valid values: Represented in microamps + +What: /sys/class/power_supply//charge_type +Date: July 2009 +Contact: linux-pm@vger.kernel.org +Description: + Represents the type of charging currently being applied to the + battery. + + Access: Read + Valid values: "Unknown", "N/A", "Trickle", "Fast" + +What: /sys/class/power_supply//charge_term_current +Date: July 2014 +Contact: linux-pm@vger.kernel.org +Description: + Reports the charging current value which is used to determine + when the battery is considered full and charging should end. + + Access: Read + Valid values: Represented in microamps + +What: /sys/class/power_supply//health +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the health of the battery or battery side of charger + functionality. + + Access: Read + Valid values: "Unknown", "Good", "Overheat", "Dead", + "Over voltage", "Unspecified failure", "Cold", + "Watchdog timer expire", "Safety timer expire", + "Over current", "Warm", "Cool", "Hot" + +What: /sys/class/power_supply//precharge_current +Date: June 2017 +Contact: linux-pm@vger.kernel.org +Description: + Reports the charging current applied during pre-charging phase + for a battery charge cycle. + + Access: Read + Valid values: Represented in microamps + +What: /sys/class/power_supply//present +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports whether a battery is present or not in the system. + + Access: Read + Valid values: + 0: Absent + 1: Present + +What: /sys/class/power_supply//status +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Represents the charging status of the battery. Normally this + is read-only reporting although for some supplies this can be + used to enable/disable charging to the battery. + + Access: Read, Write + Valid values: "Unknown", "Charging", "Discharging", + "Not charging", "Full" + +What: /sys/class/power_supply//technology +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Describes the battery technology supported by the supply. + + Access: Read + Valid values: "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", + "NiCd", "LiMn" + +What: /sys/class/power_supply//temp +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the current TBAT battery temperature reading. + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_alert_max +Date: July 2012 +Contact: linux-pm@vger.kernel.org +Description: + Maximum TBAT temperature trip-wire value where the supply will + notify user-space of the event. This is normally used for the + battery charging scenario where user-space needs to know the + battery temperature has crossed an upper threshold so it can + take appropriate action (e.g. warning user that battery level is + critically high, and charging has stopped). + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_alert_min +Date: July 2012 +Contact: linux-pm@vger.kernel.org +Description: + Minimum TBAT temperature trip-wire value where the supply will + notify user-space of the event. This is normally used for the + battery charging scenario where user-space needs to know the + battery temperature has crossed a lower threshold so it can take + appropriate action (e.g. warning user that battery level is + high, and charging current has been reduced accordingly to + remedy the situation). + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_max +Date: July 2014 +Contact: linux-pm@vger.kernel.org +Description: + Reports the maximum allowed TBAT battery temperature for + charging. + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_min +Date: July 2014 +Contact: linux-pm@vger.kernel.org +Description: + Reports the minimum allowed TBAT battery temperature for + charging. + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//voltage_avg, +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports an average VBAT voltage reading for the battery, over a + fixed period. Normally devices will provide a fixed interval in + which they average readings to smooth out the reported value. + + Access: Read + Valid values: Represented in microvolts + +What: /sys/class/power_supply//voltage_max, +Date: January 2008 +Contact: linux-pm@vger.kernel.org +Description: + Reports the maximum safe VBAT voltage permitted for the battery, + during charging. + + Access: Read + Valid values: Represented in microvolts + +What: /sys/class/power_supply//voltage_min, +Date: January 2008 +Contact: linux-pm@vger.kernel.org +Description: + Reports the minimum safe VBAT voltage permitted for the battery, + during discharging. + + Access: Read + Valid values: Represented in microvolts + +What: /sys/class/power_supply//voltage_now, +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports an instant, single VBAT voltage reading for the battery. + This value is not averaged/smoothed. + + Access: Read + Valid values: Represented in microvolts + +===== USB Properties ===== + +What: /sys/class/power_supply//current_avg +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports an average IBUS current reading over a fixed period. + Normally devices will provide a fixed interval in which they + average readings to smooth out the reported value. + + Access: Read + Valid values: Represented in microamps + + +What: /sys/class/power_supply//current_max +Date: October 2010 +Contact: linux-pm@vger.kernel.org +Description: + Reports the maximum IBUS current the supply can support. + + Access: Read + Valid values: Represented in microamps + +What: /sys/class/power_supply//current_now +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the IBUS current supplied now. This value is generally + read-only reporting, unless the 'online' state of the supply + is set to be programmable, in which case this value can be set + within the reported min/max range. + + Access: Read, Write + Valid values: Represented in microamps + +What: /sys/class/power_supply//input_current_limit +Date: July 2014 +Contact: linux-pm@vger.kernel.org +Description: + Details the incoming IBUS current limit currently set in the + supply. Normally this is configured based on the type of + connection made (e.g. A configured SDP should output a maximum + of 500mA so the input current limit is set to the same value). + + Access: Read, Write + Valid values: Represented in microamps + +What: /sys/class/power_supply//online, +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Indicates if VBUS is present for the supply. When the supply is + online, and the supply allows it, then it's possible to switch + between online states (e.g. Fixed -> Programmable for a PD_PPS + USB supply so voltage and current can be controlled). + + Access: Read, Write + Valid values: + 0: Offline + 1: Online Fixed - Fixed Voltage Supply + 2: Online Programmable - Programmable Voltage Supply + +What: /sys/class/power_supply//temp +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the current supply temperature reading. This would + normally be the internal temperature of the device itself (e.g + TJUNC temperature of an IC) + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_alert_max +Date: July 2012 +Contact: linux-pm@vger.kernel.org +Description: + Maximum supply temperature trip-wire value where the supply will + notify user-space of the event. This is normally used for the + charging scenario where user-space needs to know the supply + temperature has crossed an upper threshold so it can take + appropriate action (e.g. warning user that the supply + temperature is critically high, and charging has stopped to + remedy the situation). + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_alert_min +Date: July 2012 +Contact: linux-pm@vger.kernel.org +Description: + Minimum supply temperature trip-wire value where the supply will + notify user-space of the event. This is normally used for the + charging scenario where user-space needs to know the supply + temperature has crossed a lower threshold so it can take + appropriate action (e.g. warning user that the supply + temperature is high, and charging current has been reduced + accordingly to remedy the situation). + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_max +Date: July 2014 +Contact: linux-pm@vger.kernel.org +Description: + Reports the maximum allowed supply temperature for operation. + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//temp_min +Date: July 2014 +Contact: linux-pm@vger.kernel.org +Description: + Reports the mainimum allowed supply temperature for operation. + + Access: Read + Valid values: Represented in 1/10 Degrees Celsius + +What: /sys/class/power_supply//usb_type +Date: March 2018 +Contact: linux-pm@vger.kernel.org +Description: + Reports what type of USB connection is currently active for + the supply, for example it can show if USB-PD capable source + is attached. + + Access: Read-Only + Valid values: "Unknown", "SDP", "DCP", "CDP", "ACA", "C", "PD", + "PD_DRP", "PD_PPS", "BrickID" + +What: /sys/class/power_supply//voltage_max +Date: January 2008 +Contact: linux-pm@vger.kernel.org +Description: + Reports the maximum VBUS voltage the supply can support. + + Access: Read + Valid values: Represented in microvolts + +What: /sys/class/power_supply//voltage_min +Date: January 2008 +Contact: linux-pm@vger.kernel.org +Description: + Reports the minimum VBUS voltage the supply can support. + + Access: Read + Valid values: Represented in microvolts + +What: /sys/class/power_supply//voltage_now +Date: May 2007 +Contact: linux-pm@vger.kernel.org +Description: + Reports the VBUS voltage supplied now. This value is generally + read-only reporting, unless the 'online' state of the supply + is set to be programmable, in which case this value can be set + within the reported min/max range. + + Access: Read, Write + Valid values: Represented in microvolts + +===== Device Specific Properties ===== + What: /sys/class/power/ds2760-battery.*/charge_now Date: May 2010 KernelVersion: 2.6.35 diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 0cd608e3ed126444b2f99fce94bd5c23f0e4b336..a67387006a0fc1152e75ae09c3dee64dccc73b66 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -1,37 +1,40 @@ What: /sys/fs/f2fs//gc_max_sleep_time Date: July 2013 Contact: "Namjae Jeon" -Description: - Controls the maximun sleep time for gc_thread. Time - is in milliseconds. +Description: Controls the maximum sleep time for gc_thread. Time + is in milliseconds. What: /sys/fs/f2fs//gc_min_sleep_time Date: July 2013 Contact: "Namjae Jeon" -Description: - Controls the minimum sleep time for gc_thread. Time - is in milliseconds. +Description: Controls the minimum sleep time for gc_thread. Time + is in milliseconds. What: /sys/fs/f2fs//gc_no_gc_sleep_time Date: July 2013 Contact: "Namjae Jeon" -Description: - Controls the default sleep time for gc_thread. Time - is in milliseconds. +Description: Controls the default sleep time for gc_thread. Time + is in milliseconds. What: /sys/fs/f2fs//gc_idle Date: July 2013 Contact: "Namjae Jeon" -Description: - Controls the victim selection policy for garbage collection. +Description: Controls the victim selection policy for garbage collection. + Setting gc_idle = 0(default) will disable this option. Setting + gc_idle = 1 will select the Cost Benefit approach & setting + gc_idle = 2 will select the greedy approach. What: /sys/fs/f2fs//reclaim_segments Date: October 2013 Contact: "Jaegeuk Kim" -Description: - Controls the issue rate of segment discard commands. - -What: /sys/fs/f2fs//max_blkaddr +Description: This parameter controls the number of prefree segments to be + reclaimed. If the number of prefree segments is larger than + the number of segments in the proportion to the percentage + over total volume size, f2fs tries to conduct checkpoint to + reclaim the prefree segments to free segments. + By default, 5% over total # of segments. + +What: /sys/fs/f2fs//main_blkaddr Date: November 2019 Contact: "Ramon Pantin" Description: @@ -40,227 +43,298 @@ Description: What: /sys/fs/f2fs//ipu_policy Date: November 2013 Contact: "Jaegeuk Kim" -Description: - Controls the in-place-update policy. +Description: Controls the in-place-update policy. + updates in f2fs. User can set: + 0x01: F2FS_IPU_FORCE, 0x02: F2FS_IPU_SSR, + 0x04: F2FS_IPU_UTIL, 0x08: F2FS_IPU_SSR_UTIL, + 0x10: F2FS_IPU_FSYNC, 0x20: F2FS_IPU_ASYNC, + 0x40: F2FS_IPU_NOCACHE. + Refer segment.h for details. What: /sys/fs/f2fs//min_ipu_util Date: November 2013 Contact: "Jaegeuk Kim" -Description: - Controls the FS utilization condition for the in-place-update - policies. +Description: Controls the FS utilization condition for the in-place-update + policies. It is used by F2FS_IPU_UTIL and F2FS_IPU_SSR_UTIL policies. What: /sys/fs/f2fs//min_fsync_blocks Date: September 2014 Contact: "Jaegeuk Kim" -Description: - Controls the dirty page count condition for the in-place-update - policies. +Description: Controls the dirty page count condition for the in-place-update + policies. What: /sys/fs/f2fs//min_seq_blocks Date: August 2018 Contact: "Jaegeuk Kim" -Description: - Controls the dirty page count condition for batched sequential - writes in ->writepages. - +Description: Controls the dirty page count condition for batched sequential + writes in writepages. What: /sys/fs/f2fs//min_hot_blocks Date: March 2017 Contact: "Jaegeuk Kim" -Description: - Controls the dirty page count condition for redefining hot data. +Description: Controls the dirty page count condition for redefining hot data. What: /sys/fs/f2fs//min_ssr_sections Date: October 2017 Contact: "Chao Yu" -Description: - Controls the fee section threshold to trigger SSR allocation. +Description: Controls the free section threshold to trigger SSR allocation. + If this is large, SSR mode will be enabled early. What: /sys/fs/f2fs//max_small_discards Date: November 2013 Contact: "Jaegeuk Kim" -Description: - Controls the issue rate of small discard commands. +Description: Controls the issue rate of discard commands that consist of small + blocks less than 2MB. The candidates to be discarded are cached until + checkpoint is triggered, and issued during the checkpoint. + By default, it is disabled with 0. -What: /sys/fs/f2fs//discard_granularity -Date: July 2017 -Contact: "Chao Yu" -Description: - Controls discard granularity of inner discard thread, inner thread +What: /sys/fs/f2fs//discard_granularity +Date: July 2017 +Contact: "Chao Yu" +Description: Controls discard granularity of inner discard thread. Inner thread will not issue discards with size that is smaller than granularity. - The unit size is one block, now only support configuring in range - of [1, 512]. + The unit size is one block(4KB), now only support configuring + in range of [1, 512]. Default value is 4(=16KB). -What: /sys/fs/f2fs//umount_discard_timeout -Date: January 2019 -Contact: "Jaegeuk Kim" -Description: - Set timeout to issue discard commands during umount. - Default: 5 secs +What: /sys/fs/f2fs//umount_discard_timeout +Date: January 2019 +Contact: "Jaegeuk Kim" +Description: Set timeout to issue discard commands during umount. + Default: 5 secs What: /sys/fs/f2fs//max_victim_search Date: January 2014 Contact: "Jaegeuk Kim" -Description: - Controls the number of trials to find a victim segment. +Description: Controls the number of trials to find a victim segment + when conducting SSR and cleaning operations. The default value + is 4096 which covers 8GB block address range. What: /sys/fs/f2fs//migration_granularity Date: October 2018 Contact: "Chao Yu" -Description: - Controls migration granularity of garbage collection on large - section, it can let GC move partial segment{s} of one section - in one GC cycle, so that dispersing heavy overhead GC to - multiple lightweight one. +Description: Controls migration granularity of garbage collection on large + section, it can let GC move partial segment{s} of one section + in one GC cycle, so that dispersing heavy overhead GC to + multiple lightweight one. What: /sys/fs/f2fs//dir_level Date: March 2014 Contact: "Jaegeuk Kim" -Description: - Controls the directory level for large directory. +Description: Controls the directory level for large directory. If a + directory has a number of files, it can reduce the file lookup + latency by increasing this dir_level value. Otherwise, it + needs to decrease this value to reduce the space overhead. + The default value is 0. What: /sys/fs/f2fs//ram_thresh Date: March 2014 Contact: "Jaegeuk Kim" -Description: - Controls the memory footprint used by f2fs. +Description: Controls the memory footprint used by free nids and cached + nat entries. By default, 1 is set, which indicates + 10 MB / 1 GB RAM. What: /sys/fs/f2fs//batched_trim_sections Date: February 2015 Contact: "Jaegeuk Kim" -Description: - Controls the trimming rate in batch mode. - +Description: Controls the trimming rate in batch mode. + What: /sys/fs/f2fs//cp_interval Date: October 2015 Contact: "Jaegeuk Kim" -Description: - Controls the checkpoint timing. +Description: Controls the checkpoint timing, set to 60 seconds by default. What: /sys/fs/f2fs//idle_interval Date: January 2016 Contact: "Jaegeuk Kim" -Description: - Controls the idle timing for all paths other than - discard and gc path. +Description: Controls the idle timing of system, if there is no FS operation + during given interval. + Set to 5 seconds by default. What: /sys/fs/f2fs//discard_idle_interval Date: September 2018 Contact: "Chao Yu" Contact: "Sahitya Tummala" -Description: - Controls the idle timing for discard path. +Description: Controls the idle timing of discard thread given + this time interval. + Default is 5 secs. What: /sys/fs/f2fs//gc_idle_interval Date: September 2018 Contact: "Chao Yu" Contact: "Sahitya Tummala" -Description: - Controls the idle timing for gc path. +Description: Controls the idle timing for gc path. Set to 5 seconds by default. What: /sys/fs/f2fs//iostat_enable Date: August 2017 Contact: "Chao Yu" -Description: - Controls to enable/disable IO stat. +Description: Controls to enable/disable IO stat. What: /sys/fs/f2fs//ra_nid_pages Date: October 2015 Contact: "Chao Yu" -Description: - Controls the count of nid pages to be readaheaded. +Description: Controls the count of nid pages to be readaheaded. + When building free nids, F2FS reads NAT blocks ahead for + speed up. Default is 0. What: /sys/fs/f2fs//dirty_nats_ratio Date: January 2016 Contact: "Chao Yu" -Description: - Controls dirty nat entries ratio threshold, if current - ratio exceeds configured threshold, checkpoint will - be triggered for flushing dirty nat entries. +Description: Controls dirty nat entries ratio threshold, if current + ratio exceeds configured threshold, checkpoint will + be triggered for flushing dirty nat entries. What: /sys/fs/f2fs//lifetime_write_kbytes Date: January 2016 Contact: "Shuoran Liu" -Description: - Shows total written kbytes issued to disk. +Description: Shows total written kbytes issued to disk. What: /sys/fs/f2fs//feature Date: July 2017 Contact: "Jaegeuk Kim" -Description: - Shows all enabled features in current device. +Description: Shows all enabled features in current device. What: /sys/fs/f2fs//inject_rate Date: May 2016 Contact: "Sheng Yong" -Description: - Controls the injection rate. +Description: Controls the injection rate of arbitrary faults. What: /sys/fs/f2fs//inject_type Date: May 2016 Contact: "Sheng Yong" -Description: - Controls the injection type. +Description: Controls the injection type of arbitrary faults. + +What: /sys/fs/f2fs//dirty_segments +Date: October 2017 +Contact: "Jaegeuk Kim" +Description: Shows the number of dirty segments. What: /sys/fs/f2fs//reserved_blocks Date: June 2017 Contact: "Chao Yu" -Description: - Controls target reserved blocks in system, the threshold - is soft, it could exceed current available user space. +Description: Controls target reserved blocks in system, the threshold + is soft, it could exceed current available user space. What: /sys/fs/f2fs//current_reserved_blocks Date: October 2017 Contact: "Yunlong Song" Contact: "Chao Yu" -Description: - Shows current reserved blocks in system, it may be temporarily - smaller than target_reserved_blocks, but will gradually - increase to target_reserved_blocks when more free blocks are - freed by user later. +Description: Shows current reserved blocks in system, it may be temporarily + smaller than target_reserved_blocks, but will gradually + increase to target_reserved_blocks when more free blocks are + freed by user later. What: /sys/fs/f2fs//gc_urgent Date: August 2017 Contact: "Jaegeuk Kim" -Description: - Do background GC agressively +Description: Do background GC agressively when set. When gc_urgent = 1, + background thread starts to do GC by given gc_urgent_sleep_time + interval. It is set to 0 by default. What: /sys/fs/f2fs//gc_urgent_sleep_time Date: August 2017 Contact: "Jaegeuk Kim" -Description: - Controls sleep time of GC urgent mode +Description: Controls sleep time of GC urgent mode. Set to 500ms by default. What: /sys/fs/f2fs//readdir_ra Date: November 2017 Contact: "Sheng Yong" -Description: - Controls readahead inode block in readdir. +Description: Controls readahead inode block in readdir. Enabled by default. + +What: /sys/fs/f2fs//gc_pin_file_thresh +Date: January 2018 +Contact: Jaegeuk Kim +Description: This indicates how many GC can be failed for the pinned + file. If it exceeds this, F2FS doesn't guarantee its pinning + state. 2048 trials is set by default. What: /sys/fs/f2fs//extension_list Date: Feburary 2018 Contact: "Chao Yu" -Description: - Used to control configure extension list: - - Query: cat /sys/fs/f2fs//extension_list - - Add: echo '[h/c]extension' > /sys/fs/f2fs//extension_list - - Del: echo '[h/c]!extension' > /sys/fs/f2fs//extension_list - - [h] means add/del hot file extension - - [c] means add/del cold file extension +Description: Used to control configure extension list: + - Query: cat /sys/fs/f2fs//extension_list + - Add: echo '[h/c]extension' > /sys/fs/f2fs//extension_list + - Del: echo '[h/c]!extension' > /sys/fs/f2fs//extension_list + - [h] means add/del hot file extension + - [c] means add/del cold file extension What: /sys/fs/f2fs//unusable Date April 2019 Contact: "Daniel Rosenberg" -Description: - If checkpoint=disable, it displays the number of blocks that are unusable. - If checkpoint=enable it displays the enumber of blocks that would be unusable - if checkpoint=disable were to be set. +Description: If checkpoint=disable, it displays the number of blocks that + are unusable. + If checkpoint=enable it displays the enumber of blocks that + would be unusable if checkpoint=disable were to be set. What: /sys/fs/f2fs//encoding Date July 2019 Contact: "Daniel Rosenberg" -Description: - Displays name and version of the encoding set for the filesystem. - If no encoding is set, displays (none) +Description: Displays name and version of the encoding set for the filesystem. + If no encoding is set, displays (none) + +What: /sys/fs/f2fs//free_segments +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of free segments in disk. + +What: /sys/fs/f2fs//cp_foreground_calls +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of checkpoint operations performed on demand. Available when + CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//cp_background_calls +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of checkpoint operations performed in the background to + free segments. Available when CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//gc_foreground_calls +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of garbage collection operations performed on demand. + Available when CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//gc_background_calls +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of garbage collection operations triggered in background. + Available when CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//moved_blocks_foreground +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of blocks moved by garbage collection in foreground. + Available when CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//moved_blocks_background +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Number of blocks moved by garbage collection in background. + Available when CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//avg_vblocks +Date: September 2019 +Contact: "Hridya Valsaraju" +Description: Average number of valid blocks. + Available when CONFIG_F2FS_STAT_FS=y. + +What: /sys/fs/f2fs//mounted_time_sec +Date: February 2020 +Contact: "Jaegeuk Kim" +Description: Show the mounted time in secs of this partition. + +What: /sys/fs/f2fs//data_io_flag +Date: April 2020 +Contact: "Jaegeuk Kim" +Description: Give a way to attach REQ_META|FUA to data writes + given temperature-based bits. Now the bits indicate: + * REQ_META | REQ_FUA | + * 5 | 4 | 3 | 2 | 1 | 0 | + * Cold | Warm | Hot | Cold | Warm | Hot | + +What: /sys/fs/f2fs//iostat_period_ms +Date: April 2020 +Contact: "Daeho Jeong" +Description: Give a way to change iostat_period time. 3secs by default. + The new iostat trace gives stats gap given the period. diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 12278a926370a136e978feb31c94fa8763e9cdea..36b7e740558fee02797995e03c900cc5601f31f0 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -54,6 +54,9 @@ If you make a mistake with the syntax, the write will fail thus:: /dynamic_debug/control -bash: echo: write error: Invalid argument +Note, for systems without 'debugfs' enabled, the control file can be +found in ``/proc/dynamic_debug/control``. + Viewing Dynamic Debug Behaviour =============================== diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 3b32e5fe1447e6cbc57a297dccf70c05e6e6439b..d545de46d7def45239ec5ea4d514b5c296a9fb4f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -137,6 +137,10 @@ dynamic table installation which will install SSDT tables to /sys/firmware/acpi/tables/dynamic. + acpi_no_watchdog [HW,ACPI,WDT] + Ignore the ACPI-based watchdog interface (WDAT) and let + a native driver control the watchdog device instead. + acpi_rsdp= [ACPI,EFI,KEXEC] Pass the RSDP address to the kernel, mostly used on machines running EFI runtime service to boot the diff --git a/Documentation/arm64/tagged-address-abi.rst b/Documentation/arm64/tagged-address-abi.rst index d4a85d535bf99e09cfe5c3dc41652eaa3b64f21b..4a9d9c794ee5d889638d1a3af008dec06d11feaf 100644 --- a/Documentation/arm64/tagged-address-abi.rst +++ b/Documentation/arm64/tagged-address-abi.rst @@ -44,8 +44,15 @@ The AArch64 Tagged Address ABI has two stages of relaxation depending how the user addresses are used by the kernel: 1. User addresses not accessed by the kernel but used for address space - management (e.g. ``mmap()``, ``mprotect()``, ``madvise()``). The use - of valid tagged pointers in this context is always allowed. + management (e.g. ``mprotect()``, ``madvise()``). The use of valid + tagged pointers in this context is allowed with the exception of + ``brk()``, ``mmap()`` and the ``new_address`` argument to + ``mremap()`` as these have the potential to alias with existing + user addresses. + + NOTE: This behaviour changed in v5.6 and so some earlier kernels may + incorrectly accept valid tagged pointers for the ``brk()``, + ``mmap()`` and ``mremap()`` system calls. 2. User addresses accessed by the kernel (e.g. ``write()``). This ABI relaxation is disabled by default and the application thread needs to diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX index f8614b3d49f985ca4e7bf2c9b77de9f87e29b2f8..1c63f2cba97eb256fe714922ccf1f5171b6a96e0 100644 --- a/Documentation/block/00-INDEX +++ b/Documentation/block/00-INDEX @@ -16,6 +16,8 @@ data-integrity.txt - Block data integrity deadline-iosched.txt - Deadline IO scheduler tunables +inline-encryption.rst + - Blk-crypto internals and inline encryption ioprio.txt - Block io priorities (in CFQ scheduler) pr.txt diff --git a/Documentation/block/index.rst b/Documentation/block/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..026addfc69bc9743182cc6a594cf6952c9aa6f02 --- /dev/null +++ b/Documentation/block/index.rst @@ -0,0 +1,26 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===== +Block +===== + +.. toctree:: + :maxdepth: 1 + + bfq-iosched + biodoc + biovecs + capability + cmdline-partition + data-integrity + deadline-iosched + inline-encryption + ioprio + kyber-iosched + null_blk + pr + queue-sysfs + request + stat + switching-sched + writeback_cache_control diff --git a/Documentation/block/inline-encryption.rst b/Documentation/block/inline-encryption.rst new file mode 100644 index 0000000000000000000000000000000000000000..330106b23c09339f8dd9404fd36dc0d6ae0c2890 --- /dev/null +++ b/Documentation/block/inline-encryption.rst @@ -0,0 +1,183 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================= +Inline Encryption +================= + +Objective +========= + +We want to support inline encryption (IE) in the kernel. +To allow for testing, we also want a crypto API fallback when actual +IE hardware is absent. We also want IE to work with layered devices +like dm and loopback (i.e. we want to be able to use the IE hardware +of the underlying devices if present, or else fall back to crypto API +en/decryption). + + +Constraints and notes +===================== + +- IE hardware have a limited number of "keyslots" that can be programmed + with an encryption context (key, algorithm, data unit size, etc.) at any time. + One can specify a keyslot in a data request made to the device, and the + device will en/decrypt the data using the encryption context programmed into + that specified keyslot. When possible, we want to make multiple requests with + the same encryption context share the same keyslot. + +- We need a way for filesystems to specify an encryption context to use for + en/decrypting a struct bio, and a device driver (like UFS) needs to be able + to use that encryption context when it processes the bio. + +- We need a way for device drivers to expose their capabilities in a unified + way to the upper layers. + + +Design +====== + +We add a struct bio_crypt_ctx to struct bio that can represent an +encryption context, because we need to be able to pass this encryption +context from the FS layer to the device driver to act upon. + +While IE hardware works on the notion of keyslots, the FS layer has no +knowledge of keyslots - it simply wants to specify an encryption context to +use while en/decrypting a bio. + +We introduce a keyslot manager (KSM) that handles the translation from +encryption contexts specified by the FS to keyslots on the IE hardware. +This KSM also serves as the way IE hardware can expose their capabilities to +upper layers. The generic mode of operation is: each device driver that wants +to support IE will construct a KSM and set it up in its struct request_queue. +Upper layers that want to use IE on this device can then use this KSM in +the device's struct request_queue to translate an encryption context into +a keyslot. The presence of the KSM in the request queue shall be used to mean +that the device supports IE. + +On the device driver end of the interface, the device driver needs to tell the +KSM how to actually manipulate the IE hardware in the device to do things like +programming the crypto key into the IE hardware into a particular keyslot. All +this is achieved through the :c:type:`struct keyslot_mgmt_ll_ops` that the +device driver passes to the KSM when creating it. + +It uses refcounts to track which keyslots are idle (either they have no +encryption context programmed, or there are no in-flight struct bios +referencing that keyslot). When a new encryption context needs a keyslot, it +tries to find a keyslot that has already been programmed with the same +encryption context, and if there is no such keyslot, it evicts the least +recently used idle keyslot and programs the new encryption context into that +one. If no idle keyslots are available, then the caller will sleep until there +is at least one. + + +Blk-crypto +========== + +The above is sufficient for simple cases, but does not work if there is a +need for a crypto API fallback, or if we are want to use IE with layered +devices. To these ends, we introduce blk-crypto. Blk-crypto allows us to +present a unified view of encryption to the FS (so FS only needs to specify +an encryption context and not worry about keyslots at all), and blk-crypto +can decide whether to delegate the en/decryption to IE hardware or to the +crypto API. Blk-crypto maintains an internal KSM that serves as the crypto +API fallback. + +Blk-crypto needs to ensure that the encryption context is programmed into the +"correct" keyslot manager for IE. If a bio is submitted to a layered device +that eventually passes the bio down to a device that really does support IE, we +want the encryption context to be programmed into a keyslot for the KSM of the +device with IE support. However, blk-crypto does not know a priori whether a +particular device is the final device in the layering structure for a bio or +not. So in the case that a particular device does not support IE, since it is +possibly the final destination device for the bio, if the bio requires +encryption (i.e. the bio is doing a write operation), blk-crypto must fallback +to the crypto API *before* sending the bio to the device. + +Blk-crypto ensures that: + +- The bio's encryption context is programmed into a keyslot in the KSM of the + request queue that the bio is being submitted to (or the crypto API fallback + KSM if the request queue doesn't have a KSM), and that the ``bc_ksm`` + in the ``bi_crypt_context`` is set to this KSM + +- That the bio has its own individual reference to the keyslot in this KSM. + Once the bio passes through blk-crypto, its encryption context is programmed + in some KSM. The "its own individual reference to the keyslot" ensures that + keyslots can be released by each bio independently of other bios while + ensuring that the bio has a valid reference to the keyslot when, for e.g., the + crypto API fallback KSM in blk-crypto performs crypto on the device's behalf. + The individual references are ensured by increasing the refcount for the + keyslot in the ``bc_ksm`` when a bio with a programmed encryption + context is cloned. + + +What blk-crypto does on bio submission +-------------------------------------- + +**Case 1:** blk-crypto is given a bio with only an encryption context that hasn't +been programmed into any keyslot in any KSM (for e.g. a bio from the FS). + In this case, blk-crypto will program the encryption context into the KSM of the + request queue the bio is being submitted to (and if this KSM does not exist, + then it will program it into blk-crypto's internal KSM for crypto API + fallback). The KSM that this encryption context was programmed into is stored + as the ``bc_ksm`` in the bio's ``bi_crypt_context``. + +**Case 2:** blk-crypto is given a bio whose encryption context has already been +programmed into a keyslot in the *crypto API fallback* KSM. + In this case, blk-crypto does nothing; it treats the bio as not having + specified an encryption context. Note that we cannot do here what we will do + in Case 3 because we would have already encrypted the bio via the crypto API + by this point. + +**Case 3:** blk-crypto is given a bio whose encryption context has already been +programmed into a keyslot in some KSM (that is *not* the crypto API fallback +KSM). + In this case, blk-crypto first releases that keyslot from that KSM and then + treats the bio as in Case 1. + +This way, when a device driver is processing a bio, it can be sure that +the bio's encryption context has been programmed into some KSM (either the +device driver's request queue's KSM, or blk-crypto's crypto API fallback KSM). +It then simply needs to check if the bio's ``bc_ksm`` is the device's +request queue's KSM. If so, then it should proceed with IE. If not, it should +simply do nothing with respect to crypto, because some other KSM (perhaps the +blk-crypto crypto API fallback KSM) is handling the en/decryption. + +Blk-crypto will release the keyslot that is being held by the bio (and also +decrypt it if the bio is using the crypto API fallback KSM) once +``bio_remaining_done`` returns true for the bio. + + +Layered Devices +=============== + +Layered devices that wish to support IE need to create their own keyslot +manager for their request queue, and expose whatever functionality they choose. +When a layered device wants to pass a bio to another layer (either by +resubmitting the same bio, or by submitting a clone), it doesn't need to do +anything special because the bio (or the clone) will once again pass through +blk-crypto, which will work as described in Case 3. If a layered device wants +for some reason to do the IO by itself instead of passing it on to a child +device, but it also chose to expose IE capabilities by setting up a KSM in its +request queue, it is then responsible for en/decrypting the data itself. In +such cases, the device can choose to call the blk-crypto function +``blk_crypto_fallback_to_kernel_crypto_api`` (TODO: Not yet implemented), which will +cause the en/decryption to be done via the crypto API fallback. + + +Future Optimizations for layered devices +======================================== + +Creating a keyslot manager for the layered device uses up memory for each +keyslot, and in general, a layered device (like dm-linear) merely passes the +request on to a "child" device, so the keyslots in the layered device itself +might be completely unused. We can instead define a new type of KSM; the +"passthrough KSM", that layered devices can use to let blk-crypto know that +this layered device *will* pass the bio to some child device (and hence +through blk-crypto again, at which point blk-crypto can program the encryption +context, instead of programming it into the layered device's KSM). Again, if +the device "lies" and decides to do the IO itself instead of passing it on to +a child device, it is responsible for doing the en/decryption (and can choose +to call ``blk_crypto_fallback_to_kernel_crypto_api``). Another use case for the +"passthrough KSM" is for IE devices that want to manage their own keyslots/do +not have a limited number of keyslots. diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 5b614f215d2226fb3a6a865d2ef1f0cd648d4bc6..2888320983100a10b9278406b1d72225d2f54306 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -106,12 +106,6 @@ SoCs: - SDA429W compatible = "qcom,sda429w" -- QCM6125 - compatible = "qcom,qcm6125" - -- QCS6125 - compatible = "qcom,qcs6125" - - SA2145P compatible = "qcom,sa2145p" @@ -168,6 +162,11 @@ Generic board variants: - TTP device: compatible = "qcom,ttp" +- TRINKET-IOT + compatible = "qcom,trinket-iot" + +- TRINKETP-IOT + compatible = "qcom,trinketp-iot" Boards (SoC type + board variant): @@ -255,7 +254,6 @@ compatible = "qcom,sa8155p-adp-alcor" compatible = "qcom,sdxprairie-rumi" compatible = "qcom,sdxprairie-mtp" compatible = "qcom,sdxprairie-cdp" -compatible = "qcom,sdxprairie-ttp" compatible = "qcom,sa515m-ccard" compatible = "qcom,sa515m-ttp" compatible = "qcom,sdmmagpie-rumi" @@ -312,7 +310,7 @@ compatible = "qcom,sda429w-wdp" compatible = "qcom,sda429-wdp" compatible = "qcom,sdm429w-wdp" compatible = "qcom,sdm429-wdp" -compatible = "qcom,qcm6125" -compatible = "qcom,qcs6125" -compatible = "qcom,qcm6125-idp" -compatible = "qcom,qcs6125-idp" +compatible = "qcom,trinket-iot" +compatible = "qcom,trinketp-iot" +compatible = "qcom,trinket-iot-idp" +compatible = "qcom,trinketp-iot-idp" diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 2182ade92b46fbea8f3d4f8d1cb2e885dbb5a48f..0752f51238e1b99d3644233303162bde486cf480 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -510,6 +510,7 @@ the fps window. in floating state(not LP00 or LP11) to turn on this property. Software turns off PHY pmic power supply, phy ldo and DSI Lane ldo during idle screen (footswitch control off) when this property is enabled. +- qcom,skip-panel-reset: Boolean. when set, will skip panel reset during panel ON/OFF. [[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel. Default configuration can be chosen by specifying phandle of the selected subnode in the qcom,config-select. diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt index df29ef5d26a161c515a2563fa70745830d4d5715..9ddca43a93d9eef2b08cb438f2301cd29422d7e4 100644 --- a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt +++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt @@ -38,6 +38,8 @@ Optional properties: be aligned - qcom,unmap_fast : A boolean specifying if iommu unmap fast is supported on this target. +- qcom,secure-size : Specifies the size of gpu address region to be used for + secure memory mapping. - List of sub nodes, one for each of the translation context banks supported. The driver uses the names of these nodes to determine how they are used, diff --git a/Documentation/devicetree/bindings/iio/adc/qcom-rradc.txt b/Documentation/devicetree/bindings/iio/adc/qcom-rradc.txt index 1ab49edfe30ce59f92652fd04e7b45079b224135..240c6d82deb010179ebfb3d70835bda0bb13ecc1 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom-rradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/qcom-rradc.txt @@ -45,6 +45,10 @@ Optional property: - qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the PMIC fabrication ID for applying the appropriate temperature compensation parameters. +- qcom,batt-id-delay-ms : + Value type: + Definition: Used to specify HW settling time in MS for measuring BATT_ID. + Possible values are: 0, 1, 4, 12, 20, 40, 60, 80. Example: /* RRADC node */ diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt index a0447c6d6469f5dc4efb658b2ae699310b9352a5..81752a44865cec73979b7df411e9d29c7c639cc0 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -90,6 +90,14 @@ platforms. The PMIC is connected to the host processor via SPMI bus. 29600, 19600, 18100. Default: 29600 mV +- qcom,sync-dly + Usage: optional + Value type: + Definition: Delay for current sync in us. Values are + 0, 200, 400, 600, 800, 1000, 1200, 1400. + Default: 400 us. + This property is only applicable for WLED4. + - qcom,string-cfg Usage: optional Value type: diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt index 4b1f086128657961f600ad9a53ee6a29a1484f8e..b22615bdafef23f8c4fb5f6eb948ac4ffbc683bf 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt @@ -67,6 +67,11 @@ Second Level Node - CAM SMMU context bank device or firmware device Value type: boolean Definition: Specifies if the context bank is a secure context bank. +- qcom,secure-pixel-cb + Usage: optional + Value type: boolean + Definition: Specifies if the context bank is a secure pixel context bank. + ============================================= Third Level Node - CAM SMMU memory map device ============================================= diff --git a/Documentation/devicetree/bindings/net/fsl-fman.txt b/Documentation/devicetree/bindings/net/fsl-fman.txt index df873d1f3b7c598b6c30721d3eec915a20ea8621..2aaae210317bbbe73b83b2413a371856a6da308c 100644 --- a/Documentation/devicetree/bindings/net/fsl-fman.txt +++ b/Documentation/devicetree/bindings/net/fsl-fman.txt @@ -110,6 +110,13 @@ PROPERTIES Usage: required Definition: See soc/fsl/qman.txt and soc/fsl/bman.txt +- fsl,erratum-a050385 + Usage: optional + Value type: boolean + Definition: A boolean property. Indicates the presence of the + erratum A050385 which indicates that DMA transactions that are + split can result in a FMan lock. + ============================================================================= FMan MURAM Node diff --git a/Documentation/devicetree/bindings/net/qcom,sja1105p-eth-switch.txt b/Documentation/devicetree/bindings/net/qcom,sja1105p-eth-switch.txt new file mode 100644 index 0000000000000000000000000000000000000000..701ba523fd59cadf889b38bc21aec0262f2c71f4 --- /dev/null +++ b/Documentation/devicetree/bindings/net/qcom,sja1105p-eth-switch.txt @@ -0,0 +1,64 @@ +* NXP SJA1105P 10/100/1000 Ethernet Switch Driver + +Required properties: +### Properties of top level +- compatible: Should be "qcom,nxp,sja1105p-switch". +- reg: Should contain SPI chip select. +- spi-max-frequency: Should contain maximum spi clock frequency + for slave device. +- spi-cpha: SPI configuration to enable shift clock phase (CPHA) mode. +- switch-speed: Should contain switch ports speed 10/100/1000 Mbps. +- pinctrl-names : Names corresponding to the numbered pinctrl states +- pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt +- qcom,reset-gpio: Reference to the GPIO connected to the reset input. + +### Properties of the port-X child node +- `null-phy`: Determines if the port has a PHY connected to it or not +- `phy-ref`: _phandle_ to the connected ethernet PHY + **NOTE**: Must be `0x00` in case there is no PHY connected to port-X + (for example if port-X is a host port or a cascaded port) +- `logical-port-num`: logical port number, used for the port mapping + **NOTE**: Must be `0xff` in case port-X is a cascaded port. + +Example: + + sja1105: ethernet-switch@0{ + compatible = "qcom,nxp,sja1105p-switch"; + reg = <0>; + spi-max-frequency = <12000000>; + spi-cpha; + switch-speed = <1000>; + pinctrl-names = "default"; + pinctrl-0 = <&sja1105_default>; + qcom,reset-gpio = <&tlmm 91 0x1>; + + port-0 { + null-phy = <0x1>; + phy-ref = < 0 >; + logical-port-num = < 0 >; + }; + + port-1 { + null-phy = <0x1>; + phy-ref = < 0 >; + logical-port-num = < 1 >; + }; + + port-2 { + null-phy = <0x1>; + phy-ref = < 0 >; + logical-port-num = < 2 >; + }; + + port-3 { + null-phy = <0x1>; + phy-ref = < 0 >; + logical-port-num = < 3 >; + }; + + port-4 { + null-phy = <0x1>; + phy-ref = < 0 >; + logical-port-num = < 4 >; + }; + }; diff --git a/Documentation/devicetree/bindings/net/qcom,stmmac-ethqos.txt b/Documentation/devicetree/bindings/net/qcom,stmmac-ethqos.txt index f910fb5093964b382a94b64138b7adb89cff4173..7011dff0b7d9fd01eb51df18be353a42abca75a2 100644 --- a/Documentation/devicetree/bindings/net/qcom,stmmac-ethqos.txt +++ b/Documentation/devicetree/bindings/net/qcom,stmmac-ethqos.txt @@ -114,6 +114,8 @@ Optional properties: - snps,high_credit: max write outstanding req. limit - snps,low_credit: max read outstanding req. limit - snps,priority: TX queue priority (Range: 0x0 to 0xF) +- rx-prog-swap: boolean value to enable RX_PROG_SWAP for 10/100M +- rx-dll-bypass: boolean value to indicate RX DLL in bypass mode. Examples: stmmac_axi_setup: stmmac-axi-config { diff --git a/Documentation/devicetree/bindings/net/qrtr-ethernet-dev.txt b/Documentation/devicetree/bindings/net/qrtr-ethernet-dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..94b9f9fd3374ef49c20a56f22c3b6d1e481ca156 --- /dev/null +++ b/Documentation/devicetree/bindings/net/qrtr-ethernet-dev.txt @@ -0,0 +1,30 @@ +QTI QRTR Ethernet Device transport binding + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,qrtr-ethernet-dev" + +- qcom,net-id: + Usage: optional + Value type: + Definition: indicates what subnet this transport belongs to. Should be + passed into the qrtr core logic to determine if forwarding + is needed on this endpoint. + +- qcom,low-latency: + Usage: optional + Value type: + Definition: indicates whether this transport receiving thread needs to + be set to realtime priority for enhanced performance. + += EXAMPLE +The following example represents the qrtr ethernet dev transport node on a +device configured as an ethernet endpoint and needs to forward data from the +host to a modem co-processor. + + qcom,eth_dev_qrtr { + compatible = "qcom,qrtr-ethernet-dev"; + qcom,net-id = <4>; + qcom,low-latency; + }; diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 9c12fb871cfe5acbe8fef20b836b4f6c21bfc2bf..f4f462f6ab7f543d03fafa17e11fc965ca6d8cdf 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -80,6 +80,9 @@ Optional properties: identifier. If this is specified, then a QMP message should be sent to enable the GDSC instead of setting SW_COLLAPSE=0. + - qcom,skip-disable-before-sw-enable: Presence denotes a hardware requirement + to leave the GDSC on that has been + enabled by an entity external to HLOS. [1]: Documentation/devicetree/bindings/arm/msm/msm_bus.txt diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e4c0ef147ed9361ed837d73d0a7378f96204403 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_rsb.txt @@ -0,0 +1,19 @@ +Qualcomm technologies, Inc. bg-rsb + +BG-RSB : bg-rsb is used to communicate with Blackghost over +Glink to configure the RSB events. bg-rsb enable/disable +LDO11 and LDO15 before making any communication to BG +regarding RSB. It also provides an input device, which is +used to send the RSB/Button events to input framework. + +Required properties: +- compatible : should be "qcom,bg-rsb" +- vdd-ldo1-supply : for powering main supply +- vdd-ldo2-supply : for powering sensor + +Example: + qcom,bg-rsb { + compatible = "qcom,bg-rsb"; + vdd-ldo1-supply = <&pm660_l11>; + vdd-ldo2-supply = <&pm660_l15>; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/bgrsb_rpmsg.txt b/Documentation/devicetree/bindings/soc/qcom/bgrsb_rpmsg.txt new file mode 100644 index 0000000000000000000000000000000000000000..26dfa31d2ef83f6d114f7b08076767fa5a2bf412 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bgrsb_rpmsg.txt @@ -0,0 +1,20 @@ +Qualcomm technologies, Inc. bgrsb-rpmsg + +BGRSB-RPMSG : bgrsb-rpmsg is used as an interface between +BG-RSB and Blackghost for Glink communication. bg-rsb is +used to communicate with Blackghost over Glink to +configure the RSB events. + +Required properties: +- compatible : should be "qcom,bgrsb-rpmsg" +- glink-channels : RSB_CTRL +- glinkpkt-edge : bg +- intents : <0x200 20> + +Example: + qcom,bg-rsb { + compatible = "qcom,bgrsb-rpmsg"; + qcom,glink-channels = "RSB_CTRL"; + qcom,glinkpkt-edge = "bg"; + intents = <0x200 20>; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/blocknames.txt b/Documentation/devicetree/bindings/soc/qcom/blocknames.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0f4b39b8edaa1a49588b5a5704e14b7e8217907 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/blocknames.txt @@ -0,0 +1,18 @@ +* rename block devices + +Required properties: + +- compatible: "qcom,blkdev-rename" compatibility string +- actual-dev: Name of the disk assigned by generic driver +- rename-dev: Re-name of the disk to set for disks + +Example: + +rename_blk: rename_blk { + compatible = "qcom,blkdev-rename"; + actual-dev = "vda", "vdb", "vdc", + "vdd", "vde", "vdf", + "vdg", "vdh"; + rename-dev = "la_system", "la_userdata", "la_vendor", + "la_persist", "modem", "bluetooth", + "la_misc", "vbmeta"; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 41894da6bcf87af635269bcf0318f555b78a63e2..e57d0afaa474ecb27f7203feaa17111f8fb68c09 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1185,6 +1185,8 @@ Example: Required properties: - compatible : "qcom,sm8150-asoc-snd-stub" for SM8150 target. - compatible : "qcom,kona-asoc-snd-stub" for Kona target. +- compatible : "qcom,msm8952-audio-codec" for pmic codec, + "qcom,msm8952-dig-asoc-snd" for digital internal codec. - qcom,model : The user-visible name of this sound card. - qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec - asoc-platform: This is phandle list containing the references to platform device diff --git a/Documentation/devicetree/bindings/sound/tfa98xx.txt b/Documentation/devicetree/bindings/sound/tfa98xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..8cf30f42e71219935bbd3fab85ba49f01578ae15 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tfa98xx.txt @@ -0,0 +1,26 @@ +TFA9898 SmartpA + +Required properties: + + - compatible : "nxp,tfa98xx" + + - reg : I2C address of the device + + - reset-gpio : gpio used for HW reset + + - dvdd-supply : Power supply for PA's dvdd + + - dvdd-voltage : Minimum and maximum voltage in uV to set for power supply + + - dvdd-current : dvdd's max current in uA + +Examples: + + i2c_smartpa@34 { + compatible = "nxp,tfa98xx; + reg = <0x34>; + reset-gpio = <&tlmm 68 0>; + dvdd-supply = <&pm660_l9>; + dvdd-voltage = <1800000 1800000>; + dvdd-current = <15000>; + }; diff --git a/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt b/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt index 15d0f4a607b14dc2135219af07f25307fd5f22dc..0e136972f5f73d2eb2e5776e5c67fff564b1389b 100644 --- a/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt +++ b/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt @@ -52,6 +52,7 @@ Subsystem properties: "mmw_skin1" -> MMW skin mitigation device1, "mmw_skin2" -> MMW skin mitigation device2, "mmw_skin3" -> MMW skin mitigation device3, + "modem_v2x" -> modem CV2X mitigation device, "cpr_cold" -> for cpr restriction, "cdsp_sw" -> for CDSP DCVS mitigation device, "cdsp_hw" -> for CDSP hardware mitigation device. @@ -95,6 +96,11 @@ Example: qcom,qmi-dev-name = "cpr_cold"; #cooling-cells = <2>; }; + + modem_v2x: modem_v2x { + qcom,qmi-dev-name = "modem_v2x"; + #cooling-cells = <2>; + }; }; adsp { diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index dc2cecdaa7ddb4d8f6b45756a4bd0acc6b3f8b4f..1ca9556ec849d41f31b0e05c5de026b4e38921d3 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -235,6 +235,17 @@ checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "en hide up to all remaining free space. The actual space that would be unusable can be viewed at /sys/fs/f2fs//unusable This space is reclaimed once checkpoint=enable. +compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo", + "lz4" and "zstd" algorithm. +compress_log_size=%u Support configuring compress cluster size, the size will + be 4KB * (1 << %u), 16KB is minimum size, also it's + default size. +compress_extension=%s Support adding specified extension, so that f2fs can enable + compression on those corresponding files, e.g. if all files + with '.ext' has high compression rate, we can set the '.ext' + on compression extension list and enable compression on + these file by default rather than to enable it via ioctl. + For other files, we can still enable compression via ioctl. ================================================================================ DEBUGFS ENTRIES @@ -259,170 +270,6 @@ The files in each per-device directory are shown in table below. Files in /sys/fs/f2fs/ (see also Documentation/ABI/testing/sysfs-fs-f2fs) -.............................................................................. - File Content - - gc_urgent_sleep_time This parameter controls sleep time for gc_urgent. - 500 ms is set by default. See above gc_urgent. - - gc_min_sleep_time This tuning parameter controls the minimum sleep - time for the garbage collection thread. Time is - in milliseconds. - - gc_max_sleep_time This tuning parameter controls the maximum sleep - time for the garbage collection thread. Time is - in milliseconds. - - gc_no_gc_sleep_time This tuning parameter controls the default sleep - time for the garbage collection thread. Time is - in milliseconds. - - gc_idle This parameter controls the selection of victim - policy for garbage collection. Setting gc_idle = 0 - (default) will disable this option. Setting - gc_idle = 1 will select the Cost Benefit approach - & setting gc_idle = 2 will select the greedy approach. - - gc_urgent This parameter controls triggering background GCs - urgently or not. Setting gc_urgent = 0 [default] - makes back to default behavior, while if it is set - to 1, background thread starts to do GC by given - gc_urgent_sleep_time interval. - - reclaim_segments This parameter controls the number of prefree - segments to be reclaimed. If the number of prefree - segments is larger than the number of segments - in the proportion to the percentage over total - volume size, f2fs tries to conduct checkpoint to - reclaim the prefree segments to free segments. - By default, 5% over total # of segments. - - main_blkaddr This value gives the first block address of - MAIN area in the partition. - - max_small_discards This parameter controls the number of discard - commands that consist small blocks less than 2MB. - The candidates to be discarded are cached until - checkpoint is triggered, and issued during the - checkpoint. By default, it is disabled with 0. - - discard_granularity This parameter controls the granularity of discard - command size. It will issue discard commands iif - the size is larger than given granularity. Its - unit size is 4KB, and 4 (=16KB) is set by default. - The maximum value is 128 (=512KB). - - reserved_blocks This parameter indicates the number of blocks that - f2fs reserves internally for root. - - batched_trim_sections This parameter controls the number of sections - to be trimmed out in batch mode when FITRIM - conducts. 32 sections is set by default. - - ipu_policy This parameter controls the policy of in-place - updates in f2fs. There are five policies: - 0x01: F2FS_IPU_FORCE, 0x02: F2FS_IPU_SSR, - 0x04: F2FS_IPU_UTIL, 0x08: F2FS_IPU_SSR_UTIL, - 0x10: F2FS_IPU_FSYNC. - - min_ipu_util This parameter controls the threshold to trigger - in-place-updates. The number indicates percentage - of the filesystem utilization, and used by - F2FS_IPU_UTIL and F2FS_IPU_SSR_UTIL policies. - - min_fsync_blocks This parameter controls the threshold to trigger - in-place-updates when F2FS_IPU_FSYNC mode is set. - The number indicates the number of dirty pages - when fsync needs to flush on its call path. If - the number is less than this value, it triggers - in-place-updates. - - min_seq_blocks This parameter controls the threshold to serialize - write IOs issued by multiple threads in parallel. - - min_hot_blocks This parameter controls the threshold to allocate - a hot data log for pending data blocks to write. - - min_ssr_sections This parameter adds the threshold when deciding - SSR block allocation. If this is large, SSR mode - will be enabled early. - - ram_thresh This parameter controls the memory footprint used - by free nids and cached nat entries. By default, - 1 is set, which indicates 10 MB / 1 GB RAM. - - ra_nid_pages When building free nids, F2FS reads NAT blocks - ahead for speed up. Default is 0. - - dirty_nats_ratio Given dirty ratio of cached nat entries, F2FS - determines flushing them in background. - - max_victim_search This parameter controls the number of trials to - find a victim segment when conducting SSR and - cleaning operations. The default value is 4096 - which covers 8GB block address range. - - migration_granularity For large-sized sections, F2FS can stop GC given - this granularity instead of reclaiming entire - section. - - dir_level This parameter controls the directory level to - support large directory. If a directory has a - number of files, it can reduce the file lookup - latency by increasing this dir_level value. - Otherwise, it needs to decrease this value to - reduce the space overhead. The default value is 0. - - cp_interval F2FS tries to do checkpoint periodically, 60 secs - by default. - - idle_interval F2FS detects system is idle, if there's no F2FS - operations during given interval, 5 secs by - default. - - discard_idle_interval F2FS detects the discard thread is idle, given - time interval. Default is 5 secs. - - gc_idle_interval F2FS detects the GC thread is idle, given time - interval. Default is 5 secs. - - umount_discard_timeout When unmounting the disk, F2FS waits for finishing - queued discard commands which can take huge time. - This gives time out for it, 5 secs by default. - - iostat_enable This controls to enable/disable iostat in F2FS. - - readdir_ra This enables/disabled readahead of inode blocks - in readdir, and default is enabled. - - gc_pin_file_thresh This indicates how many GC can be failed for the - pinned file. If it exceeds this, F2FS doesn't - guarantee its pinning state. 2048 trials is set - by default. - - extension_list This enables to change extension_list for hot/cold - files in runtime. - - inject_rate This controls injection rate of arbitrary faults. - - inject_type This controls injection type of arbitrary faults. - - dirty_segments This shows # of dirty segments. - - lifetime_write_kbytes This shows # of data written to the disk. - - features This shows current features enabled on F2FS. - - current_reserved_blocks This shows # of blocks currently reserved. - - unusable If checkpoint=disable, this shows the number of - blocks that are unusable. - If checkpoint=enable it shows the number of blocks - that would be unusable if checkpoint=disable were - to be set. - -encoding This shows the encoding used for casefolding. - If casefolding is not enabled, returns (none) ================================================================================ USAGE @@ -780,3 +627,44 @@ zero or random data, which is useful to the below scenario where: 4. address = fibmap(fd, offset) 5. open(blkdev) 6. write(blkdev, address) + +Compression implementation +-------------------------- + +- New term named cluster is defined as basic unit of compression, file can +be divided into multiple clusters logically. One cluster includes 4 << n +(n >= 0) logical pages, compression size is also cluster size, each of +cluster can be compressed or not. + +- In cluster metadata layout, one special block address is used to indicate +cluster is compressed one or normal one, for compressed cluster, following +metadata maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs +stores data including compress header and compressed data. + +- In order to eliminate write amplification during overwrite, F2FS only +support compression on write-once file, data can be compressed only when +all logical blocks in file are valid and cluster compress ratio is lower +than specified threshold. + +- To enable compression on regular inode, there are three ways: +* chattr +c file +* chattr +c dir; touch dir/file +* mount w/ -o compress_extension=ext; touch file.ext + +Compress metadata layout: + [Dnode Structure] + +-----------------------------------------------+ + | cluster 1 | cluster 2 | ......... | cluster N | + +-----------------------------------------------+ + . . . . + . . . . + . Compressed Cluster . . Normal Cluster . ++----------+---------+---------+---------+ +---------+---------+---------+---------+ +|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 | ++----------+---------+---------+---------+ +---------+---------+---------+---------+ + . . + . . + . . + +-------------+-------------+----------+----------------------------+ + | data length | data chksum | reserved | compressed data | + +-------------+-------------+----------+----------------------------+ diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 471a511c75088d7e5b3528f055d420a3d59e22d5..7f9a372031fd05a9a127877d08ac41c9fc1645d7 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -234,8 +234,8 @@ HKDF is more flexible, is nonreversible, and evenly distributes entropy from the master key. HKDF is also standardized and widely used by other software, whereas the AES-128-ECB based KDF is ad-hoc. -Per-file keys -------------- +Per-file encryption keys +------------------------ Since each master key can protect many files, it is necessary to "tweak" the encryption of each file so that the same plaintext in two @@ -268,9 +268,9 @@ is greater than that of an AES-256-XTS key. Therefore, to improve performance and save memory, for Adiantum a "direct key" configuration is supported. When the user has enabled this by setting FSCRYPT_POLICY_FLAG_DIRECT_KEY in the fscrypt policy, -per-file keys are not used. Instead, whenever any data (contents or -filenames) is encrypted, the file's 16-byte nonce is included in the -IV. Moreover: +per-file encryption keys are not used. Instead, whenever any data +(contents or filenames) is encrypted, the file's 16-byte nonce is +included in the IV. Moreover: - For v1 encryption policies, the encryption is done directly with the master key. Because of this, users **must not** use the same master @@ -292,8 +292,22 @@ files' data differently, inode numbers are included in the IVs. Consequently, shrinking the filesystem may not be allowed. This format is optimized for use with inline encryption hardware -compliant with the UFS or eMMC standards, which support only 64 IV -bits per I/O request and may have only a small number of keyslots. +compliant with the UFS standard, which supports only 64 IV bits per +I/O request and may have only a small number of keyslots. + +IV_INO_LBLK_32 policies +----------------------- + +IV_INO_LBLK_32 policies work like IV_INO_LBLK_64, except that for +IV_INO_LBLK_32, the inode number is hashed with SipHash-2-4 (where the +SipHash key is derived from the master key) and added to the file +logical block number mod 2^32 to produce a 32-bit IV. + +This format is optimized for use with inline encryption hardware +compliant with the eMMC v5.2 standard, which supports only 32 IV bits +per I/O request and may have only a small number of keyslots. This +format results in some level of IV reuse, so it should only be used +when necessary due to hardware limitations. Key identifiers --------------- @@ -302,6 +316,16 @@ For master keys used for v2 encryption policies, a unique 16-byte "key identifier" is also derived using the KDF. This value is stored in the clear, since it is needed to reliably identify the key itself. +Dirhash keys +------------ + +For directories that are indexed using a secret-keyed dirhash over the +plaintext filenames, the KDF is also used to derive a 128-bit +SipHash-2-4 key per directory in order to hash filenames. This works +just like deriving a per-file encryption key, except that a different +KDF context is used. Currently, only casefolded ("case-insensitive") +encrypted directories use this style of hashing. + Encryption modes and usage ========================== @@ -325,11 +349,11 @@ used. Adiantum is a (primarily) stream cipher-based mode that is fast even on CPUs without dedicated crypto instructions. It's also a true wide-block mode, unlike XTS. It can also eliminate the need to derive -per-file keys. However, it depends on the security of two primitives, -XChaCha12 and AES-256, rather than just one. See the paper -"Adiantum: length-preserving encryption for entry-level processors" -(https://eprint.iacr.org/2018/720.pdf) for more details. To use -Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast +per-file encryption keys. However, it depends on the security of two +primitives, XChaCha12 and AES-256, rather than just one. See the +paper "Adiantum: length-preserving encryption for entry-level +processors" (https://eprint.iacr.org/2018/720.pdf) for more details. +To use Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast implementations of ChaCha and NHPoly1305 should be enabled, e.g. CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM. @@ -359,6 +383,10 @@ a little endian number, except that: to 32 bits and is placed in bits 0-31 of the IV. The inode number (which is also limited to 32 bits) is placed in bits 32-63. +- With `IV_INO_LBLK_32 policies`_, the logical block number is limited + to 32 bits and is placed in bits 0-31 of the IV. The inode number + is then hashed and added mod 2^32. + Note that because file logical block numbers are included in the IVs, filesystems must enforce that blocks are never shifted around within encrypted files, e.g. via "collapse range" or "insert range". @@ -455,8 +483,15 @@ This structure must be initialized as follows: (0x3). - FSCRYPT_POLICY_FLAG_DIRECT_KEY: See `DIRECT_KEY policies`_. - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: See `IV_INO_LBLK_64 - policies`_. This is mutually exclusive with DIRECT_KEY and is not - supported on v1 policies. + policies`_. + - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32: See `IV_INO_LBLK_32 + policies`_. + + v1 encryption policies only support the PAD_* and DIRECT_KEY flags. + The other flags are only supported by v2 encryption policies. + + The DIRECT_KEY, IV_INO_LBLK_64, and IV_INO_LBLK_32 flags are + mutually exclusive. - For v2 encryption policies, ``__reserved`` must be zeroed. @@ -513,7 +548,9 @@ FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors: - ``EEXIST``: the file is already encrypted with an encryption policy different from the one specified - ``EINVAL``: an invalid encryption policy was specified (invalid - version, mode(s), or flags; or reserved bits were set) + version, mode(s), or flags; or reserved bits were set); or a v1 + encryption policy was specified but the directory has the casefold + flag enabled (casefolding is incompatible with v1 policies). - ``ENOKEY``: a v2 encryption policy was specified, but the key with the specified ``master_key_identifier`` has not been added, nor does the process have the CAP_FOWNER capability in the initial user @@ -621,6 +658,17 @@ from a passphrase or other low-entropy user credential. FS_IOC_GET_ENCRYPTION_PWSALT is deprecated. Instead, prefer to generate and manage any needed salt(s) in userspace. +Getting a file's encryption nonce +--------------------------------- + +Since Linux v5.7, the ioctl FS_IOC_GET_ENCRYPTION_NONCE is supported. +On encrypted files and directories it gets the inode's 16-byte nonce. +On unencrypted files and directories, it fails with ENODATA. + +This ioctl can be useful for automated tests which verify that the +encryption is being done correctly. It is not needed for normal use +of fscrypt. + Adding keys ----------- @@ -638,7 +686,8 @@ follows:: struct fscrypt_add_key_arg { struct fscrypt_key_specifier key_spec; __u32 raw_size; - __u32 __reserved[9]; + __u32 key_id; + __u32 __reserved[8]; __u8 raw[]; }; @@ -655,6 +704,12 @@ follows:: } u; }; + struct fscrypt_provisioning_key_payload { + __u32 type; + __u32 __reserved; + __u8 raw[]; + }; + :c:type:`struct fscrypt_add_key_arg` must be zeroed, then initialized as follows: @@ -677,9 +732,26 @@ as follows: ``Documentation/security/keys/core.rst``). - ``raw_size`` must be the size of the ``raw`` key provided, in bytes. + Alternatively, if ``key_id`` is nonzero, this field must be 0, since + in that case the size is implied by the specified Linux keyring key. + +- ``key_id`` is 0 if the raw key is given directly in the ``raw`` + field. Otherwise ``key_id`` is the ID of a Linux keyring key of + type "fscrypt-provisioning" whose payload is a :c:type:`struct + fscrypt_provisioning_key_payload` whose ``raw`` field contains the + raw key and whose ``type`` field matches ``key_spec.type``. Since + ``raw`` is variable-length, the total size of this key's payload + must be ``sizeof(struct fscrypt_provisioning_key_payload)`` plus the + raw key size. The process must have Search permission on this key. + + Most users should leave this 0 and specify the raw key directly. + The support for specifying a Linux keyring key is intended mainly to + allow re-adding keys after a filesystem is unmounted and re-mounted, + without having to store the raw keys in userspace memory. - ``raw`` is a variable-length field which must contain the actual - key, ``raw_size`` bytes long. + key, ``raw_size`` bytes long. Alternatively, if ``key_id`` is + nonzero, then this field is unused. For v2 policy keys, the kernel keeps track of which user (identified by effective user ID) added the key, and only allows the key to be @@ -701,11 +773,16 @@ FS_IOC_ADD_ENCRYPTION_KEY can fail with the following errors: - ``EACCES``: FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR was specified, but the caller does not have the CAP_SYS_ADMIN capability in the initial - user namespace + user namespace; or the raw key was specified by Linux key ID but the + process lacks Search permission on the key. - ``EDQUOT``: the key quota for this user would be exceeded by adding the key - ``EINVAL``: invalid key size or key specifier type, or reserved bits were set +- ``EKEYREJECTED``: the raw key was specified by Linux key ID, but the + key has the wrong type +- ``ENOKEY``: the raw key was specified by Linux key ID, but no key + exists with that ID - ``ENOTTY``: this type of filesystem does not implement encryption - ``EOPNOTSUPP``: the kernel was not configured with encryption support for this filesystem, or the filesystem superblock has not @@ -1108,8 +1185,8 @@ The context structs contain the same information as the corresponding policy structs (see `Setting an encryption policy`_), except that the context structs also contain a nonce. The nonce is randomly generated by the kernel and is used as KDF input or as a tweak to cause -different files to be encrypted differently; see `Per-file keys`_ and -`DIRECT_KEY policies`_. +different files to be encrypted differently; see `Per-file encryption +keys`_ and `DIRECT_KEY policies`_. Data path changes ----------------- @@ -1161,7 +1238,7 @@ filesystem-specific hash(es) needed for directory lookups. This allows the filesystem to still, with a high degree of confidence, map the filename given in ->lookup() back to a particular directory entry that was previously listed by readdir(). See :c:type:`struct -fscrypt_digested_name` in the source for more details. +fscrypt_nokey_name` in the source for more details. Note that the precise way that filenames are presented to userspace without the key is subject to change in the future. It is only meant diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 93e0a24045322b3e2417e024821520c9996eb6fc..c757c1c3cb814b2b1f5c565fd1c6551fa05d3b46 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -606,3 +606,10 @@ in your dentry operations instead. dentry separately, and it now has request_mask and query_flags arguments to specify the fields and sync type requested by statx. Filesystems not supporting any statx-specific features may ignore the new arguments. +-- +[mandatory] + + [should've been added in 2016] stale comment in finish_open() + nonwithstanding, failure exits in ->atomic_open() instances should + *NOT* fput() the file, no matter what. Everything is handled by the + caller. diff --git a/Documentation/sound/hd-audio/index.rst b/Documentation/sound/hd-audio/index.rst index f8a72ffffe66f49560a2f5cdb9ae61243824098f..6e12de9fc34e29eb168e33ac2ec53a3955ad9fc3 100644 --- a/Documentation/sound/hd-audio/index.rst +++ b/Documentation/sound/hd-audio/index.rst @@ -8,3 +8,4 @@ HD-Audio models controls dp-mst + realtek-pc-beep diff --git a/Documentation/sound/hd-audio/realtek-pc-beep.rst b/Documentation/sound/hd-audio/realtek-pc-beep.rst new file mode 100644 index 0000000000000000000000000000000000000000..be47c6f76a6e9fefed4a94c7b44bfea035d830ab --- /dev/null +++ b/Documentation/sound/hd-audio/realtek-pc-beep.rst @@ -0,0 +1,129 @@ +=============================== +Realtek PC Beep Hidden Register +=============================== + +This file documents the "PC Beep Hidden Register", which is present in certain +Realtek HDA codecs and controls a muxer and pair of passthrough mixers that can +route audio between pins but aren't themselves exposed as HDA widgets. As far +as I can tell, these hidden routes are designed to allow flexible PC Beep output +for codecs that don't have mixer widgets in their output paths. Why it's easier +to hide a mixer behind an undocumented vendor register than to just expose it +as a widget, I have no idea. + +Register Description +==================== + +The register is accessed via processing coefficient 0x36 on NID 20h. Bits not +identified below have no discernible effect on my machine, a Dell XPS 13 9350:: + + MSB LSB + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | |h|S|L| | B |R| | Known bits + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + |0|0|1|1| 0x7 |0|0x0|1| 0x7 | Reset value + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +1Ah input select (B): 2 bits + When zero, expose the PC Beep line (from the internal beep generator, when + enabled with the Set Beep Generation verb on NID 01h, or else from the + external PCBEEP pin) on the 1Ah pin node. When nonzero, expose the headphone + jack (or possibly Line In on some machines) input instead. If PC Beep is + selected, the 1Ah boost control has no effect. + +Amplify 1Ah loopback, left (L): 1 bit + Amplify the left channel of 1Ah before mixing it into outputs as specified + by h and S bits. Does not affect the level of 1Ah exposed to other widgets. + +Amplify 1Ah loopback, right (R): 1 bit + Amplify the right channel of 1Ah before mixing it into outputs as specified + by h and S bits. Does not affect the level of 1Ah exposed to other widgets. + +Loopback 1Ah to 21h [active low] (h): 1 bit + When zero, mix 1Ah (possibly with amplification, depending on L and R bits) + into 21h (headphone jack on my machine). Mixed signal respects the mute + setting on 21h. + +Loopback 1Ah to 14h (S): 1 bit + When one, mix 1Ah (possibly with amplification, depending on L and R bits) + into 14h (internal speaker on my machine). Mixed signal **ignores** the mute + setting on 14h and is present whenever 14h is configured as an output. + +Path diagrams +============= + +1Ah input selection (DIV is the PC Beep divider set on NID 01h):: + + + | | | + +--DIV--+--!DIV--+ {1Ah boost control} + | | + +--(b == 0)--+--(b != 0)--+ + | + >1Ah (Beep/Headphone Mic/Line In)< + +Loopback of 1Ah to 21h/14h:: + + <1Ah (Beep/Headphone Mic/Line In)> + | + {amplify if L/R} + | + +-----!h-----+-----S-----+ + | | + {21h mute control} | + | | + >21h (Headphone)< >14h (Internal Speaker)< + +Background +========== + +All Realtek HDA codecs have a vendor-defined widget with node ID 20h which +provides access to a bank of registers that control various codec functions. +Registers are read and written via the standard HDA processing coefficient +verbs (Set/Get Coefficient Index, Set/Get Processing Coefficient). The node is +named "Realtek Vendor Registers" in public datasheets' verb listings and, +apart from that, is entirely undocumented. + +This particular register, exposed at coefficient 0x36 and named in commits from +Realtek, is of note: unlike most registers, which seem to control detailed +amplifier parameters not in scope of the HDA specification, it controls audio +routing which could just as easily have been defined using standard HDA mixer +and selector widgets. + +Specifically, it selects between two sources for the input pin widget with Node +ID (NID) 1Ah: the widget's signal can come either from an audio jack (on my +laptop, a Dell XPS 13 9350, it's the headphone jack, but comments in Realtek +commits indicate that it might be a Line In on some machines) or from the PC +Beep line (which is itself multiplexed between the codec's internal beep +generator and external PCBEEP pin, depending on if the beep generator is +enabled via verbs on NID 01h). Additionally, it can mix (with optional +amplification) that signal onto the 21h and/or 14h output pins. + +The register's reset value is 0x3717, corresponding to PC Beep on 1Ah that is +then amplified and mixed into both the headphones and the speakers. Not only +does this violate the HDA specification, which says that "[a vendor defined +beep input pin] connection may be maintained *only* while the Link reset +(**RST#**) is asserted", it means that we cannot ignore the register if we care +about the input that 1Ah would otherwise expose or if the PCBEEP trace is +poorly shielded and picks up chassis noise (both of which are the case on my +machine). + +Unfortunately, there are lots of ways to get this register configuration wrong. +Linux, it seems, has gone through most of them. For one, the register resets +after S3 suspend: judging by existing code, this isn't the case for all vendor +registers, and it's led to some fixes that improve behavior on cold boot but +don't last after suspend. Other fixes have successfully switched the 1Ah input +away from PC Beep but have failed to disable both loopback paths. On my +machine, this means that the headphone input is amplified and looped back to +the headphone output, which uses the exact same pins! As you might expect, this +causes terrible headphone noise, the character of which is controlled by the +1Ah boost control. (If you've seen instructions online to fix XPS 13 headphone +noise by changing "Headphone Mic Boost" in ALSA, now you know why.) + +The information here has been obtained through black-box reverse engineering of +the ALC256 codec's behavior and is not guaranteed to be correct. It likely +also applies for the ALC255, ALC257, ALC235, and ALC236, since those codecs +seem to be close relatives of the ALC256. (They all share one initialization +function.) Additionally, other codecs like the ALC225 and ALC285 also have this +register, judging by existing fixups in ``patch_realtek.c``, but specific +data (e.g. node IDs, bit positions, pin mappings) for those codecs may differ +from what I've described here. diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst new file mode 100644 index 0000000000000000000000000000000000000000..9e78cb858f861b7ca52b987fcaed9942f3c2610c --- /dev/null +++ b/Documentation/usb/raw-gadget.rst @@ -0,0 +1,61 @@ +============== +USB Raw Gadget +============== + +USB Raw Gadget is a kernel module that provides a userspace interface for +the USB Gadget subsystem. Essentially it allows to emulate USB devices +from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is +currently a strictly debugging feature and shouldn't be used in +production, use GadgetFS instead. + +Comparison to GadgetFS +~~~~~~~~~~~~~~~~~~~~~~ + +Raw Gadget is similar to GadgetFS, but provides a more low-level and +direct access to the USB Gadget layer for the userspace. The key +differences are: + +1. Every USB request is passed to the userspace to get a response, while + GadgetFS responds to some USB requests internally based on the provided + descriptors. However note, that the UDC driver might respond to some + requests on its own and never forward them to the Gadget layer. + +2. GadgetFS performs some sanity checks on the provided USB descriptors, + while Raw Gadget allows you to provide arbitrary data as responses to + USB requests. + +3. Raw Gadget provides a way to select a UDC device/driver to bind to, + while GadgetFS currently binds to the first available UDC. + +4. Raw Gadget uses predictable endpoint names (handles) across different + UDCs (as long as UDCs have enough endpoints of each required transfer + type). + +5. Raw Gadget has ioctl-based interface instead of a filesystem-based one. + +Userspace interface +~~~~~~~~~~~~~~~~~~~ + +To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget +instances (bound to different UDCs) can be used at the same time. The +interaction with the opened file happens through the ioctl() calls, see +comments in include/uapi/linux/usb/raw_gadget.h for details. + +The typical usage of Raw Gadget looks like: + +1. Open Raw Gadget instance via /dev/raw-gadget. +2. Initialize the instance via USB_RAW_IOCTL_INIT. +3. Launch the instance with USB_RAW_IOCTL_RUN. +4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from + Raw Gadget and react to those depending on what kind of USB device + needs to be emulated. + +Potential future improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Implement ioctl's for setting/clearing halt status on endpoints. + +- Reporting more events (suspend, resume, etc.) through + USB_RAW_IOCTL_EVENT_FETCH. + +- Support O_NONBLOCK I/O. diff --git a/MAINTAINERS b/MAINTAINERS index 77c68f63e29f2696c677b51bbf8d13752983d781..858c3a81d063dd29c01dc48f4c73b964315aad0e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6899,7 +6899,7 @@ M: Joonas Lahtinen M: Rodrigo Vivi L: intel-gfx@lists.freedesktop.org W: https://01.org/linuxgraphics/ -B: https://01.org/linuxgraphics/documentation/how-report-bugs +B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs C: irc://chat.freenode.net/intel-gfx Q: http://patchwork.freedesktop.org/project/intel-gfx/ T: git git://anongit.freedesktop.org/drm-intel @@ -9591,6 +9591,12 @@ S: Maintained F: Documentation/scsi/NinjaSCSI.txt F: drivers/scsi/nsp32* +NINTENDO HID DRIVER +M: Daniel J. Ogorchock +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-nintendo* + NIOS2 ARCHITECTURE M: Ley Foon Tan L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers) diff --git a/Makefile b/Makefile index dc545445d4e3534acf5a4ba5dac1388d4de23f98..a75d57b348d9db88015b1b6c83ff8a96e17c1ed9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 170 +SUBLEVEL = 180 EXTRAVERSION = NAME = Petit Gorille @@ -875,7 +875,7 @@ LD_FLAGS_LTO_CLANG := -mllvm -import-instr-limit=5 KBUILD_LDFLAGS += $(LD_FLAGS_LTO_CLANG) KBUILD_LDFLAGS_MODULE += $(LD_FLAGS_LTO_CLANG) -KBUILD_LDS_MODULE += $(srctree)/scripts/module-lto.lds +KBUILD_LDFLAGS_MODULE += -T scripts/module-lto.lds # allow disabling only clang LTO where needed DISABLE_LTO_CLANG := -fno-lto @@ -883,11 +883,11 @@ export DISABLE_LTO_CLANG endif ifdef CONFIG_LTO -lto-flags := $(lto-clang-flags) -KBUILD_CFLAGS += $(lto-flags) +LTO_CFLAGS := $(lto-clang-flags) +KBUILD_CFLAGS += $(LTO_CFLAGS) DISABLE_LTO := $(DISABLE_LTO_CLANG) -export DISABLE_LTO +export LTO_CFLAGS DISABLE_LTO # LDFINAL_vmlinux and LDFLAGS_FINAL_vmlinux can be set to override # the linker and flags for vmlinux_link. @@ -913,12 +913,12 @@ endif ifdef CONFIG_CFI # cfi-flags are re-tested in prepare-compiler-check -cfi-flags := $(cfi-clang-flags) -KBUILD_CFLAGS += $(cfi-flags) +CFI_CFLAGS := $(cfi-clang-flags) +KBUILD_CFLAGS += $(CFI_CFLAGS) DISABLE_CFI := $(DISABLE_CFI_CLANG) DISABLE_LTO += $(DISABLE_CFI) -export DISABLE_CFI +export CFI_CFLAGS DISABLE_CFI endif ifdef CONFIG_SHADOW_CALL_STACK @@ -1256,7 +1256,7 @@ endif endif # Disable clang-specific config options when using a different compiler -clang-specific-configs := LTO_CLANG CFI_CLANG SHADOW_CALL_STACK +clang-specific-configs := LTO_CLANG CFI_CLANG SHADOW_CALL_STACK INIT_STACK_ALL PHONY += check-clang-specific-options check-clang-specific-options: $(KCONFIG_CONFIG) FORCE diff --git a/arch/Kconfig b/arch/Kconfig index eceadb83be66907a50e35ba76edf504f2251486f..82437946208dce5ef9e3fd5a855b11c493d949e7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -650,7 +650,6 @@ config LTO_CLANG depends on !KASAN select LTO select THIN_ARCHIVES - select LD_DEAD_CODE_DATA_ELIMINATION help This option enables clang's Link Time Optimization (LTO), which allows the compiler to optimize the kernel globally at link time. If you diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi index e114000a84f56c9e07ddd3a2e623c4dfeb3df6a2..d825b9dbae5de20fd5b697a40072de34dcffea57 100644 --- a/arch/arc/boot/dts/axs10x_mb.dtsi +++ b/arch/arc/boot/dts/axs10x_mb.dtsi @@ -70,6 +70,7 @@ interrupt-names = "macirq"; phy-mode = "rgmii"; snps,pbl = < 32 >; + snps,multicast-filter-bins = <256>; clocks = <&apbclk>; clock-names = "stmmaceth"; max-speed = <100>; diff --git a/arch/arc/include/asm/linkage.h b/arch/arc/include/asm/linkage.h index b29f1a9fd6f7359957389d5cd30725b7a449f579..07c8e1a6c56e25dd40463107809e40491baac77c 100644 --- a/arch/arc/include/asm/linkage.h +++ b/arch/arc/include/asm/linkage.h @@ -14,6 +14,8 @@ #ifdef __ASSEMBLY__ #define ASM_NL ` /* use '`' to mark new line in macro */ +#define __ALIGN .align 4 +#define __ALIGN_STR __stringify(__ALIGN) /* annotation for data we want in DCCM - if enabled in .config */ .macro ARCFP_DATA nm diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d93c1347d97d51733f35a55a89dc3cbd53bb660d..48ebd0d1a0a709bc601b8a357aece1019293b667 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1572,12 +1572,10 @@ config THUMB2_KERNEL bool "Compile the kernel in Thumb-2 mode" if !CPU_THUMBONLY depends on (CPU_V7 || CPU_V7M) && !CPU_V6 && !CPU_V6K default y if CPU_THUMBONLY - select ARM_ASM_UNIFIED select ARM_UNWIND help By enabling this option, the kernel will be compiled in - Thumb-2 mode. A compiler/assembler that understand the unified - ARM-Thumb syntax is needed. + Thumb-2 mode. If unsure, say N. @@ -1612,9 +1610,6 @@ config THUMB2_AVOID_R_ARM_THM_JUMP11 Unless you are sure your tools don't have this problem, say Y. -config ARM_ASM_UNIFIED - bool - config ARM_PATCH_IDIV bool "Runtime patch udiv/sdiv instructions into __aeabi_{u}idiv()" depends on CPU_32v7 && !XIP_KERNEL @@ -2113,7 +2108,7 @@ config XIP_PHYS_ADDR config KEXEC bool "Kexec system call (EXPERIMENTAL)" depends on (!SMP || PM_SLEEP_SMP) - depends on !CPU_V7M + depends on MMU select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 6f71a32967c05b41f5483922e4bddd0a6396a5b4..975d4d29e2e1fd0c931918d2f65b80d9afa93101 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -129,9 +129,11 @@ ifeq ($(cc-name),clang) CFLAGS_ABI += -meabi gnu endif +# Accept old syntax despite ".syntax unified" +AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W) + ifeq ($(CONFIG_THUMB2_KERNEL),y) AFLAGS_AUTOIT :=$(call as-option,-Wa$(comma)-mimplicit-it=always,-Wa$(comma)-mauto-it) -AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W) CFLAGS_ISA :=-mthumb $(AFLAGS_AUTOIT) $(AFLAGS_NOWARN) AFLAGS_ISA :=$(CFLAGS_ISA) -Wa$(comma)-mthumb # Work around buggy relocation from gas if requested: @@ -139,7 +141,7 @@ ifeq ($(CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11),y) CFLAGS_MODULE +=-fno-optimize-sibling-calls endif else -CFLAGS_ISA :=$(call cc-option,-marm,) +CFLAGS_ISA :=$(call cc-option,-marm,) $(AFLAGS_NOWARN) AFLAGS_ISA :=$(CFLAGS_ISA) endif diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts index b8565fc33eea6bc18b88ab72cf8774b15f3c678d..e5f2cca86f04483c428869ee1e82ae65373d684b 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts @@ -118,6 +118,7 @@ &sdhci { #address-cells = <1>; #size-cells = <0>; + pinctrl-names = "default"; pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>; mmc-pwrseq = <&wifi_pwrseq>; non-removable; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index fdb018e1278fb51820f97510241e349591caa79e..9d1e1061d8af1f8a9fbc3f92911ca9cfbe3649f9 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -454,6 +454,7 @@ "dsi0_ddr2", "dsi0_ddr"; + status = "disabled"; }; thermal: thermal@7e212000 { diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index fec965009b9fc5ed9a747695a9215e046bde5aef..f271c564d57d74f8e585f94662c9144468c5e13d 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -137,6 +137,7 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x0 0x0 0xc0000000>; + dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>; ti,hwmods = "l3_main_1", "l3_main_2"; reg = <0x0 0x44000000 0x0 0x1000000>, <0x0 0x45000000 0x0 0x1000>; @@ -302,6 +303,7 @@ device_type = "pci"; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x20013000 0x13000 0 0xffed000>; + dma-ranges = <0x02000000 0x0 0x00000000 0x00000000 0x1 0x00000000>; bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; @@ -356,6 +358,7 @@ device_type = "pci"; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x30013000 0x13000 0 0xffed000>; + dma-ranges = <0x02000000 0x0 0x00000000 0x00000000 0x1 0x00000000>; bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; diff --git a/arch/arm/boot/dts/dra76x.dtsi b/arch/arm/boot/dts/dra76x.dtsi index 1c88c581ff18879a4991f3a77634e3b998d56b3d..78d58b8af67e85fac505a697e858da29058f3751 100644 --- a/arch/arm/boot/dts/dra76x.dtsi +++ b/arch/arm/boot/dts/dra76x.dtsi @@ -17,3 +17,8 @@ &crossbar_mpu { ti,irqs-skip = <10 67 68 133 139 140>; }; + +&mmc3 { + /* dra76x is not affected by i887 */ + max-frequency = <96000000>; +}; diff --git a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi index 849eb3443cde2712705bbbe6c74679ddb81095a8..719e63092c2ea0911f2fcf8b19cb7b04d4f9a8b6 100644 --- a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi +++ b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi @@ -587,7 +587,7 @@ pinctrl-0 = <&pinctrl_usdhc2>; bus-width = <4>; cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; - wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>; + disable-wp; vmmc-supply = <®_3p3v_sd>; vqmmc-supply = <®_3p3v>; status = "okay"; @@ -598,7 +598,7 @@ pinctrl-0 = <&pinctrl_usdhc3>; bus-width = <4>; cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; - wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; + disable-wp; vmmc-supply = <®_3p3v_sd>; vqmmc-supply = <®_3p3v>; status = "okay"; @@ -1001,7 +1001,6 @@ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x40010040 MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x40010040 >; }; @@ -1014,7 +1013,6 @@ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x40010040 MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x40010040 >; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 1343c86988c54d2653bb39bc9e3ca2cf7629f69e..68f4482c35e2df127f45f4da276223683cc23edf 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -562,7 +562,7 @@ }; mdio0: mdio@2d24000 { - compatible = "fsl,etsec2-mdio"; + compatible = "gianfar"; device_type = "mdio"; #address-cells = <1>; #size-cells = <0>; @@ -570,7 +570,7 @@ }; mdio1: mdio@2d64000 { - compatible = "fsl,etsec2-mdio"; + compatible = "gianfar"; device_type = "mdio"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index eaff2a5751ddc11c5b1ec901a60c6f7c671aabac..bc3f53c79e9daa0c3748951e257639439b1d2829 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -131,6 +131,7 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0 0 0 0xc0000000>; + dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>; ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; reg = <0 0x44000000 0 0x2000>, <0 0x44800000 0 0x3000>, diff --git a/arch/arm/boot/dts/ox810se.dtsi b/arch/arm/boot/dts/ox810se.dtsi index 46aa6db8353ac3bc1dfa9f2af943d0fee15551c7..3d2f91234f1a7e212bb308d67ce465713ccc372e 100644 --- a/arch/arm/boot/dts/ox810se.dtsi +++ b/arch/arm/boot/dts/ox810se.dtsi @@ -322,8 +322,8 @@ interrupt-controller; reg = <0 0x200>; #interrupt-cells = <1>; - valid-mask = <0xFFFFFFFF>; - clear-mask = <0>; + valid-mask = <0xffffffff>; + clear-mask = <0xffffffff>; }; timer0: timer@200 { diff --git a/arch/arm/boot/dts/ox820.dtsi b/arch/arm/boot/dts/ox820.dtsi index 459207536a46654246517adfdd62cd6a38629202..8355cb0345255fbb25f2a07c8a3e63ebb4f13c1b 100644 --- a/arch/arm/boot/dts/ox820.dtsi +++ b/arch/arm/boot/dts/ox820.dtsi @@ -239,8 +239,8 @@ reg = <0 0x200>; interrupts = ; #interrupt-cells = <1>; - valid-mask = <0xFFFFFFFF>; - clear-mask = <0>; + valid-mask = <0xffffffff>; + clear-mask = <0xffffffff>; }; timer0: timer@200 { diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index 8ee0b2ca5d39a26556b570c6e529c1eeab2f42f3..2face089d65b90cc82322c4e4c99f36d42d0ec41 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -67,6 +67,14 @@ <0xf0000100 0x100>; }; + timer@f0000200 { + compatible = "arm,cortex-a9-global-timer"; + reg = <0xf0000200 0x100>; + interrupts = ; + clocks = <&cpg_clocks R8A7779_CLK_ZS>; + }; + timer@f0000600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0xf0000600 0x20>; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 554d0bdedc7a172c9bad3b8e84ac068cb388a412..f96b41ed5b96890996cd4f753a8e3b14f6d08719 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -1185,49 +1185,49 @@ usart0_clk: usart0_clk { #clock-cells = <0>; reg = <12>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; usart1_clk: usart1_clk { #clock-cells = <0>; reg = <13>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; usart2_clk: usart2_clk { #clock-cells = <0>; reg = <14>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; usart3_clk: usart3_clk { #clock-cells = <0>; reg = <15>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; uart0_clk: uart0_clk { #clock-cells = <0>; reg = <16>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; twi0_clk: twi0_clk { reg = <18>; #clock-cells = <0>; - atmel,clk-output-range = <0 16625000>; + atmel,clk-output-range = <0 41500000>; }; twi1_clk: twi1_clk { #clock-cells = <0>; reg = <19>; - atmel,clk-output-range = <0 16625000>; + atmel,clk-output-range = <0 41500000>; }; twi2_clk: twi2_clk { #clock-cells = <0>; reg = <20>; - atmel,clk-output-range = <0 16625000>; + atmel,clk-output-range = <0 41500000>; }; mci0_clk: mci0_clk { @@ -1243,19 +1243,19 @@ spi0_clk: spi0_clk { #clock-cells = <0>; reg = <24>; - atmel,clk-output-range = <0 133000000>; + atmel,clk-output-range = <0 166000000>; }; spi1_clk: spi1_clk { #clock-cells = <0>; reg = <25>; - atmel,clk-output-range = <0 133000000>; + atmel,clk-output-range = <0 166000000>; }; tcb0_clk: tcb0_clk { #clock-cells = <0>; reg = <26>; - atmel,clk-output-range = <0 133000000>; + atmel,clk-output-range = <0 166000000>; }; pwm_clk: pwm_clk { @@ -1266,7 +1266,7 @@ adc_clk: adc_clk { #clock-cells = <0>; reg = <29>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; dma0_clk: dma0_clk { @@ -1297,13 +1297,13 @@ ssc0_clk: ssc0_clk { #clock-cells = <0>; reg = <38>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; ssc1_clk: ssc1_clk { #clock-cells = <0>; reg = <39>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; sha_clk: sha_clk { diff --git a/arch/arm/boot/dts/sama5d3_can.dtsi b/arch/arm/boot/dts/sama5d3_can.dtsi index c5a3772741bf610b300a10147e76bcc882b973fb..0fac79f75c06ccd3008673a0147a3692656f095f 100644 --- a/arch/arm/boot/dts/sama5d3_can.dtsi +++ b/arch/arm/boot/dts/sama5d3_can.dtsi @@ -37,13 +37,13 @@ can0_clk: can0_clk { #clock-cells = <0>; reg = <40>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; can1_clk: can1_clk { #clock-cells = <0>; reg = <41>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; }; }; diff --git a/arch/arm/boot/dts/sama5d3_tcb1.dtsi b/arch/arm/boot/dts/sama5d3_tcb1.dtsi index 801f9745e82f1cd06163b1af76d37ab6a5c1b175..b80dbc45a3c20bb207346f08e980faa8b73d07c6 100644 --- a/arch/arm/boot/dts/sama5d3_tcb1.dtsi +++ b/arch/arm/boot/dts/sama5d3_tcb1.dtsi @@ -23,6 +23,7 @@ tcb1_clk: tcb1_clk { #clock-cells = <0>; reg = <27>; + atmel,clk-output-range = <0 166000000>; }; }; }; diff --git a/arch/arm/boot/dts/sama5d3_uart.dtsi b/arch/arm/boot/dts/sama5d3_uart.dtsi index 186377d41c917515523386827fae06ce19437a2a..48e23d18e5e37b7a53264c3fb57c5fee8e6b7ebf 100644 --- a/arch/arm/boot/dts/sama5d3_uart.dtsi +++ b/arch/arm/boot/dts/sama5d3_uart.dtsi @@ -42,13 +42,13 @@ uart0_clk: uart0_clk { #clock-cells = <0>; reg = <16>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; uart1_clk: uart1_clk { #clock-cells = <0>; reg = <17>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; }; }; diff --git a/arch/arm/configs/vendor/sa515m-perf_defconfig b/arch/arm/configs/vendor/sa515m-perf_defconfig index 8b002ff2c1080066338b4fe914f33d7691d7233c..ba1f7b8d3bca791a954c0d59add6974fac1f8486 100644 --- a/arch/arm/configs/vendor/sa515m-perf_defconfig +++ b/arch/arm/configs/vendor/sa515m-perf_defconfig @@ -166,6 +166,7 @@ CONFIG_BRIDGE=y CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SWITCHDEV=y CONFIG_QRTR=y CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y @@ -322,7 +323,6 @@ CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_UEVENT=y -CONFIG_USB_CONFIGFS_F_UAC1=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_GSI=y diff --git a/arch/arm/configs/vendor/sa515m_defconfig b/arch/arm/configs/vendor/sa515m_defconfig index 98c80cfb7720dd4d813f3a5b19315573e8a2034e..90b571160d954deaf63160314d9c5f00b1a12f62 100644 --- a/arch/arm/configs/vendor/sa515m_defconfig +++ b/arch/arm/configs/vendor/sa515m_defconfig @@ -166,6 +166,7 @@ CONFIG_BRIDGE=y CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SWITCHDEV=y CONFIG_QRTR=y CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y @@ -324,7 +325,6 @@ CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_UEVENT=y -CONFIG_USB_CONFIGFS_F_UAC1=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_GSI=y diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index 8a899bbc4584b56afa9dac374278efb1c0cda0af..232a5c1d88974f8b85fb7c4f45a0d6e2cb3c748a 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -41,7 +41,6 @@ CONFIG_EMBEDDED=y CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y @@ -76,8 +75,8 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y CONFIG_CPU_IDLE=y -CONFIG_ARM_CPUIDLE=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y @@ -267,17 +266,16 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y +CONFIG_IFB=y CONFIG_TUN=y CONFIG_MSM_RMNET_BAM=y CONFIG_PPP=y @@ -295,10 +293,23 @@ CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y -CONFIG_WIL6210=m +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y -CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -358,14 +369,11 @@ CONFIG_CPU_THERMAL=y CONFIG_DEVFREQ_THERMAL=y CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_TSENS=y -CONFIG_QTI_THERMAL_LIMITS_DCVS=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y -CONFIG_QTI_BCL_PMIC5=y -CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QTI_ADC_TM=y -CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y @@ -434,6 +442,7 @@ CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y +CONFIG_SND_SOC_TFA98XX=y CONFIG_UHID=y CONFIG_HID_APPLE=y CONFIG_HID_ELECOM=y @@ -483,7 +492,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_RTC_CLASS=y @@ -548,7 +556,7 @@ CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y -CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_DCC=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_ICNSS=y CONFIG_ICNSS_QMI=y @@ -573,7 +581,12 @@ CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_BGCOM_INTERFACE=y CONFIG_MSM_BGCOM=y +CONFIG_MSM_BGRSB=y +CONFIG_MSM_BGRSB_RPMSG=y CONFIG_MSM_PIL_SSR_BG=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -625,6 +638,7 @@ CONFIG_PAGE_OWNER=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y CONFIG_IPC_LOGGING=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y @@ -638,7 +652,6 @@ CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -652,4 +665,3 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index a1a1662dcb858db295698f84c157e8f079554351..e32e45440db34eaaafe3473569548937df26d40c 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -42,7 +42,6 @@ CONFIG_EMBEDDED=y CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y @@ -78,8 +77,8 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y CONFIG_CPU_IDLE=y -CONFIG_ARM_CPUIDLE=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y @@ -273,18 +272,17 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y +CONFIG_IFB=y CONFIG_TUN=y CONFIG_MSM_RMNET_BAM=y CONFIG_PPP=y @@ -302,9 +300,23 @@ CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y -CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -369,14 +381,11 @@ CONFIG_CPU_THERMAL=y CONFIG_DEVFREQ_THERMAL=y CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_TSENS=y -CONFIG_QTI_THERMAL_LIMITS_DCVS=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y -CONFIG_QTI_BCL_PMIC5=y -CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QTI_ADC_TM=y -CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y @@ -445,6 +454,7 @@ CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y +CONFIG_SND_SOC_TFA98XX=y CONFIG_UHID=y CONFIG_HID_APPLE=y CONFIG_HID_ELECOM=y @@ -497,7 +507,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_EDAC=y @@ -568,7 +577,7 @@ CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y -CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_DCC=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y CONFIG_MSM_GLADIATOR_ERP=y CONFIG_PANIC_ON_GLADIATOR_ERROR=y @@ -598,7 +607,12 @@ CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_BGCOM_INTERFACE=y CONFIG_MSM_BGCOM=y +CONFIG_MSM_BGRSB=y +CONFIG_MSM_BGRSB_RPMSG=y CONFIG_MSM_PIL_SSR_BG=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -714,7 +728,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -729,6 +742,5 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_CRC8=y CONFIG_XZ_DEC=y diff --git a/arch/arm/configs/vendor/trinket-perf_defconfig b/arch/arm/configs/vendor/trinket-perf_defconfig index bb27b3b2c7f980f6e5658381712c812b50e3607a..d50f0e7098f1128230049eb90cf1050e9f82d53d 100644 --- a/arch/arm/configs/vendor/trinket-perf_defconfig +++ b/arch/arm/configs/vendor/trinket-perf_defconfig @@ -265,11 +265,9 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -491,7 +489,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y @@ -652,7 +649,6 @@ CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -666,4 +662,3 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm/configs/vendor/trinket_defconfig b/arch/arm/configs/vendor/trinket_defconfig index 815167c2471b129d3c9a7e1de3ed621919634ab6..c941cc9f033c70332cab5f80b5d75ab9ca5a31a6 100644 --- a/arch/arm/configs/vendor/trinket_defconfig +++ b/arch/arm/configs/vendor/trinket_defconfig @@ -273,12 +273,10 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -505,7 +503,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y @@ -732,7 +729,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -747,5 +743,4 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_XZ_DEC=y diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 98089ffd91bb602649cc7724adafe5ce045b9c8a..078dbd25cca4c92f8556bc1359f1dfb7ec87ee93 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -144,6 +144,11 @@ static inline bool kvm_vcpu_dabt_issext(struct kvm_vcpu *vcpu) return kvm_vcpu_get_hsr(vcpu) & HSR_SSE; } +static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu) +{ + return false; +} + static inline int kvm_vcpu_dabt_get_rd(struct kvm_vcpu *vcpu) { return (kvm_vcpu_get_hsr(vcpu) & HSR_SRT_MASK) >> HSR_SRT_SHIFT; diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h index f3a7de71f515016bf9ab0b2525bfe622794975a7..848339d76f9a169b332e7b2535f3d877f968b8a1 100644 --- a/arch/arm/include/asm/kvm_mmio.h +++ b/arch/arm/include/asm/kvm_mmio.h @@ -26,6 +26,8 @@ struct kvm_decode { unsigned long rt; bool sign_extend; + /* Not used on 32-bit arm */ + bool sixty_four; }; void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data); diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h index a91ae499614cbb5e1c23a646a04082026bec061f..2c3b952be63ebbc536d767798eb21dfba153d25b 100644 --- a/arch/arm/include/asm/unified.h +++ b/arch/arm/include/asm/unified.h @@ -20,8 +20,10 @@ #ifndef __ASM_UNIFIED_H #define __ASM_UNIFIED_H -#if defined(__ASSEMBLY__) && defined(CONFIG_ARM_ASM_UNIFIED) +#if defined(__ASSEMBLY__) .syntax unified +#else +__asm__(".syntax unified"); #endif #ifdef CONFIG_CPU_V7M @@ -64,77 +66,4 @@ #endif /* CONFIG_THUMB2_KERNEL */ -#ifndef CONFIG_ARM_ASM_UNIFIED - -/* - * If the unified assembly syntax isn't used (in ARM mode), these - * macros expand to an empty string - */ -#ifdef __ASSEMBLY__ - .macro it, cond - .endm - .macro itt, cond - .endm - .macro ite, cond - .endm - .macro ittt, cond - .endm - .macro itte, cond - .endm - .macro itet, cond - .endm - .macro itee, cond - .endm - .macro itttt, cond - .endm - .macro ittte, cond - .endm - .macro ittet, cond - .endm - .macro ittee, cond - .endm - .macro itett, cond - .endm - .macro itete, cond - .endm - .macro iteet, cond - .endm - .macro iteee, cond - .endm -#else /* !__ASSEMBLY__ */ -__asm__( -" .macro it, cond\n" -" .endm\n" -" .macro itt, cond\n" -" .endm\n" -" .macro ite, cond\n" -" .endm\n" -" .macro ittt, cond\n" -" .endm\n" -" .macro itte, cond\n" -" .endm\n" -" .macro itet, cond\n" -" .endm\n" -" .macro itee, cond\n" -" .endm\n" -" .macro itttt, cond\n" -" .endm\n" -" .macro ittte, cond\n" -" .endm\n" -" .macro ittet, cond\n" -" .endm\n" -" .macro ittee, cond\n" -" .endm\n" -" .macro itett, cond\n" -" .endm\n" -" .macro itete, cond\n" -" .endm\n" -" .macro iteet, cond\n" -" .endm\n" -" .macro iteee, cond\n" -" .endm\n"); -#endif /* __ASSEMBLY__ */ - -#endif /* CONFIG_ARM_ASM_UNIFIED */ - #endif /* !__ASM_UNIFIED_H */ diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index f4dd7f9663c10a704d3858de6beb538e5023cf78..0001742c131d965908fa7c9572482862dd269eba 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -103,6 +103,8 @@ static bool __init cntvct_functional(void) * this. */ np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); + if (!np) + np = of_find_compatible_node(NULL, NULL, "arm,armv8-timer"); if (!np) goto out_put; diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index 6709a8d33963b679b0a0f6ec683e3291a7f07a71..f1e34f16cfab9ad98db4628c78bbf558544cebc5 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -100,7 +100,7 @@ ENTRY(arm_copy_from_user) ENDPROC(arm_copy_from_user) - .pushsection .fixup,"ax" + .pushsection .text.fixup,"ax" .align 0 copy_abort_preamble ldmfd sp!, {r1, r2, r3} diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 8ff71058207dc1a43939d985f9781d68219d73cd..1d0923b4a82b38db31850e8ba1ff277b629bf39b 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -87,6 +87,10 @@ AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o endif +ifeq ($(CONFIG_ARM_CPU_SUSPEND),y) +AFLAGS_resume-imx6.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_IMX6) += resume-imx6.o +endif obj-$(CONFIG_SOC_IMX6) += pm-imx6.o obj-$(CONFIG_SOC_IMX1) += mach-imx1.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index b09a2ec192671f6e496d47178210d2ac706026c1..4b318c86444686199bf7430813b8727c76ec3a4a 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -111,17 +111,17 @@ void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); #ifdef CONFIG_SUSPEND -void v7_cpu_resume(void); void imx53_suspend(void __iomem *ocram_vbase); extern const u32 imx53_suspend_sz; void imx6_suspend(void __iomem *ocram_vbase); #else -static inline void v7_cpu_resume(void) {} static inline void imx53_suspend(void __iomem *ocram_vbase) {} static const u32 imx53_suspend_sz; static inline void imx6_suspend(void __iomem *ocram_vbase) {} #endif +void v7_cpu_resume(void); + void imx6_pm_ccm_init(const char *ccm_compat); void imx6q_pm_init(void); void imx6dl_pm_init(void); diff --git a/arch/arm/mach-imx/resume-imx6.S b/arch/arm/mach-imx/resume-imx6.S new file mode 100644 index 0000000000000000000000000000000000000000..5bd1ba7ef15b61cb98d1bd2d3af4e85acc5ec632 --- /dev/null +++ b/arch/arm/mach-imx/resume-imx6.S @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2014 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include "hardware.h" + +/* + * The following code must assume it is running from physical address + * where absolute virtual addresses to the data section have to be + * turned into relative ones. + */ + +ENTRY(v7_cpu_resume) + bl v7_invalidate_l1 +#ifdef CONFIG_CACHE_L2X0 + bl l2c310_early_resume +#endif + b cpu_resume +ENDPROC(v7_cpu_resume) diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index 76ee2ceec8d546d0ca3f51aebcb8f40509213ba6..7d84b617af4815817d3ffbb60b8c067bcbb8a41b 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -333,17 +333,3 @@ resume: ret lr ENDPROC(imx6_suspend) - -/* - * The following code must assume it is running from physical address - * where absolute virtual addresses to the data section have to be - * turned into relative ones. - */ - -ENTRY(v7_cpu_resume) - bl v7_invalidate_l1 -#ifdef CONFIG_CACHE_L2X0 - bl l2c310_early_resume -#endif - b cpu_resume -ENDPROC(v7_cpu_resume) diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index dd4a67dabd91692dffae18fd07245c372770840f..b7cd41461e7d2fb3175dc0e8e45be9aacb7b73c0 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -382,6 +382,14 @@ _pll_m_c_x_done: pll_locked r1, r0, CLK_RESET_PLLC_BASE pll_locked r1, r0, CLK_RESET_PLLX_BASE + tegra_get_soc_id TEGRA_APB_MISC_BASE, r1 + cmp r1, #TEGRA30 + beq 1f + ldr r1, [r0, #CLK_RESET_PLLP_BASE] + bic r1, r1, #(1<<31) @ disable PllP bypass + str r1, [r0, #CLK_RESET_PLLP_BASE] +1: + mov32 r7, TEGRA_TMRUS_BASE ldr r1, [r7] add r1, r1, #LOCK_DELAY @@ -641,7 +649,10 @@ tegra30_switch_cpu_to_clk32k: str r0, [r4, #PMC_PLLP_WB0_OVERRIDE] /* disable PLLP, PLLA, PLLC and PLLX */ + tegra_get_soc_id TEGRA_APB_MISC_BASE, r1 + cmp r1, #TEGRA30 ldr r0, [r5, #CLK_RESET_PLLP_BASE] + orrne r0, r0, #(1 << 31) @ enable PllP bypass on fast cluster bic r0, r0, #(1 << 30) str r0, [r5, #CLK_RESET_PLLP_BASE] ldr r0, [r5, #CLK_RESET_PLLA_BASE] diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index f0eb37b5ff098fc86aeda729390e3340699f0eee..34ae9585edc48ed18d5b671e735e3bb4bfe36608 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -356,7 +356,7 @@ static inline void poison_init_mem(void *s, size_t count) *p++ = 0xe7fddef0; } -static inline void +static inline void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn) { struct page *start_pg, *end_pg; diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index d8d90cf65b39f835ff84eea9fa687a845d2245ac..b397cf1e486d25a29f2e75f9dc4bfa0e96535e22 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -18,6 +18,7 @@ #include #include #include +#include #include "proc-macros.S" @@ -547,10 +548,10 @@ __v7_setup_stack_ptr: ENDPROC(__v7_setup) .bss - .align 2 + .align L1_CACHE_SHIFT __v7_setup_stack: .space 4 * 7 @ 7 registers - + .align L1_CACHE_SHIFT __INITDATA .weak cpu_v7_bugs_init diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index b18fb70c5dcf9b1b2cc6338ee8f79507e43376f7..e13aca6e6d4b1e067c449a6c6810212f9980c108 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -796,7 +796,11 @@ static inline void emit_a32_rsh_i64(const u8 dst[], bool dstk, } /* Do LSR operation */ - if (val < 32) { + if (val == 0) { + /* An immediate value of 0 encodes a shift amount of 32 + * for LSR. To shift by 0, don't do anything. + */ + } else if (val < 32) { emit(ARM_MOV_SI(tmp2[1], rd, SRTYPE_LSR, val), ctx); emit(ARM_ORR_SI(rd, tmp2[1], rm, SRTYPE_ASL, 32 - val), ctx); emit(ARM_MOV_SI(rm, rm, SRTYPE_LSR, val), ctx); @@ -829,7 +833,11 @@ static inline void emit_a32_arsh_i64(const u8 dst[], bool dstk, } /* Do ARSH operation */ - if (val < 32) { + if (val == 0) { + /* An immediate value of 0 encodes a shift amount of 32 + * for ASR. To shift by 0, don't do anything. + */ + } else if (val < 32) { emit(ARM_MOV_SI(tmp2[1], rd, SRTYPE_LSR, val), ctx); emit(ARM_ORR_SI(rd, tmp2[1], rm, SRTYPE_ASL, 32 - val), ctx); emit(ARM_MOV_SI(rm, rm, SRTYPE_ASR, val), ctx); diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi index 169e171407a631cef269be07a5836dcfabb3aae9..acd205ef329f7da400ba35aae6206bba98bd9938 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi @@ -21,6 +21,8 @@ }; &fman0 { + fsl,erratum-a050385; + /* these aliases provide the FMan ports mapping */ enet0: ethernet@e0000 { }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts index 3dc0c8e9663d435a00c938efbf11385c63c9db09..3aead63e54755a4777acb6069b74726f9b1fc9e4 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts @@ -155,12 +155,12 @@ ethernet@e4000 { phy-handle = <&rgmii_phy1>; - phy-connection-type = "rgmii-txid"; + phy-connection-type = "rgmii-id"; }; ethernet@e6000 { phy-handle = <&rgmii_phy2>; - phy-connection-type = "rgmii-txid"; + phy-connection-type = "rgmii-id"; }; ethernet@e8000 { diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts index 5dc2782e2a58e785c8ec0263d2f2faafe9c07987..e775e59d03702c8462b2c0bbe52064e7f6310414 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts @@ -162,12 +162,12 @@ &fman0 { ethernet@e4000 { phy-handle = <&rgmii_phy1>; - phy-connection-type = "rgmii"; + phy-connection-type = "rgmii-id"; }; ethernet@e6000 { phy-handle = <&rgmii_phy2>; - phy-connection-type = "rgmii"; + phy-connection-type = "rgmii-id"; }; ethernet@e8000 { diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index afd6433706da0a1d82840ad00b4663d79dd3e53b..b553403e7dd069d7ff2e98682560ae9cda467088 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -26,7 +26,10 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-cdp.dtb \ sa8155p-v2-adp-star.dtb \ sa8155-v2-adp-air.dtb \ sa8155p-v2-adp-air.dtb \ - sa8155p-v2-adp-air-lpass.dtb + sa8155p-v2-adp-air-lpass.dtb \ + sa8155p-v2-adp-air-capture.dtb \ + sa8155p-v2-adp-star-capture.dtb + endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) @@ -40,7 +43,7 @@ sa8195p-adp-star-overlay.dtbo-base := sa8195p.dtb sa8195p-v2-adp-air-overlay.dtbo-base := sa8195p.dtb else dtb-$(CONFIG_ARCH_SDMSHRIKE) += sdmshrike-cdp.dtb \ - sa8195p-adp-star.dtb + sa8195p-adp-star.dtb \ sa8195p-v2-adp-air.dtb endif @@ -74,7 +77,9 @@ dtb-$(CONFIG_ARCH_SM6150) += sa6155-adp-star.dtb \ sa6155p-v2-adp-air-lpass.dtb endif -else + +else # TARGET_BOARD_TYPE != auto + dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk01.dtb @@ -83,12 +88,14 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8992-bullhead-rev-101.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb dtb-$(CONFIG_ARCH_QCS403) += qcs403-iot-sku1.dtb \ - qcs403-iot-sku3.dtb \ - qcs403-iot-sku5.dtb \ - qcs401-iot-sku5.dtb \ - qcs404-iot-sku3.dtb \ - qcs404-iot-sku5.dtb \ - qcs404-iot-sku6.dtb + qcs403-iot-sku3.dtb \ + qcs403-iot-sku5.dtb \ + qcs401-iot-sku5.dtb \ + qcs404-iot-sku3.dtb \ + qcs404-iot-sku5.dtb \ + qcs404-iot-sku6.dtb \ + sa2145p-ccard-nand-dc.dtb \ + sa2150p-ccard-nand-dc.dtb dtb-$(CONFIG_ARCH_QCS405) += qcs405-iot-sku1.dtb \ qcs407-iot-sku1.dtb \ @@ -172,6 +179,8 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sa8155p-v2-adp-star.dtb \ sa8155-v2-adp-air.dtb \ sa8155p-v2-adp-air.dtb \ + sa8155p-v2-adp-air-capture.dtb \ + sa8155p-v2-adp-star-capture.dtb \ sa8155-adp-alcor.dtb \ sa8155p-adp-alcor.dtb \ sm8150-v2-rumi.dtb \ @@ -197,6 +206,7 @@ dtb-$(CONFIG_QTI_GVM) += sa8155-vm-la.dtb \ sa8195-vm-la.dtb \ sa8195-vm-la-mt.dtb \ sa8195-vm-lv.dtb \ + sa8195-vm-lv-lxc.dtb \ sa8195-vm-lv-mt.dtb ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) @@ -321,17 +331,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) trinket-external-codec-idp-overlay.dtbo \ trinket-usbc-external-codec-idp-overlay.dtbo \ trinket-usbc-idp-overlay.dtbo \ - trinket-dp-idp-overlay.dtbo \ - qcm6125-iot-idp-overlay.dtbo \ - qcs6125-iot-idp-overlay.dtbo \ - qcm6125-iot-external-codec-idp-overlay.dtbo \ - qcs6125-iot-external-codec-idp-overlay.dtbo \ - qcm6125-iot-usbc-external-codec-idp-overlay.dtbo \ - qcs6125-iot-usbc-external-codec-idp-overlay.dtbo \ - qcm6125-iot-usbc-idp-overlay.dtbo \ - qcs6125-iot-usbc-idp-overlay.dtbo \ - qcm6125-iot-dp-idp-overlay.dtbo \ - qcs6125-iot-dp-idp-overlay.dtbo + trinket-dp-idp-overlay.dtbo trinket-rumi-overlay.dtbo-base := trinket.dtb trinket-idp-overlay.dtbo-base := trinket.dtb @@ -340,16 +340,6 @@ trinket-external-codec-idp-overlay.dtbo-base := trinket.dtb trinket-usbc-external-codec-idp-overlay.dtbo-base := trinket.dtb trinket-usbc-idp-overlay.dtbo-base := trinket.dtb trinket-dp-idp-overlay.dtbo-base := trinket.dtb -qcm6125-iot-idp-overlay.dtbo-base := qcm6125.dtb -qcs6125-iot-idp-overlay.dtbo-base := qcs6125.dtb -qcm6125-iot-external-codec-idp-overlay.dtbo-base := qcm6125.dtb -qcs6125-iot-external-codec-idp-overlay.dtbo-base := qcs6125.dtb -qcm6125-iot-usbc-external-codec-idp-overlay.dtbo-base := qcm6125.dtb -qcs6125-iot-usbc-external-codec-idp-overlay.dtbo-base := qcs6125.dtb -qcm6125-iot-usbc-idp-overlay.dtbo-base := qcm6125.dtb -qcs6125-iot-usbc-idp-overlay.dtbo-base := qcs6125.dtb -qcm6125-iot-dp-idp-overlay.dtbo-base := qcm6125.dtb -qcs6125-iot-dp-idp-overlay.dtbo-base := qcs6125.dtb else dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb \ trinket-idp.dtb \ @@ -357,17 +347,7 @@ dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb \ trinket-external-codec-idp.dtb \ trinket-usbc-external-codec-idp.dtb \ trinket-usbc-idp.dtb \ - trinket-dp-idp.dtb \ - qcm6125-iot-idp.dtb \ - qcs6125-iot-idp.dtb \ - qcm6125-iot-external-codec-idp.dtb \ - qcs6125-iot-external-codec-idp.dtb \ - qcm6125-iot-usbc-external-codec-idp.dtb \ - qcs6125-iot-usbc-external-codec-idp.dtb \ - qcm6125-iot-usbc-idp.dtb \ - qcs6125-iot-usbc-idp.dtb \ - qcm6125-iot-dp-idp.dtb \ - qcs6125-iot-dp-idp.dtb + trinket-dp-idp.dtb endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) @@ -435,7 +415,7 @@ dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ sdxprairie-v2-mtp-v1.1-cpe.dtb \ sdxprairie-v2-mtp-v1.1.dtb \ sdxprairie-v2-mtp-le-cpe.dtb \ - sdxprairie-v2-ttp-cpe.dtb \ + sdxprairie-v2-mtp-au-dsda.dtb \ sa515m-v2-ttp.dtb \ sa515m-v2-ttp-usb-ep.dtb \ sa515m-v2-ttp-pcie-ep.dtb \ @@ -547,8 +527,8 @@ dtb-$(CONFIG_ARCH_SDM429W) += sdm429-wtp.dtb\ sda429-bg-dvt2-wtp.dtb endif - endif + ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi b/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi index 0eba4a21ff28f6ae242c9d6d3a0cc88e44d90623..776b1b552f0c5599586838156514a9551fa159f2 100644 --- a/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -134,6 +134,7 @@ qcom,poll-cfg-gdscr; domain-addr = <&gpu_gx_domain_addr>; sw-reset = <&gpu_gx_sw_reset>; + qcom,skip-disable-before-sw-enable; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/atoll-npu.dtsi b/arch/arm64/boot/dts/qcom/atoll-npu.dtsi index 4a236a5f30774fa01810122d4686dec5c77b9156..2743496362cee799562bc95449db541617007e53 100644 --- a/arch/arm64/boot/dts/qcom/atoll-npu.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-npu.dtsi @@ -31,6 +31,7 @@ iommus = <&apps_smmu 0x1441 0x0>, <&apps_smmu 0x1442 0x0>, <&apps_smmu 0x1461 0x0>, <&apps_smmu 0x1462 0x0>, <&apps_smmu 0x1481 0x0>, <&apps_smmu 0x1482 0x0>; + qcom,npu-dsp-sid-mapped; clocks = <&clock_npucc NPU_CC_XO_CLK>, <&clock_npucc NPU_CC_CORE_CLK>, diff --git a/arch/arm64/boot/dts/qcom/atoll.dtsi b/arch/arm64/boot/dts/qcom/atoll.dtsi index 3c8b470205c1f44ffd860cae794aecbf55cce041..4f2f8b1c7b09ab3691ee9807a3cb88c11f34e277 100644 --- a/arch/arm64/boot/dts/qcom/atoll.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll.dtsi @@ -2679,13 +2679,12 @@ sdhc_1: sdhci@7c4000 { compatible = "qcom,sdhci-msm-v5"; - reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>; - reg-names = "hc_mem", "cmdq_mem"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>, <0x7c8000 0x8000>; + reg-names = "hc_mem", "cmdq_mem", "cmdq_ice"; interrupts = , ; interrupt-names = "hc_irq", "pwr_irq"; - sdhc-msm-crypto = <&sdcc1_ice>; qcom,bus-width = <8>; qcom,large-address-bus; @@ -2835,11 +2834,11 @@ ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; - reg = <0x1d84000 0x3000>; + reg = <0x1d84000 0x3000>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; interrupts = <0 265 0>; phys = <&ufsphy_mem>; phy-names = "ufsphy"; - ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <1>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ diff --git a/arch/arm64/boot/dts/qcom/mdm9607.dtsi b/arch/arm64/boot/dts/qcom/mdm9607.dtsi index 23c160c7fa8c882f1fc5489323567de2e49fd0f8..285495da97d7256ff3acdd0c87d517592b26f690 100644 --- a/arch/arm64/boot/dts/qcom/mdm9607.dtsi +++ b/arch/arm64/boot/dts/qcom/mdm9607.dtsi @@ -57,6 +57,12 @@ reg = <0x87c00000 0x400000>; }; + tz_apps_mem: tz_apps_region@0 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x88000000 0x500000>; + }; + audio_mem: audio_region@0 { compatible = "shared-dma-pool"; reusable; @@ -69,7 +75,7 @@ reusable; alignment = <0x400000>; size = <0x0400000>; - status = "disabled"; + status = "ok"; }; }; @@ -1673,14 +1679,15 @@ qcom,ce-opp-freq = <100000000>; }; - qcom_seecom: qseecom@87a80000 { + qcom_seecom: qseecom@88000000 { compatible = "qcom,qseecom"; - reg = <0x87a80000 0x100000>; + reg = <0x88000000 0x500000>; reg-names = "secapp-region"; memory-region = <&qseecom_mem>; qcom,hlos-num-ce-hw-instances = <1>; qcom,hlos-ce-hw-instance = <0>; qcom,qsee-ce-hw-instance = <0>; + qcom,support-bus-scaling; qcom,msm-bus,name = "qseecom-noc"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <1>; @@ -1697,7 +1704,7 @@ clock-names = "core_clk_src", "core_clk", "iface_clk", "bus_clk"; qcom,ce-opp-freq = <100000000>; - status = "disabled"; + status = "ok"; }; qcom_tzlog: tz-log@8600720 { diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-qcs405.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-qcs405.dtsi index 2338738e7c551a0a4ad7840eb23e52a598921342..449d918b8f66a0d0659d823317449f03f5d5eaa4 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-qcs405.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,7 +18,7 @@ reg = <0x1f00000 0x10000>, <0x1ee2000 0x20>; reg-names = "base", "tcu-base"; - #iommu-cells = <2>; + #iommu-cells = <1>; qcom,tz-device-id = "GPU"; qcom,skip-init; qcom,disable-atos; diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index ee36196df1d1a851c1ff57ec3b8da43a7017243e..4a8f485645380aa97f0651dad66d74608918eed4 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -84,18 +84,18 @@ }; wcnss_mem: wcnss@89300000 { - reg = <0x0 0x89300000 0x0 0x700000>; + reg = <0x0 0x89300000 0x0 0x600000>; no-map; }; venus_mem: venus@89900000 { - reg = <0x0 0x89A00000 0x0 0x600000>; + reg = <0x0 0x89900000 0x0 0x600000>; no-map; }; mba_mem: mba@8ea00000 { no-map; - reg = <0 0x8A000000 0 0x100000>; + reg = <0 0x8ea00000 0 0x100000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 6f372ec055dd310a51757cb6274d00abf864d79f..da2949586c7a3bcc513f2be2e0ce23f7366815da 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -788,6 +788,8 @@ interrupts = <0 138 0>; phys = <&hsusb_phy2>; phy-names = "usb2-phy"; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; }; }; @@ -817,6 +819,8 @@ interrupts = <0 131 0>; phys = <&hsusb_phy1>, <&ssusb_phy_0>; phy-names = "usb2-phy", "usb3-phy"; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi index 7ebb230eb2690efda7eb84d769299d5b4f80272a..a26ed10d7dc57f0ebef5fbd3c513e600288c7612 100644 --- a/arch/arm64/boot/dts/qcom/pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/pm660.dtsi @@ -551,6 +551,106 @@ }; &thermal_zones { + ibat-high { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 0>; + wake-capable-sensor; + + trips { + ibat-high { + temperature = <4200>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + ibat-vhigh { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 1>; + wake-capable-sensor; + + trips { + ibat-vhigh { + temperature = <4300>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + vbat_adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 2>; + wake-capable-sensor; + tracks-low; + + trips { + pm660_vbat_adc: vbat-adc { + temperature = <3200>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + vbat_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 3>; + wake-capable-sensor; + tracks-low; + + trips { + vbat-low { + temperature = <2800>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + vbat_too_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 4>; + wake-capable-sensor; + tracks-low; + + trips { + vbat-too-low { + temperature = <2600>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + soc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 5>; + wake-capable-sensor; + tracks-low; + + trips { + pm660_low_soc: low-soc { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + pm660_temp_alarm: pm660-tz { polling-delay-passive = <0>; polling-delay = <0>; diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi index cee370cb5a548597dd63f464d0f3980f71269ed0..5640a5b9126e16f3ccb0ca7445c27154a328fece 100644 --- a/arch/arm64/boot/dts/qcom/pm660l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi @@ -163,6 +163,7 @@ label = "backlight"; qcom,pmic-revid = <&pm660l_revid>; qcom,auto-calibration; + qcom,sync-dly = <800>; status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts deleted file mode 100644 index 96696b0399be409de99c514d9391b98c8a1ac838..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include -#include -#include "qcm6125-iot-idp.dtsi" -#include "trinket-audio-overlay.dtsi" - -/ { - model = "Display Port Enable IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,msm-id = <467 0x10000>; - qcom,board-id = <34 4>; -}; - -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; - -&sde_dp { - status = "ok"; - qcom,dp-hpd-gpio = <&tlmm 100 0>; - qcom,dp-low-power-hw-hpd; -}; - -&mdss_dp_pll { - status = "ok"; -}; - -&usb0 { - dwc3@4e00000 { - usb-phy = <&qusb_phy0>, <&usb_nop_phy>; - maximum-speed = "high-speed"; - }; -}; - -&mdss_mdp { - connectors = <&sde_wb &sde_dsi &sde_dp>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts deleted file mode 100644 index 2a0232f761737b484128abd200febe85fadb93a8..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcm6125.dtsi" -#include "qcm6125-iot-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT Disp. Port Enable IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,board-id = <34 4>; -}; - -&sde_dp { - status = "ok"; - qcom,dp-hpd-gpio = <&tlmm 100 0>; - qcom,dp-low-power-hw-hpd; -}; - -&mdss_dp_pll { - status = "ok"; -}; - -&usb0 { - dwc3@4e00000 { - usb-phy = <&qusb_phy0>, <&usb_nop_phy>; - maximum-speed = "high-speed"; - }; -}; - -&mdss_mdp { - connectors = <&sde_wb &sde_dsi &sde_dp>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts deleted file mode 100644 index c8a93d2e1cc4c2c534385fb9d8bcbef257f45144..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include - -#include "qcm6125-iot-idp.dtsi" -#include "trinket-tasha-codec-audio-overlay.dtsi" -#include "trinket-tasha-codec.dtsi" - -/ { - model = "Ext Audio Codec IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,msm-id = <467 0x10000>; - qcom,board-id = <34 1>; -}; - -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts deleted file mode 100644 index 586d54193c076f103a446bbc990e50f929769fdd..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcm6125.dtsi" -#include "qcm6125-iot-idp.dtsi" -#include "trinket-tasha-codec-audio-overlay.dtsi" -#include "trinket-tasha-codec.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT Ext Audio Codec IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,board-id = <34 1>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-idp-overlay.dts deleted file mode 100644 index 936473fcec4beef7c4cf07ff809aa6ce7409eb51..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-idp-overlay.dts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include "qcm6125-iot-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT IDP Overlay"; - compatible = "qcom,qcm6125"; - qcom,msm-id = <467 0x10000>; - qcom,board-id = <34 0>; -}; - diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-idp.dts deleted file mode 100644 index 37f06e2c3f4661dd92aed8dd26ea37101d3125c5..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-idp.dts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcm6125.dtsi" -#include "qcm6125-iot-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT IDP SoC"; - compatible = "qcom,qcm6125"; - qcom,board-id = <34 0>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-idp.dtsi b/arch/arm64/boot/dts/qcom/qcm6125-iot-idp.dtsi deleted file mode 100644 index 6d198b235fbc228456a2d965ddb01901d588bb65..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-idp.dtsi +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include "trinket-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts deleted file mode 100644 index 73f65a9fc2d638ec2e6fe138e5c8ab54cf3b4b45..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcm6125.dtsi" -#include "qcm6125-iot-idp.dtsi" -#include "qcm6125-iot-usbc-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT USBC Audio IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,board-id = <34 2>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125.dts b/arch/arm64/boot/dts/qcom/qcm6125.dts deleted file mode 100644 index 4e31d2849dc3d53d5e1088c6c1a6fea406f6343a..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125.dts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcm6125.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT IDP SoC"; - compatible = "qcom,qcm6125"; - qcom,board-id = <0 0>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125.dtsi b/arch/arm64/boot/dts/qcom/qcm6125.dtsi deleted file mode 100644 index dca459b90404ff6a78fbbd96ff9ed973fdaab74f..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcm6125.dtsi +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "trinket.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125"; - compatible = "qcom,qcm6125"; - qcom,msm-id = <467 0x0>; - qcom,msm-name = "QCM6125"; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-gpu.dtsi b/arch/arm64/boot/dts/qcom/qcs405-gpu.dtsi index 2b58972a222c3cc840279eb9538e6bcdc84e774a..5c04900cd0b16680edb2ed4f67a7176ae7b36c62 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-gpu.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -180,7 +180,7 @@ qcom,retention; gfx3d_user: gfx3d_user { compatible = "qcom,smmu-kgsl-cb"; - iommus = <&gfx_iommu 0 1>; + iommus = <&gfx_iommu 0>; qcom,gpu-offset = <0xa000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index dfbb2146b1c9b8c8aeb964adbc027ef84764919d..52aff5591aea8ef0b4e5cf1c261785c823cb991f 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -962,6 +962,11 @@ qcom,proc-img-to-load = "cdsp"; }; + qcom,eth_dev_qrtr { + compatible = "qcom,qrtr-ethernet-dev"; + qcom,low-latency; + }; + qcom,glink { compatible = "qcom,glink"; #address-cells = <1>; @@ -1579,7 +1584,7 @@ }; mtl_tx_setup: tx-queues-config { - snps,tx-queues-to-use = <5>; + snps,tx-queues-to-use = <4>; snps,tx-sched-sp; queue0 { snps,dcb-algorithm; @@ -1606,7 +1611,7 @@ }; }; - ethqos_hw: qcom,ethernet@00020000 { + ethqos_hw: qcom,ethernet@07A80000 { compatible = "qcom,stmmac-ethqos"; reg = <0x07A80000 0x10000>, <0x7A96000 0x100>; @@ -1637,7 +1642,6 @@ qcom,bus-vector-names = "0", "10", "100", "1000"; snps,tso; snps,pbl = <32>; - mac-address = [00 55 7B B5 7D f7]; clocks = <&clock_gcc GCC_ETH_AXI_CLK>, <&clock_gcc GCC_ETH_SLAVE_AHB_CLK>, <&clock_gcc GCC_ETH_PTP_CLK>, @@ -1718,9 +1722,9 @@ qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = <98 512 0 0>, <1 781 0 0>, /* No vote */ - <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ - <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ - <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + <98 512 2500 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 25000 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 250000 0>, <1 781 0 40000>; /* 1000Mbps vote */ qcom,bus-vector-names = "0", "10", "100", "1000"; clocks = <&clock_gcc GCC_ETH_AXI_CLK>, <&clock_gcc GCC_ETH_PTP_CLK>, diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dts b/arch/arm64/boot/dts/qcom/qcs410-iot.dts index 2fe709638dbc56f59428a298b97719caa314859a..3c640e55c7216cf776b11a20670cb686966f1c55 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dts +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dts @@ -14,7 +14,6 @@ #include "qcs410.dtsi" #include "qcs410-iot.dtsi" -#include "sm6150-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS410 IOT"; @@ -22,6 +21,3 @@ qcom,board-id = <32 0>; }; -&sm6150_snd { - /delete-property/ fsa4480-i2c-handle; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi index 237eaee48848d628cec0cad830826163ff2b7a8d..3dc3f2141b1767476cfd42b1a8be88732665546a 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi @@ -10,355 +10,10 @@ * GNU General Public License for more details. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qcs410.dtsi" -#include "sm6150-sde-pll.dtsi" -#include "sm6150-sde-display.dtsi" -#include "qcs610-camera-sensor-idp.dtsi" +#include "qcs610-iot.dtsi" / { model = "Qualcomm Technologies, Inc. QCS410 IOT"; compatible = "qcom,qcs410-iot", "qcom,qcs410", "qcom,iot"; }; -&qupv3_se3_i2c { - status = "ok"; - #include "smb1390.dtsi" -}; - -&fsa4480 { - status = "disabled"; -}; - -&pm6150l_gpios { - key_vol_up { - key_vol_up_default: key_vol_up_default { - pins = "gpio2"; - function = "normal"; - input-enable; - bias-pull-up; - power-source = <0>; - }; - }; - - irled { - irled_pwm: irled_pwm_default { - pins = "gpio6"; - function = "func1"; - qcom,drive-strength = <2>; - power-source = <0>; - bias-disable; - output-low; - }; - }; -}; - -&soc { - gpio_keys { - compatible = "gpio-keys"; - label = "gpio-keys"; - - pinctrl-names = "default"; - pinctrl-0 = <&key_vol_up_default>; - - vol_up { - label = "volume_up"; - gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; - linux,input-type = <1>; - linux,code = ; - linux,can-disable; - debounce-interval = <15>; - gpio-key,wakeup; - }; - }; - - mtp_batterydata: qcom,battery-data { - qcom,batt-id-range-pct = <15>; - #include "qg-batterydata-alium-3600mah.dtsi" - #include "qg-batterydata-mlp356477-2800mah.dtsi" - }; -}; - -&pm6150l_wled { - qcom,string-cfg= <3>; - qcom,leds-per-string = <7>; - status = "ok"; -}; - -&pm6150l_lcdb { - status = "ok"; -}; - -&pm6150l_pwm_1 { - status = "okay"; -}; - -&pm6150_qg { - qcom,battery-data = <&mtp_batterydata>; - qcom,qg-iterm-ma = <100>; - qcom,hold-soc-while-full; - qcom,linearize-soc; - qcom,cl-feedback-on; -}; - -&pm6150_charger { - io-channels = <&pm6150_vadc ADC_USB_IN_V_16>, - <&pm6150_vadc ADC_USB_IN_I>, - <&pm6150_vadc ADC_CHG_TEMP>, - <&pm6150_vadc ADC_DIE_TEMP>, - <&pm6150_vadc ADC_AMUX_THM4_PU2>, - <&pm6150_vadc ADC_SBUx>, - <&pm6150_vadc ADC_VPH_PWR>; - io-channel-names = "usb_in_voltage", - "usb_in_current", - "chg_temp", - "die_temp", - "conn_temp", - "sbux_res", - "vph_voltage"; - qcom,battery-data = <&mtp_batterydata>; - qcom,auto-recharge-soc = <98>; - qcom,step-charging-enable; - qcom,sw-jeita-enable; - qcom,fcc-stepping-enable; - qcom,suspend-input-on-debug-batt; - qcom,sec-charger-config = <3>; - qcom,thermal-mitigation = <4200000 3500000 3000000 - 2500000 2000000 1500000 1000000 500000>; - dpdm-supply = <&qusb_phy0>; - qcom,charger-temp-max = <800>; - qcom,smb-temp-max = <800>; -}; - -&smb1390 { - /delete-property/ interrupts; - interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&smb_stat_default>; - status = "ok"; -}; - -&smb1390_charger { - /delete-property/ compatible; - compatible = "qcom,smb1390-charger-psy"; - io-channels = <&pm6150_vadc ADC_AMUX_THM3>; - io-channel-names = "cp_die_temp"; - status = "ok"; -}; - -&sdhc_1 { - vdd-supply = <&pm6150l_l11>; - qcom,vdd-voltage-level = <2950000 2950000>; - qcom,vdd-current-level = <0 570000>; - - vdd-io-supply = <&pm6150_l12>; - qcom,vdd-io-always-on; - qcom,vdd-io-lpm-sup; - qcom,vdd-io-voltage-level = <1800000 1800000>; - qcom,vdd-io-current-level = <0 325000>; - - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; - pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; - - status = "ok"; -}; - -&sdhc_2 { - vdd-supply = <&pm6150l_l9>; - qcom,vdd-voltage-level = <2950000 2950000>; - qcom,vdd-current-level = <0 800000>; - - vdd-io-supply = <&pm6150l_l6>; - qcom,vdd-io-voltage-level = <1800000 3100000>; - qcom,vdd-io-current-level = <0 22000>; - - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; - pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; - - cd-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>; - - status = "ok"; -}; - -&pil_camera_mem { - reg = <0 0x8f800000 0 0x500000>; -}; - -&pil_modem_mem { - reg = <0 0x8fd00000 0 0x3100000>; -}; - -&pil_video_mem { - reg = <0 0x92e00000 0 0x500000>; -}; - -&wlan_msa_mem { - reg = <0 0x93300000 0 0x200000>; -}; - -&pil_cdsp_mem { - reg = <0 0x93500000 0 0x1e00000>; -}; - -&pil_adsp_mem { - reg = <0 0x95300000 0 0x1e00000>; -}; - -&pil_ipa_fw_mem { - reg = <0 0x97100000 0 0x10000>; -}; - -&pil_ipa_gsi_mem { - reg = <0 0x97110000 0 0x5000>; -}; - -&pil_gpu_mem { - reg = <0 0x97115000 0 0x2000>; -}; - -&L16A { - regulator-max-microvolt = <3304000>; -}; - -&L19A { - regulator-max-microvolt = <3304000>; -}; - -&L4C { - regulator-max-microvolt = <2912000>; -}; - -&L5C { - regulator-max-microvolt = <2912000>; -}; - -&sde_dp { - status="disabled"; -}; - -&mdss_dp_pll { - status="disabled"; -}; - -&mdss_mdp { - connectors = <&sde_rscc &sde_wb &sde_dsi>; -}; - -&qupv3_se1_i2c { - status = "ok"; - lt9611: lt,lt9611@3b { - compatible = "lt,lt9611"; - reg = <0x3b>; - interrupt-parent = <&tlmm>; - interrupts = <26 0>; - interrupt-names = "lt_irq"; - lt,irq-gpio = <&tlmm 26 0x0>; - lt,reset-gpio = <&tlmm 20 0x0>; - lt,hdmi-en-gpio = <&tlmm 79 0x0>; - instance_id = <0>; - lt,non-pluggable; - lt,preferred-mode = "1920x1080"; - - pinctrl-names = "default"; - pinctrl-0 = <<9611_pins>; - - vdd-supply = <&pm6150_l13>; - vcc-supply = <&pm6150_l16>; - - lt,supply-entries { - #address-cells = <1>; - #size-cells = <0>; - - lt,supply-entry@0 { - reg = <0>; - lt,supply-name = "vdd"; - lt,supply-min-voltage = <1800000>; - lt,supply-max-voltage = <1800000>; - lt,supply-enable-load = <200000>; - lt,supply-post-on-sleep = <50>; - }; - lt,supply-entry@1 { - reg = <1>; - lt,supply-name = "vcc"; - lt,supply-min-voltage = <3304000>; - lt,supply-max-voltage = <3304000>; - lt,supply-enable-load = <200000>; - lt,supply-post-on-sleep = <50>; - }; - - - }; - - lt,customize-modes { - lt,customize-mode-id@0 { - lt,mode-h-active = <1920>; - lt,mode-h-front-porch = <88>; - lt,mode-h-pulse-width = <44>; - lt,mode-h-back-porch = <148>; - lt,mode-h-active-high; - lt,mode-v-active = <1080>; - lt,mode-v-front-porch = <4>; - lt,mode-v-pulse-width = <5>; - lt,mode-v-back-porch = <36>; - lt,mode-v-active-high; - lt,mode-refresh-rate = <60>; - lt,mode-clock-in-khz = <148500>; - }; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - lt9611_in: endpoint { - remote-endpoint = <&ext_dsi_out>; - }; - }; - }; - }; -}; - -&dsi_ext_bridge_hdmi_1080p { - qcom,mdss-dsi-ext-bridge = <0>; -}; - -&soc { - ext_dsi_bridge_display: qcom,dsi-display@50 { - label = "ext_dsi_bridge_display hdmi 1080p"; - qcom,dsi-display-active; - qcom,display-type = "primary"; - - qcom,dsi-ctrl-num = <0>; - qcom,dsi-phy-num = <0>; - qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; - qcom,dsi-panel = <&dsi_ext_bridge_hdmi_1080p>; - }; -}; - -&sde_dsi { - qcom,dsi-display-list = <&ext_dsi_bridge_display>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - ext_dsi_out: endpoint { - remote-endpoint = <<9611_in>; - }; - }; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs610-iot.dts b/arch/arm64/boot/dts/qcom/qcs610-iot.dts index a0a6c723d17254bcc2a238191dd7654b22ef4e24..9d79b8ceea0ae8b22040772fd5e954f291fcd751 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-iot.dts +++ b/arch/arm64/boot/dts/qcom/qcs610-iot.dts @@ -13,7 +13,6 @@ /dts-v1/; #include "qcs610.dtsi" #include "qcs610-iot.dtsi" -#include "sm6150-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS610 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi index 733d9335b4fd519328e815f31a71a7bd46a57cf2..3397b23ca9ba2ec65cfaf94c2f334068278c4bbb 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi @@ -25,6 +25,7 @@ #include "sm6150-sde-pll.dtsi" #include "sm6150-sde-display.dtsi" #include "qcs610-camera-sensor-idp.dtsi" +#include "sm6150-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS610 IOT"; @@ -324,6 +325,10 @@ reg = <0 0x97115000 0 0x2000>; }; +&msm_gpu { + /delete-node/qcom,gpu-mempools; +}; + &sdhc_1 { vdd-supply = <&pm6150l_l11>; qcom,vdd-voltage-level = <2950000 2950000>; @@ -360,6 +365,12 @@ status = "ok"; }; +&usb0 { + dwc3@a600000 { + snps,usb3-u1u2-disable; + }; +}; + &L16A { regulator-max-microvolt = <3304000>; }; diff --git a/arch/arm64/boot/dts/qcom/qcs610-ipc.dts b/arch/arm64/boot/dts/qcom/qcs610-ipc.dts index aa9b6439e0b3c806ef2afbdf004f8d9aa4715fbc..cb0b1a23bfa6c2278ab077b43785d0f0d2b953ba 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-ipc.dts +++ b/arch/arm64/boot/dts/qcom/qcs610-ipc.dts @@ -13,7 +13,6 @@ /dts-v1/; #include "qcs610.dtsi" -#include "qcs610-iot.dtsi" #include "qcs610-ipc.dtsi" / { @@ -21,7 +20,3 @@ compatible = "qcom,qcs610-iot", "qcom,qcs610", "qcom,iot"; qcom,board-id = <32 1>; }; - -&sm6150_snd { - /delete-property/ fsa4480-i2c-handle; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs610-ipc.dtsi b/arch/arm64/boot/dts/qcom/qcs610-ipc.dtsi index 87c198d211ec41377590eced844a83f5216c8626..934e4a7f95f1c8e4ed9d8e457c9e8a363addad04 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-ipc.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs610-ipc.dtsi @@ -10,8 +10,8 @@ * GNU General Public License for more details. */ -#include "sm6150-audio-overlay.dtsi" -#include "sm6150-camera-sensor-idp.dtsi" +#include "qcs610-iot.dtsi" + / { model = "Qualcomm Technologies, Inc. QCS610 IPC"; compatible = "qcom,qcs610-iot", "qcom,qcs610", "qcom,iot"; @@ -67,31 +67,19 @@ qcom,wsa-max-devs = <1>; qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; + qcom,linein-det-swh = <1>; + qcom,lineout-det-swh = <1>; + qcom,linein-det-gpio = <&tlmm 1 0>; + qcom,lineout-det-gpio = <&tlmm 60 0>; + pinctrl-names = "default"; + pinctrl-0 = <&jack_det_linein_default + &jack_det_lineout_default>; }; &pm6150_charger { qcom,batteryless-platform; }; -&eeprom_rear { - cam_vana-supply = <&pm6150l_l4>; - rgltr-min-voltage = <1800000 2900000 1200000 0 2800000>; - rgltr-max-voltage = <1800000 2900000 1200000 0 2800000>; -}; - -&cam_cci { - qcom,cam-sensor@0 { - cam_vana-supply = <&pm6150l_l4>; - rgltr-min-voltage = <1800000 2900000 1200000 0>; - rgltr-max-voltage = <1800000 2900000 1200000 0>; - }; -}; - - -&led_flash_front { - status = "disabled"; -}; - &tlmm { led_red_default: led_red_default { mux { diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts deleted file mode 100644 index 2830ca6cfde8d553c963704f6ebe7fa2f908ebfd..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include -#include -#include "qcs6125-iot-idp.dtsi" -#include "trinket-audio-overlay.dtsi" - -/ { - model = "Display Port Enable IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,msm-id = <468 0x10000>; - qcom,board-id = <34 4>; -}; - -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; - -&sde_dp { - status = "ok"; - qcom,dp-hpd-gpio = <&tlmm 100 0>; - qcom,dp-low-power-hw-hpd; -}; - -&mdss_dp_pll { - status = "ok"; -}; - -&usb0 { - dwc3@4e00000 { - usb-phy = <&qusb_phy0>, <&usb_nop_phy>; - maximum-speed = "high-speed"; - }; -}; - -&mdss_mdp { - connectors = <&sde_wb &sde_dsi &sde_dp>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts deleted file mode 100644 index 69bf2c2be9d88d8216be395924fbc073688b8e70..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcs6125.dtsi" -#include "qcs6125-iot-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCM6125 IOT Disp. Port Enable IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,board-id = <34 4>; -}; - -&sde_dp { - status = "ok"; - qcom,dp-hpd-gpio = <&tlmm 100 0>; - qcom,dp-low-power-hw-hpd; -}; - -&mdss_dp_pll { - status = "ok"; -}; - -&usb0 { - dwc3@4e00000 { - usb-phy = <&qusb_phy0>, <&usb_nop_phy>; - maximum-speed = "high-speed"; - }; -}; - -&mdss_mdp { - connectors = <&sde_wb &sde_dsi &sde_dp>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts deleted file mode 100644 index d5c75339ba9d4648ece66f54c0ba144e6c9ef388..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include - -#include "qcs6125-iot-idp.dtsi" -#include "trinket-tasha-codec-audio-overlay.dtsi" -#include "trinket-tasha-codec.dtsi" - -/ { - model = "Ext Audio Codec IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,msm-id = <468 0x10000>; - qcom,board-id = <34 1>; -}; - -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts deleted file mode 100644 index 7d75678fd29a1cc0ffc1178328e47a89e25e1079..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcs6125.dtsi" -#include "qcs6125-iot-idp.dtsi" -#include "trinket-tasha-codec-audio-overlay.dtsi" -#include "trinket-tasha-codec.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCS6125 IOT Ext Audio Codec IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,board-id = <34 1>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-idp-overlay.dts deleted file mode 100644 index 8b80605046e5aed9fe5e78511c36e382319bd5c6..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-idp-overlay.dts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include "qcs6125-iot-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCS6125 IOT IDP Overlay"; - compatible = "qcom,qcs6125"; - qcom,msm-id = <468 0x10000>; - qcom,board-id = <34 0>; -}; - diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-idp.dts deleted file mode 100644 index 4eaa9b6ccccba3e9c4e58d7537e8434ae728ed8f..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-idp.dts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcs6125.dtsi" -#include "qcs6125-iot-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCS6125 IOT IDP SoC"; - compatible = "qcom,qcs6125"; - qcom,board-id = <34 0>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-idp.dtsi b/arch/arm64/boot/dts/qcom/qcs6125-iot-idp.dtsi deleted file mode 100644 index 6d198b235fbc228456a2d965ddb01901d588bb65..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-idp.dtsi +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include "trinket-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts deleted file mode 100644 index 8fb605f7dac8e01411abb9d24b071bd81396ab86..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include - -#include "qcs6125-iot-idp.dtsi" - -/ { - model = "USB-C Ext Audio Codec IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,msm-id = <468 0x10000>; - qcom,board-id = <34 3>; -}; - -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts deleted file mode 100644 index 3428c7b93bc452053e34ea1bd89aeb61c41f610f..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; -/plugin/; - -#include - -#include "qcs6125-iot-idp.dtsi" -#include "qcs6125-iot-usbc-idp.dtsi" - -/ { - model = "USBC Audio IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,msm-id = <468 0x10000>; - qcom,board-id = <34 2>; -}; - -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts deleted file mode 100644 index a33a34046fdcf189395b81acd843174005e829c0..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcs6125.dtsi" -#include "qcs6125-iot-idp.dtsi" -#include "qcs6125-iot-usbc-idp.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCS6125 IOT USBC Audio IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,board-id = <34 2>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi deleted file mode 100644 index faafcf82f5e3ce0aac93a47d06e5c3ae907aabe9..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "trinket-audio-overlay.dtsi" - -&sm6150_snd { - qcom,msm-mbhc-usbc-audio-supported = <1>; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <1>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125.dts b/arch/arm64/boot/dts/qcom/qcs6125.dts deleted file mode 100644 index c2ac4473ee4b9983e0f80eed0f48493405855779..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125.dts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/dts-v1/; - -#include "qcs6125.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCS6125 SoC"; - compatible = "qcom,qcs6125"; - qcom,board-id = <0 0>; -}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125.dtsi b/arch/arm64/boot/dts/qcom/qcs6125.dtsi deleted file mode 100644 index aed91a65501948d640b5dbf777efe439f2f37aca..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/qcs6125.dtsi +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "trinket.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. QCS6125"; - compatible = "qcom,qcs6125"; - qcom,msm-id = <468 0x0>; - qcom,msm-name = "QCS6125"; -}; diff --git a/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi b/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi index e74e61844d3f8938f6c58ece2387520b97e14a6e..5c5abef195ae8f54c71b926d230a6bd2168d1ee3 100644 --- a/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi +++ b/arch/arm64/boot/dts/qcom/quin-vm-common.dtsi @@ -58,23 +58,37 @@ firmware: firmware { android { compatible = "android,firmware"; + boot_devices = "vdevs/1c140000.virtio_blk,vdevs/1c0b0000.virtio_blk,vdevs/1c0f0000.virtio_blk"; + vbmeta { compatible = "android,vbmeta"; - parts = "vbmeta,boot,system,vendor,dtbo"; + parts = "vbmeta,la_system,la_vendor"; }; + fstab { compatible = "android,fstab"; + vendor { compatible = "android,vendor"; - dev="/dev/block/platform/vdevs/1c0f0000.virtio_blk/vdc"; + dev="/dev/block/platform/vdevs/1c0f0000.virtio_blk/la_vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,avb"; status = "ok"; }; }; }; }; + + rename_blk: rename_blk { + compatible = "qcom,blkdev-rename"; + actual-dev = "vda", "vdb", "vdc", + "vdd", "vde", "vdf", + "vdg", "vdh"; + rename-dev = "la_system", "la_userdata", "la_vendor", + "la_persist", "modem", "bluetooth", + "la_misc", "vbmeta"; + }; }; &soc { @@ -120,6 +134,11 @@ memory-region = <&qseecom_ta_mem>; qcom,ion-heap-type = "DMA"; }; + + qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; }; hab: qcom,hab { diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts index 3ebad18c83404a486093b4d7013334397cd8747e..4f84d3aa500d2bad1b614d8298303d373325357b 100644 --- a/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts @@ -36,3 +36,78 @@ &blsp1_uart4_hs { status = "disabled"; }; + +&wlan_fw_mem { + reg = <0x0 0x86400000 0x0 0x100000>; +}; + +&qseecom_mem { + size = <0 0x400000>; +}; + +&soc { + /delete-node/ qcom,wlan_dsp@7000000; + /delete-node/ qcom,icnss@18800000; +}; + +&reserved_mem { + /delete-node/ wlan_msa_region@88E0000; + /delete-node/ wlan_fw_mem@86400000; +}; + +&tlmm { + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; + bias-pull-down; + }; + }; +}; + +&sdx_ext_ipc { + qcom,wakeup-gpio-out = <&tlmm 77 0x00>; +}; + +ðqos_hw { + rxc-skew-ps = <720>; + io-macro-info { + rx-prog-swap; + rx-dll-bypass; + }; +}; + +&tlmm { + /delete-node/ mdss_hdmi_ddc_active; + /delete-node/ mdss_hdmi_ddc_suspend; + rgmii_level_shifter: rgmii_level_shifter { + mux { + pins = "gpio16"; + function = "gpio"; + }; + config { + pins = "gpio16"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; +}; + +ðqos_hw { + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state", + "dev-emac-rgmii_lvl_shift_state"; + pinctrl-16 = <&rgmii_level_shifter>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi index fe397be6067b313dfddac5a01cc602d293b47e4d..882275bc970d0597a008a464553002c24c84b233 100644 --- a/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi @@ -24,6 +24,19 @@ output-high; }; }; + + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; &pcie0_perst_default { @@ -166,6 +179,14 @@ }; }; }; + + sdx_ext_ipc: qcom,sdx_ext_ipc { + compatible = "qcom,sdx-ext-ipc"; + qcom,wakeup-gpio-in = <&tlmm 14 0x00>; + qcom,wakeup-gpio-out = <&tlmm 79 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + }; }; &thermal_zones { @@ -249,22 +270,6 @@ status = "ok"; }; -&gpu_bw_tbl { - status = "disabled"; -}; - -&gpubw { - status = "disabled"; -}; - -&msm_gpu { - status = "disabled"; -}; - -&kgsl_msm_iommu { - status = "disabled"; -}; - &rpm_bus { rpm-regulator-ldoa1 { status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts index a6183bd11c49470b26614a3681963f4d18a1f4f5..3f9b8b2428e7b5a0b7982330ee44113fbe24c3f2 100644 --- a/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts @@ -104,3 +104,84 @@ &blsp1_uart4_hs { status = "disabled"; }; + +&wlan_fw_mem { + reg = <0x0 0x86400000 0x0 0x100000>; +}; + +&reserved_mem { + linux,cma { + size = <0 0x400000>; + }; +}; + +&qseecom_mem { + size = <0 0x400000>; +}; + +&soc { + /delete-node/ qcom,wlan_dsp@7000000; + /delete-node/ qcom,icnss@18800000; +}; + +&reserved_mem { + /delete-node/ wlan_msa_region@88E0000; + /delete-node/ wlan_fw_mem@86400000; +}; + +&tlmm { + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; + bias-pull-down; + }; + }; +}; + +&sdx_ext_ipc { + qcom,wakeup-gpio-out = <&tlmm 77 0x00>; +}; + +ðqos_hw { + rxc-skew-ps = <720>; + io-macro-info { + rx-prog-swap; + rx-dll-bypass; + }; +}; + +&tlmm { + /delete-node/ mdss_hdmi_ddc_active; + /delete-node/ mdss_hdmi_ddc_suspend; + rgmii_level_shifter: rgmii_level_shifter { + mux { + pins = "gpio16"; + function = "gpio"; + }; + config { + pins = "gpio16"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; +}; + +ðqos_hw { + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state", + "dev-emac-rgmii_lvl_shift_state"; + pinctrl-16 = <&rgmii_level_shifter>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi index 8b352bad0fcdb7e5e0e7e23c8a9ee0b4af176ed4..5988b66988b784f50bcdde0fb85e5460ccfbc9cb 100644 --- a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi @@ -188,7 +188,6 @@ pinctrl-names = "default"; pinctrl-0 = <&wakeup_gpio_default>; }; - }; &thermal_zones { @@ -214,11 +213,39 @@ extcon = <&usb2_extcon>; }; +&mtl_rx_setup { + queue2 { + snps,dcb-algorithm; + }; + + queue3 { + snps,dcb-algorithm; + }; +}; + +&mtl_tx_setup { + queue2 { + snps,dcb-algorithm; + }; + + queue3 { + snps,dcb-algorithm; + }; +}; + ðqos_hw { status = "okay"; vreg_emac_phy-supply = <&vreg_emac_phy>; vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; rxc-skew-ps = <0>; + qcom,qoe_mode = <1>; + qcom,qoe-queue = <2>; + qcom,qoe-vlan-offset = <0>; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + qcom,cv2x_mode = <2>; + qcom,cv2x-queue = <3>; + qcom,cv2x-vlan-offset = <1>; pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", @@ -272,22 +299,6 @@ status = "ok"; }; -&gpu_bw_tbl { - status = "disabled"; -}; - -&gpubw { - status = "disabled"; -}; - -&msm_gpu { - status = "disabled"; -}; - -&kgsl_msm_iommu { - status = "disabled"; -}; - &rpm_bus { rpm-regulator-ldoa1 { status = "disabled"; @@ -318,3 +329,20 @@ }; }; +&pms405_vadc { + pa_therm1 { + /delete-property/ qcom,ratiometric; + /delete-property/ qcom,hw-settle-time; + label = "pa_therm1"; + reg = ; + qcom,pre-scaling = <1 1>; + }; + + pa_therm3 { + /delete-property/ qcom,ratiometric; + /delete-property/ qcom,hw-settle-time; + label = "pa_therm3"; + reg = ; + qcom,pre-scaling = <1 1>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts index 67e23a084989f13cbd5bc70ae16113e7d612053c..f00de0ec211099424b71ad8ee299bca561827ace 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts @@ -41,3 +41,47 @@ &usb { qcom,smmu-s1-bypass; }; + +&sdx_ext_ipc { + compatible = "qcom,sa515m-ccard"; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; + qcom,wakeup-gpio-in = <&tlmm 77 0x00>; + qcom,wakeup-gpio-out = <&tlmm 96 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + qcom,default-policy-nop; + status = "okay"; +}; + +&mtl_rx_setup { + queue2 { + snps,dcb-algorithm; + }; + + queue3 { + snps,dcb-algorithm; + }; +}; + +&mtl_tx_setup { + queue2 { + snps,dcb-algorithm; + }; + + queue3 { + snps,dcb-algorithm; + }; +}; + +ðqos_hw { + qcom,qoe_mode = <1>; + qcom,qoe-queue = <2>; + qcom,qoe-vlan-offset = <0>; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + qcom,cv2x_mode = <1>; + qcom,cv2x-queue = <3>; + qcom,cv2x-vlan-offset = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts index 81786435e82ce1f9469870424e14fb461d6b0ea0..ff3f04b02f6777c8473e7d4c2b374a8bce02be03 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-pcie-ep.dts @@ -73,6 +73,10 @@ }; &sdx_ext_ipc { + compatible = "qcom,sa515m-ccard"; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; qcom,default-policy-nop; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts index 1053f3273f3135329e4546c649a5c51fb25c7dc0..7bd2e445adf7c42ea35982af614faf3573dfc38d 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-usb-ep.dts @@ -56,3 +56,16 @@ &usb { qcom,num-gsi-evt-buffs = <0x5>; }; + +&sdx_ext_ipc { + compatible = "qcom,sa515m-ccard"; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; + qcom,wakeup-gpio-in = <&tlmm 77 0x00>; + qcom,wakeup-gpio-out = <&tlmm 96 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + qcom,default-policy-nop; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi index 69f4da650cecc6d253cefac0aa718b243e99912e..251b24cce5f1ad1b72427adc6fc1144ed3d303d6 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi @@ -51,7 +51,9 @@ <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_sec_tdm_rx_1>, <&dai_sec_tdm_tx_1>, <&dai_sec_auxpcm>, <&incall2_record_rx>, <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", @@ -63,7 +65,9 @@ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36866", "msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36882", "msm-dai-q6-tdm.36883", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; @@ -78,6 +82,15 @@ gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; status = "okay"; }; + + qmi-tmd-devices { + modem { + modem_v2x: modem_v2x { + qcom,qmi-dev-name = "modem_v2x"; + #cooling-cells = <2>; + }; + }; + }; }; &mpss_adsp_mem { @@ -97,6 +110,71 @@ /delete-node/ pm8150b-bcl-lvl1; /delete-node/ pm8150b-bcl-lvl2; /delete-node/ soc; + + /* update Tj thresholds */ + mdm-core-0-step { + trips { + active-config0 { + temperature = <95000>; + hysteresis = <5000>; + }; + + active-config1 { + temperature = <100000>; + hysteresis = <5000>; + }; + + active-config2 { + temperature = <105000>; + hysteresis = <5000>; + }; + }; + }; + + mdm-core-0-v2x-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + tj_v2x_config0: active-config0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config1: active-config1 { + temperature = <110000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config2: active-config2 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj0_v2x_cdev { + trip = <&tj_v2x_config0>; + cooling-device = <&modem_v2x 1 1>; + }; + + modem_tj1_v2x_cdev { + trip = <&tj_v2x_config1>; + cooling-device = <&modem_v2x 2 2>; + }; + + modem_tj2_v2x_cdev { + trip = <&tj_v2x_config2>; + cooling-device = <&modem_v2x 3 3>; + }; + }; + }; }; &usb { @@ -565,3 +643,17 @@ }; }; }; + +&tlmm { + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio96"; + function = "gpio"; + }; + config { + pins = "gpio96"; + drive-strength = <2>; + bias-pull-down; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi b/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi index 9b3b3cf860d5b8dea95b10b9ba3aec96a349564f..3445ca95d43aa2f761aeeb5049b5203b3fface97 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi @@ -19,3 +19,81 @@ &pil_modem { qcom,auto-boot; }; + +&soc { + qmi-tmd-devices { + modem { + modem_v2x: modem_v2x { + qcom,qmi-dev-name = "modem_v2x"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + /* update Tj thresholds */ + mdm-core-0-step { + trips { + active-config0 { + temperature = <95000>; + hysteresis = <5000>; + }; + + active-config1 { + temperature = <100000>; + hysteresis = <5000>; + }; + + active-config2 { + temperature = <105000>; + hysteresis = <5000>; + }; + }; + }; + + mdm-core-0-v2x-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + tj_v2x_config0: active-config0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config1: active-config1 { + temperature = <110000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config2: active-config2 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj0_v2x_cdev { + trip = <&tj_v2x_config0>; + cooling-device = <&modem_v2x 1 1>; + }; + + modem_tj1_v2x_cdev { + trip = <&tj_v2x_config1>; + cooling-device = <&modem_v2x 2 2>; + }; + + modem_tj2_v2x_cdev { + trip = <&tj_v2x_config2>; + cooling-device = <&modem_v2x 3 3>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts index 9eeb1c42076f54e505ca4c9553fe0618c0abed5c..3b27467715581038c6b271cb6853211e4929b0a2 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts @@ -41,3 +41,47 @@ &usb { qcom,smmu-s1-bypass; }; + +&sdx_ext_ipc { + compatible = "qcom,sa515m-ccard"; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; + qcom,wakeup-gpio-in = <&tlmm 77 0x00>; + qcom,wakeup-gpio-out = <&tlmm 96 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + qcom,default-policy-nop; + status = "okay"; +}; + +&mtl_rx_setup { + queue2 { + snps,dcb-algorithm; + }; + + queue3 { + snps,dcb-algorithm; + }; +}; + +&mtl_tx_setup { + queue2 { + snps,dcb-algorithm; + }; + + queue3 { + snps,dcb-algorithm; + }; +}; + +ðqos_hw { + qcom,qoe_mode = <1>; + qcom,qoe-queue = <2>; + qcom,qoe-vlan-offset = <0>; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + qcom,cv2x_mode = <1>; + qcom,cv2x-queue = <3>; + qcom,cv2x-vlan-offset = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts index ebeac7624478a048f820dd3e12bf1a67f92ea9b5..3b49920ff05c5f505d8cfc5ae0168bbd2fb2361b 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts @@ -74,9 +74,10 @@ }; &sdx_ext_ipc { - compatible = "qcom,sa515m-ccard"; - qcom,status-in-gpio = <&tlmm 76 0x00>; - qcom,status-out-gpio = <&tlmm 33 0x00>; - qcom,status-out2-gpio = <&tlmm 31 0x00>; - status = "okay"; + compatible = "qcom,sa515m-ccard"; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; + qcom,default-policy-nop; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-usb-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-usb-ep.dts index 9734f0b88ab4b0d41780378c6d8d60b21eaf7f89..fe78525bc0625f51933d98d22d8e0d10d9635079 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-usb-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-usb-ep.dts @@ -56,3 +56,16 @@ &usb { qcom,num-gsi-evt-buffs = <0x5>; }; + +&sdx_ext_ipc { + compatible = "qcom,sa515m-ccard"; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; + qcom,wakeup-gpio-in = <&tlmm 77 0x00>; + qcom,wakeup-gpio-out = <&tlmm 96 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + qcom,default-policy-nop; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi index cd13e45e4145c6b8916eda4a4548bb64b285faef..b8547fbf19c9e3a8526573d22307b089a0bbeebb 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi @@ -17,6 +17,17 @@ reg = <0x90800000 0xf800000>; }; +&soc { + qmi-tmd-devices { + modem { + modem_v2x: modem_v2x { + qcom,qmi-dev-name = "modem_v2x"; + #cooling-cells = <2>; + }; + }; + }; +}; + /* delete pm8150b nodes */ &thermal_zones { /delete-node/ pm8150b-wp-therm; @@ -30,6 +41,71 @@ /delete-node/ pm8150b-bcl-lvl1; /delete-node/ pm8150b-bcl-lvl2; /delete-node/ soc; + + /* update Tj thresholds */ + mdm-core-0-step { + trips { + active-config0 { + temperature = <95000>; + hysteresis = <5000>; + }; + + active-config1 { + temperature = <100000>; + hysteresis = <5000>; + }; + + active-config2 { + temperature = <105000>; + hysteresis = <5000>; + }; + }; + }; + + mdm-core-0-v2x-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + tj_v2x_config0: active-config0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config1: active-config1 { + temperature = <110000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config2: active-config2 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj0_v2x_cdev { + trip = <&tj_v2x_config0>; + cooling-device = <&modem_v2x 1 1>; + }; + + modem_tj1_v2x_cdev { + trip = <&tj_v2x_config1>; + cooling-device = <&modem_v2x 2 2>; + }; + + modem_tj2_v2x_cdev { + trip = <&tj_v2x_config2>; + cooling-device = <&modem_v2x 3 3>; + }; + }; + }; }; &usb { diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi index 4b73b902333b6a63e1baa154bdbcc235ab8eced1..3f9013f63bd8ec9a82fee275f842e30ca838c9dd 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi @@ -13,6 +13,10 @@ #include #include "sa6155-cnss.dtsi" +&qupv3_2 { + status = "ok"; +}; + &bluetooth_ext { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi index 1ecae102b065c83a33f3c589d64068bef8c098ec..ab3647ea3828b9d721fefaa70821cb733f29be0a 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -13,6 +13,10 @@ #include #include "sa6155-cnss.dtsi" +&qupv3_2 { + status = "ok"; +}; + &bluetooth_ext { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi index 137d946a946d935b665c5b81a85812203aee1d94..41c5448b182c6e2262eaedc7ebad35b58de877b3 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi @@ -313,7 +313,8 @@ sde_card1: qcom,sde-kms-lease@0 { compatible = "qcom,sde-kms-lease"; qcom,dev-name = "msm_drm"; - qcom,lease-connectors = "shared-disp-0","DP-1","DP-2","DP-3"; + qcom,lease-connectors = "shared-disp-0","DP-1","DP-2","DP-3", + "Virtual-1"; qcom,lease-planes = "plane-0","plane-1","plane-2","plane-3", "plane-4", "plane-5", "plane-6", "plane-7","plane-8","plane-9"; diff --git a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi index ccef59f575bcfac5e9a3724a692bf2044fb74370..7b54f7d59b81116899514c985b7e9fb23ae5c5df 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi @@ -338,6 +338,15 @@ pm6155-1-tz { cooling-maps { + /* + * trip0 cooling map is dummy node to enable + * passive polling on trip0 violation. + */ + trip0_cpu0 { + trip = <&pm6155_trip0>; + cooling-device = <&CPU0 0 0>; + }; + trip1_cpu0 { trip = <&pm6155_trip1>; cooling-device = diff --git a/arch/arm64/boot/dts/qcom/sa6155p-camera.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-camera.dtsi index 3eb01a1b915b5c67ddb1e0c8aeea1612838d9c4e..d9b3dd8a4490cbeabb8d82cc45a6097d99188be2 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-camera.dtsi @@ -46,6 +46,26 @@ status = "disabled"; }; +&cam_smmu { + msm_cam_smmu_ife_cp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x821 0x1C0>, + <&apps_smmu 0x841 0x0>, + <&apps_smmu 0x861 0x1C0>; + label = "ife-cp"; + qcom,secure-pixel-cb; + ife_cp_iova_mem_map: iova-mem-map { + /* IO region is approximately 2.5 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0x98C00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; +}; &soc { /delete-node/ cam_isp_mgr; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm-qupv3.dtsi index a3b8ff0bb9ef10edb948896ca1f51df558cdbffe..5b77a4412e493d4fb4fc996afc323808c8ea8a09 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm-qupv3.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -426,6 +426,7 @@ pinctrl-1 = <&qupv3_se9_spi_sleep>; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_2>; + qcom,disable-dma; status = "disabled"; }; @@ -445,6 +446,7 @@ pinctrl-1 = <&qupv3_se10_spi_sleep>; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_2>; + qcom,disable-dma; status = "disabled"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi index ef2dcb739f3538842b85798cde19e2b54f2ed6ba..b74f80add2900506fbc1c57c0571e2a305966349 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm-usb.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -58,6 +58,7 @@ 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,pm-qos-latency = <61>; + qcom,ignore-wakeup-src-in-hostmode; status = "disabled"; dwc3@a600000 { compatible = "snps,dwc3"; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi index 9f47fd1779eea86ebe59f1c937266d695c0245a4..a51e041d6ac68afa4920904989e5f31240848352 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi @@ -16,6 +16,10 @@ #include "sa8155-pmic-overlay.dtsi" #include "sa8155-cnss.dtsi" +&qupv3_3 { + status = "ok"; +}; + &qupv3_se0_spi { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi index 925a9c239c57ad87f33a2bd8454fd156f5e8cd6f..f9e38514f73298a80c55c54ebead6b4940c363e9 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi @@ -397,7 +397,7 @@ compatible = "qcom,sde-kms-lease"; qcom,dev-name = "msm_drm"; qcom,lease-connectors = "DSI-2", "shared-disp-0", - "DP-1", "DP-2", "DP-3"; + "DP-1", "DP-2", "DP-3", "Virtual-1"; qcom,lease-planes = "plane-0", "plane-1", "plane-2", "plane-3","plane-4", "plane-5", "plane-6","plane-7", "plane-8", diff --git a/arch/arm64/boot/dts/qcom/sa8155-camera.dtsi b/arch/arm64/boot/dts/qcom/sa8155-camera.dtsi index 2ded8cd4df2f3c649cf717a7afacb9f517bbbd9b..708cc284af93b8d843211b05cc10befa1b9338e1 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-camera.dtsi @@ -62,6 +62,31 @@ status = "disabled"; }; +&cam_smmu { + msm_cam_smmu_ife_cp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x841 0x620>, + <&apps_smmu 0x861 0x620>, + <&apps_smmu 0xA41 0x620>, + <&apps_smmu 0xA61 0x620>, + <&apps_smmu 0xC41 0x620>, + <&apps_smmu 0xC61 0x620>, + <&apps_smmu 0xE41 0x620>, + <&apps_smmu 0xE61 0x620>; + label = "ife-cp"; + qcom,secure-pixel-cb; + ife_cp_iova_mem_map: iova-mem-map { + /* IO region is approximately 2.5 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0x98C00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; +}; &soc { /delete-node/ cam_isp_mgr; diff --git a/arch/arm64/boot/dts/qcom/sa8155-capture.dtsi b/arch/arm64/boot/dts/qcom/sa8155-capture.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ce36343a5d8de93bd0e280e08335b63caa9662c0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-capture.dtsi @@ -0,0 +1,544 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "skeleton64.dtsi" +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + + model = "Qualcomm Technologies, Inc. SM8150"; + compatible = "qcom,sa8155"; + qcom,msm-name = "SM8150"; + interrupt-parent = <&intc>; + cpus { + #address-cells = <0x2>; + #size-cells = <0x0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + #cooling-cells = <0x2>; + + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <0x2>; + next-level-cache = <&L3_0>; + L3_0: l3-cache { + compatible = "arm,arch-cache"; + cache-level = <0x3>; + }; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + + L2_TLB_0: l2-tlb { + qcom,dump-size = <0x5000>; + }; + }; + }; + + soc: soc { } ; + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + }; + + aliases { + serial0 = "/soc/qcom,qup_uart@0xa90000"; + }; + + memory { + device_type = "memory"; + reg = <0x1 0x40000000 0x0 0x20000000>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; +}; + +#include "sm8150-gdsc.dtsi" + +&soc { + status = "ok"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges = <0x0 0x0 0x0 0xffffffff>; + compatible = "simple-bus"; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + interrupt-parent = <&intc>; + }; + + clock_gcc: qcom,gcc { + compatible = "qcom,gcc-sa8155-v2", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + #clock-cells = <0x1>; + #reset-cells = <0x1>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + timer@0x17c20000 { + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c20000 0x1000>; + clock-frequency = <0x124f800>; + frame@0x17c21000 { + frame-number = <0x0>; + interrupts = <0x0 0x8 0x4 0x0 0x6 0x4>; + reg = <0x17c21000 0x1000 0x17c22000 0x1000>; + }; + }; + + wdog: qcom,wdt@17c10000 { + compatible = "qcom,msm-watchdog"; + reg = <0x17c10000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 0 0>, <0 1 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + qcom,scandump-sizes = <0x10100 0x10100 0x10100 0x10100 + 0x18100 0x18100 0x18100 0x18100>; + }; + + apps_rsc: mailbox@18220000 { + compatible = "qcom,tcs-drv"; + status="ok"; + label = "apps_rsc"; + reg = <0x18220000 0x100>, <0x18220d00 0x3000>; + interrupts = <0 5 0>; + #mbox-cells = <1>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + }; + + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sm8150"; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + #clock-cells = <1>; + }; + + disp_rsc: mailbox@af20000 { + compatible = "qcom,tcs-drv"; + label = "display_rsc"; + reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>; + interrupts = <0 129 0>; + #mbox-cells = <1>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + status = "disabled"; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + reg = <0xc300000 0x1000>, <0x17c0000C 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x1>; + interrupts = ; + + label = "aop"; + qcom,early-boot; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + cmd_db: qcom,cmd-db@c3f000c { + compatible = "qcom,cmd-db"; + reg = <0xc3f000c 8>; + }; + + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x603 0x0>; + }; + + }; + /* 2-wire UART */ + + /* Debug UART Instance for CDP/MTP platform */ + qupv3_se12_2uart: qcom,qup_uart@0xa90000 { + compatible = "qcom,msm-geni-console"; + reg = <0xa90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_2uart_active>; + pinctrl-1 = <&qupv3_se12_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "ok"; + }; + + apps_smmu: apps-smmu@0x15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x100000>, + <0x15182000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,disable-atos; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + ufs_ice: ufsice@1d90000 { + compatible = "qcom,ice"; + reg = <0x1d90000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_phy_gdsc>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + compatible = "qcom,ufs-phy-qmp-v4"; + reg = <0x1d87000 0xda8>; /* PHY regs */ + reg-names = "phy_mem"; + #phy-cells = <0>; + ufs-qcom-crypto = <&ufs_ice>; + + lanes-per-direction = <2>; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_PHY_AUX_CLK>; + + vdda-pll-supply = <&pm8150_2_l8>; + vdda-phy-max-microamp = <87100>; + vdda-pll-max-microamp = <18300>; + vdda-phy-supply = <&pm8150_1_l5>; + + status = "ok"; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x2500>; + interrupts = <0 265 0>; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; + + lanes-per-direction = <2>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + clocks = + <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + freq-table-hz = + <37500000 300000000>, + <0 0>, + <0 0>, + <37500000 300000000>, + <37500000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <26>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G1 L2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G2 L2 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G3 L2 */ + <123 512 14752 0>, <1 757 1000 0>, /* PWM G4 L2 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G4 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G1 RA L2 */ + <123 512 511181 0>, <1 757 1000 0>, /* HS G2 RA L2 */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */ + <123 512 8388608 0>, <1 757 409600 0>, /* HS G4 RA L2 */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G4 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */ + <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */ + /* As UFS working in HS G3 RB L2 mode, aggregated + * bandwidth (AB) should take care of providing + * optimum throughput requested. However, as tested, + * in order to scale up CNOC clock, instantaneous + * bindwidth (IB) needs to be given a proper value too. + */ + <123 512 4194304 0>, <1 757 204800 409600>, /* HS G3 RB L2 */ + <123 512 8388608 0>, <1 757 409600 409600>, /* HS G4 RB L2 */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", "HS_RA_G4_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", "HS_RA_G4_L2", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", "HS_RB_G4_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", "HS_RB_G4_L2", + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cpu-group-latency-us = <44 44>; + qcom,pm-qos-default-cpu = <0>; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&clock_gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_1_l10>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8150_1_s4>; + vcc-max-microamp = <750000>; + vccq2-max-microamp = <750000>; + + qcom,vddp-ref-clk-supply = <&pm8150_2_l5>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; + }; + +}; + +&apps_smmu { + qcom,actlr = + /* HF0 and HF1 TBUs: +3 deep PF */ + <0x800 0x7ff 0x103>, + + /* SF TBU: +3 deep PF */ + <0x2000 0x3ff 0x103>, + + /* NPU SIDs: +15 deep PF */ + <0x1480 0x3 0x303>, + <0x1484 0x1 0x303>, + <0x1080 0x3 0x303>, + <0x1084 0x1 0x303>; +}; + +&ufs_phy_gdsc { + status = "ok"; +}; + +#include "sa8155-regulator.dtsi" +#include "sm8150-pinctrl.dtsi" +#include "sm8150-bus.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi index 41df55dbe659ed4057ce63a5cef7fafa39e47733..516b606cfcd359c57233681bcc1aeba53d8d5ccf 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi @@ -193,6 +193,15 @@ pm8150_1_gpios: &pm8150_gpios { }; cooling-maps { + /* + * trip0 cooling map is dummy node to enable + * passive polling on trip0 violation. + */ + trip0_cpu0 { + trip = <&pm8150_2_trip0>; + cooling-device = <&CPU0 0 0>; + }; + trip1_cpu0 { trip = <&pm8150_2_trip1>; cooling-device = @@ -253,6 +262,15 @@ pm8150_1_gpios: &pm8150_gpios { pm8150_tz { cooling-maps { + /* + * trip0 cooling map is dummy node to enable + * passive polling on trip0 violation. + */ + trip0_cpu0 { + trip = <&pm8150_trip0>; + cooling-device = <&CPU0 0 0>; + }; + trip1_cpu0 { trip = <&pm8150_trip1>; cooling-device = diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi index c2ef8679006ab4351ef6e80a5b60585eaa76bd81..55c498669e6157f481a8fe941fb5c5b9d9eab258 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi @@ -21,6 +21,7 @@ }; /delete-node/ cpus; + /delete-node/ rename_blk; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi index ae9b504816090cee833f806476fd164453255b3e..f03c5e50c1ec25c1b048d25d36b2f7cea9564ea9 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi @@ -19,6 +19,8 @@ label = "pmem_shared_mem"; }; }; + + /delete-node/ rename_blk; }; &hab { @@ -49,3 +51,11 @@ /delete-property/ qcom,client-id; qcom,client-id = "7816"; }; + +&pcie0_msi { + status = "ok"; +}; + +&pcie0 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi index 90366d5cb5db66db7ce278811c14d746e11a0978..80c4744e12e1602fad8f73e392b9454b646d0c19 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-usb.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -58,7 +58,7 @@ 0x144 /* GSI_RING_BASE_ADDR_H */ 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; - + qcom,ignore-wakeup-src-in-hostmode; status = "disabled"; dwc3@a600000 { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi index 540e18690a992414ac800f8479a9be5e796f0448..009d2c30df2900706aea5f500f2b1371a60bda66 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi @@ -885,6 +885,7 @@ &sdc2_cmd_off &sdc2_data_off &storage_cd_default>; broken-cd; + qcom,nonhotplug; status = "disabled"; }; @@ -997,7 +998,7 @@ compatible = "qcom,smem"; memory-region = <&smem_region>; hwlocks = <&tcsr_mutex 3>; - smem-host-id = <10>; + smem-host-id = <12>; }; gvm_intr: mailbox@17c00000 { @@ -1045,3 +1046,19 @@ &tlmm { dirconn-list = <37 216 1>; }; + +&iommu_qupv3_0_geni_se_cb { + iommus = <&apps_smmu 0xd8 0x0>; +}; + +&iommu_qupv3_1_geni_se_cb { + iommus = <&apps_smmu 0x618 0x0>; +}; + +&iommu_qupv3_2_geni_se_cb { + iommus = <&apps_smmu 0x7b8 0x0>; +}; + +&iommu_qupv3_3_geni_se_cb { + iommus = <&apps_smmu 0x4f8 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index 18f6d27a9d83810a14f52524aee0f0c05eb30708..08d6d085f65339064feeb089a8da033a0d35d210 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -761,6 +761,38 @@ status="disabled"; }; +&cti_cpu0 { + status = "disabled"; +}; + +&cti_cpu1 { + status = "disabled"; +}; + +&cti_cpu2 { + status = "disabled"; +}; + +&cti_cpu3 { + status = "disabled"; +}; + +&cti_cpu4 { + status = "disabled"; +}; + +&cti_cpu5 { + status = "disabled"; +}; + +&cti_cpu6 { + status = "disabled"; +}; + +&cti_cpu7 { + status = "disabled"; +}; + #include "sa8155-audio.dtsi" #include "sa8155-camera.dtsi" #include "sa8155-camera-sensor.dtsi" diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-capture.dts similarity index 69% rename from arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts rename to arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-capture.dts index 8a47d58bc4d11ecc70c619300c9f6d5a0b447f0f..c29816000ecbd4160363987c4d87e2a1e18681cf 100644 --- a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-capture.dts @@ -12,11 +12,12 @@ /dts-v1/; -#include "qcs6125.dtsi" -#include "qcs6125-iot-idp.dtsi" +#include "sa8155-capture.dtsi" / { - model = "Qualcomm Technologies,Inc. QCS6125IOT USBC Ext AudioCodec IDP"; - compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; - qcom,board-id = <34 3>; + model = "Qualcomm Technologies, Inc. SA8155P V2 ADP AIR capture"; + compatible = "qcom,sa8155p-v2-adp-air", "qcom,sa8155p", "qcom,adp-air"; + qcom,board-id = <0x01000019 0>; + qcom,msm-id = <367 0x20000>; }; + diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass-overlay.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass-overlay.dts index 95a413d28b647b94ffd8b143dfa4f0a2e9a1bdd1..9a620c6b027f90a483bc2838cc31fea98ed57767 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass-overlay.dts @@ -23,3 +23,6 @@ qcom,board-id = <0x04010019 0>; }; +&qupv3_se0_spi { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass.dts index 46270f6b99df87b972f96e387c0387c96751f9c9..f41c0456c35cf908606579f4d194423bb41c18a9 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-lpass.dts @@ -23,3 +23,6 @@ qcom,board-id = <0x04010019 0>; }; +&qupv3_se0_spi { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star-capture.dts similarity index 70% rename from arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts rename to arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star-capture.dts index a3c69c31f73435bdf875ea86471a79f91a8ebf7c..38ae7dbb2fa66ade8c257e8551b6f1af192ca242 100644 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star-capture.dts @@ -12,11 +12,12 @@ /dts-v1/; -#include "qcm6125.dtsi" -#include "qcm6125-iot-idp.dtsi" +#include "sa8155-capture.dtsi" / { - model = "Qualcomm Technologies,Inc. QCM6125 IOT USBC Ext Aud Codec IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,board-id = <34 3>; + model = "Qualcomm Technologies, Inc. SA8155P V2 ADP STAR Capture"; + compatible = "qcom,sa8155p-adp-star", "qcom,sa8155p", "qcom,adp-star"; + qcom,board-id = <25 0>; + qcom,msm-id = <367 0x20000>; }; + diff --git a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi index ebeac6853f38c17db528028fc1ef5f4a65b8d25c..ff1d341d6729b360296737dbf7914cdf0362efef 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi @@ -122,6 +122,15 @@ }; cooling-maps { + /* + * trip0 cooling map is dummy node to enable + * passive polling on trip0 violation. + */ + trip0_cpu0 { + trip = <&pm8195_1_trip0>; + cooling-device = <&CPU0 0 0>; + }; + trip1_cpu0 { trip = <&pm8195_1_trip1>; cooling-device = @@ -206,6 +215,15 @@ }; cooling-maps { + /* + * trip0 cooling map is dummy node to enable + * passive polling on trip0 violation. + */ + trip0_cpu0 { + trip = <&pm8195_2_trip0>; + cooling-device = <&CPU0 0 0>; + }; + trip1_cpu0 { trip = <&pm8195_2_trip1>; cooling-device = @@ -290,6 +308,15 @@ }; cooling-maps { + /* + * trip0 cooling map is dummy node to enable + * passive polling on trip0 violation. + */ + trip0_cpu0 { + trip = <&pm8195_3_trip0>; + cooling-device = <&CPU0 0 0>; + }; + trip1_cpu0 { trip = <&pm8195_3_trip1>; cooling-device = diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-lxc.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-lxc.dts new file mode 100644 index 0000000000000000000000000000000000000000..fc7e93ba28748dfbd3becc915121021e0a8d714c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-lxc.dts @@ -0,0 +1,40 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8195-vm.dtsi" +#include "sa8195-vm-lv-lxc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8195 Single LV Virtual Machine"; + compatible = "qcom,sa8195p"; + qcom,pmic-name = "PM8195"; + qcom,board-id = <0x1000002 0>; +}; + +&soc { + sde_kms_hyp1: qcom,sde_kms_hyp@ae10000 { + compatible = "qcom,sde-kms-hyp"; + qcom,client-id = "7815"; + }; + + sde_kms_hyp2: qcom,sde_kms_hyp@ae20000 { + compatible = "qcom,sde-kms-hyp"; + qcom,client-id = "7818"; + }; + + sde_kms_hyp3: qcom,sde_kms_hyp@ae30000 { + compatible = "qcom,sde-kms-hyp"; + qcom,client-id = "7819"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-lxc.dtsi similarity index 51% rename from arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts rename to arch/arm64/boot/dts/qcom/sa8195-vm-lv-lxc.dtsi index 2c9d5820eccb2efde4683ada75b47dac08e1860b..98522181a703583221e882a65841475923a85c82 100644 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-lxc.dtsi @@ -10,20 +10,51 @@ * GNU General Public License for more details. */ -/dts-v1/; -/plugin/; +/ { + reserved_memory: reserved-memory { -#include + pmem_shared: pmem_shared_region@a0000000 { + reg = <0x0 0xa0000000 0x0 0x20000000>; + label = "pmem_shared_mem"; + }; + }; -#include "qcm6125-iot-idp.dtsi" + /delete-node/ rename_blk; +}; -/ { - model = "USB-C Ext Audio Codec IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,msm-id = <467 0x10000>; - qcom,board-id = <34 3>; +&hab { + vmid = <3>; +}; + +&slpi_tlmm { + status = "ok"; +}; + +&apps_smmu { + status = "ok"; +}; + +&qupv3_se13_4uart { + status = "ok"; +}; + +&usb0 { + status = "ok"; +}; + +&usb2_phy0 { + status = "ok"; +}; + +&pcie0_msi { + status = "ok"; +}; + +&pcie0 { + status = "ok"; }; -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; +&sde_kms_hyp { + /delete-property/ qcom,client-id; + qcom,client-id = "7816"; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi index 074d40913c28044b55c92bd0fe9bb672144e7912..a678e6c4afc759b362c1247175cf874cd653f86e 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi @@ -20,6 +20,7 @@ }; /delete-node/ cpus; + /delete-node/ rename_blk; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dtsi index f55efa749ab192f196e316d6912ead671e553b46..097af7244c89babec215e8fbc1baad12eafee813 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dtsi @@ -19,6 +19,7 @@ }; }; + /delete-node/ rename_blk; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi index 1035d25de40bd1e16aa4be2502bc73e6fd7eecdc..01e507a282e611e39642f2c3c92ceb89689be759 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-usb.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -56,7 +56,7 @@ 0x144 /* GSI_RING_BASE_ADDR_H */ 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; - + qcom,ignore-wakeup-src-in-hostmode; status = "disabled"; dwc3@a600000 { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi index 32e1be94cae597cdbc338c1e6196f7cdf66a4f32..ef2709cf57191f7991c43e1dd1e07d2b04105d06 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi @@ -129,6 +129,104 @@ }; &soc { + hsi2s: qcom,hsi2s { + compatible = "qcom,sa8195-hsi2s", "qcom,hsi2s"; + number-of-interfaces = <3>; + reg = <0x172C0000 0x28000>, + <0x17080000 0xE000>; + reg-names = "lpa_if", "lpass_tcsr"; + interrupts = ; + number-of-rate-detectors = <2>; + rate-detector-interfaces = <0 1>; + + sdr0: qcom,hs0_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs1_i2s_mclk_active &hs1_i2s_sck_active + &hs1_i2s_ws_active &hs1_i2s_data0_active + &hs1_i2s_data1_active>; + pinctrl-1 = <&hs1_i2s_mclk_sleep &hs1_i2s_sck_sleep + &hs1_i2s_ws_sleep &hs1_i2s_data0_sleep + &hs1_i2s_data1_sleep>; + bit-clock-hz = <12288000>; + data-buffer-ms = <10>; + bit-depth = <32>; + spkr-channel-count = <2>; + mic-channel-count = <2>; + pcm-rate = <2>; + pcm-sync-src = <0>; + aux-mode = <0>; + rpcm-width = <1>; + tpcm-width = <1>; + enable-tdm = <1>; + tdm-rate = <32>; + tdm-rpcm-width = <16>; + tdm-tpcm-width = <16>; + tdm-sync-delay = <2>; + tdm-inv-sync = <0>; + pcm-lane-config = <1>; + }; + + sdr1: qcom,hs1_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs2_i2s_mclk_active &hs2_i2s_sck_active + &hs2_i2s_ws_active &hs2_i2s_data0_active + &hs2_i2s_data1_active>; + pinctrl-1 = <&hs2_i2s_mclk_sleep &hs2_i2s_sck_sleep + &hs2_i2s_ws_sleep &hs2_i2s_data0_sleep + &hs2_i2s_data1_sleep>; + bit-clock-hz = <12288000>; + data-buffer-ms = <10>; + bit-depth = <32>; + spkr-channel-count = <2>; + mic-channel-count = <2>; + pcm-rate = <2>; + pcm-sync-src = <0>; + aux-mode = <0>; + rpcm-width = <1>; + tpcm-width = <1>; + enable-tdm = <1>; + tdm-rate = <32>; + tdm-rpcm-width = <16>; + tdm-tpcm-width = <16>; + tdm-sync-delay = <2>; + tdm-inv-sync = <0>; + pcm-lane-config = <1>; + }; + + sdr2: qcom,hs2_i2s { + compatible = "qcom,hsi2s-interface"; + minor-number = <2>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hs3_i2s_mclk_active &hs3_i2s_sck_active + &hs3_i2s_ws_active &hs3_i2s_data0_active + &hs3_i2s_data1_active>; + pinctrl-1 = <&hs3_i2s_mclk_sleep &hs3_i2s_sck_sleep + &hs3_i2s_ws_sleep &hs3_i2s_data0_sleep + &hs3_i2s_data1_sleep>; + bit-clock-hz = <12288000>; + data-buffer-ms = <10>; + bit-depth = <32>; + spkr-channel-count = <2>; + mic-channel-count = <2>; + pcm-rate = <2>; + pcm-sync-src = <0>; + aux-mode = <0>; + rpcm-width = <1>; + tpcm-width = <1>; + enable-tdm = <1>; + tdm-rate = <32>; + tdm-rpcm-width = <16>; + tdm-tpcm-width = <16>; + tdm-sync-delay = <2>; + tdm-inv-sync = <0>; + pcm-lane-config = <1>; + }; + }; + pdc: interrupt-controller@0xb220000{ compatible = "qcom,pdc-virt"; reg = <0xb220000 0x400>; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-common.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4ded57fd707b52d4255d58ab81f4cda9a4646cba --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-common.dtsi @@ -0,0 +1,146 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "sa8195p-cnss.dtsi" + +&qupv3_3 { + status = "ok"; +}; + +&qupv3_se0_spi { + status = "ok"; + +#address-cells = <1>; +#size-cells = <0>; + + can-controller@0 { + compatible = "qcom,nxp,mpc5746c"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <38 0>; + spi-max-frequency = <5000000>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <1>; + qcom,bits-per-word = <8>; + qcom,support-can-fd; + }; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&qupv3_se13_4uart { + status = "ok"; +}; + +&qupv3_se4_i2c { + status = "ok"; +}; + +&pil_lpass { + status = "ok"; +}; + +&pil_ssc { + status = "disabled"; +}; + +&pil_spss { + status = "ok"; +}; + +&pil_turing { + status = "ok"; +}; + +&pil_venus { + status = "ok"; +}; + +&pil_npu { + status = "ok"; +}; + +&glink_modem { + status = "disabled"; +}; + +&ssc_sensors { + status = "disabled"; +}; + +&soc { + qcom,msm-cdsp-loader { + status = "ok"; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8195_1_l10>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8195_1_l2>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on + &sdc2_cmd_on &sdc2_data_on &storage_cd_default>; + pinctrl-1 = <&sdc2_clk_off + &sdc2_cmd_off &sdc2_data_off &storage_cd_default>; + + cd-gpios = <&pm8195_1_gpios 4 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pcie2 { + qcom,boot-option = <0x0>; +}; + +&pcie_rc2 { +nvme_x8: qcom,nvme@pcie_rc2 { + reg = <0 0 0 0 0>; + compatible = "qcom,nvme"; + pci-ids = + "8086:0953", + "8086:0a54", + "8086:0a55", + "8086:f1a5", + "8086:f1a5", + "1c58:0003", + "1c58:0023", + "1c5c:1327", + "1c5f:0540", + "144d:a821", + "144d:a822", + "144d:a808", + "1d1d:1f1f", + "1d1d:2807", + "1d1d:2601", + "106b:2001", + "106b:2003", + "1179:0115", + "1179:0116"; + + qcom,smmu; + qcom,smmu-iova-base = /bits/ 64 <0x20000000>; + qcom,smmu-iova-size = /bits/ 64 <0x40000000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-s1-bypass; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi index 36ffa616fecdb7ad814f04ba82bd7783f2bd4ad1..b75b2f8a515626cef0e20fdbc26bc6393d984a91 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi @@ -432,7 +432,8 @@ compatible = "qcom,sde-kms-lease"; qcom,dev-name = "msm_drm"; qcom,lease-connectors = "DSI-2", "shared-disp-0", - "DP-1", "DP-2", "DP-3", "DP-4", "DP-5"; + "DP-1", "DP-2", "DP-3", "DP-4", "DP-5", + "Virtual-1"; qcom,lease-planes = "plane-0", "plane-1", "plane-2", "plane-3","plane-4", "plane-5", "plane-6","plane-7", "plane-8", diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi index e0156fc8768703a956c02059d93435cf3d3b3922..e9792470cb5e9a0708d0c03f1ac817d0c93cf720 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,122 +11,5 @@ */ #include +#include "sa8195p-adp-common.dtsi" #include "sa8195p-adp-star-display.dtsi" -#include "sa8195p-cnss.dtsi" - -&qupv3_se0_spi { - status = "ok"; - - #address-cells = <1>; - #size-cells = <0>; - - can-controller@0 { - compatible = "qcom,nxp,mpc5746c"; - reg = <0>; - interrupt-parent = <&tlmm>; - interrupts = <38 0>; - spi-max-frequency = <5000000>; - qcom,clk-freq-mhz = <40000000>; - qcom,max-can-channels = <1>; - qcom,bits-per-word = <8>; - qcom,support-can-fd; - }; -}; - -&qupv3_se12_2uart { - status = "ok"; -}; - -&qupv3_se13_4uart{ - status = "ok"; -}; - -&sdhc_2 { - vdd-supply = <&pm8195_1_l10>; - qcom,vdd-voltage-level = <2950000 2960000>; - qcom,vdd-current-level = <200 800000>; - - vdd-io-supply = <&pm8195_1_l2>; - qcom,vdd-io-voltage-level = <1808000 2960000>; - qcom,vdd-io-current-level = <200 22000>; - - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc2_clk_on - &sdc2_cmd_on &sdc2_data_on &storage_cd_default>; - pinctrl-1 = <&sdc2_clk_off - &sdc2_cmd_off &sdc2_data_off &storage_cd_default>; - - cd-gpios = <&pm8195_1_gpios 4 GPIO_ACTIVE_LOW>; - - status = "ok"; -}; - -&pil_lpass { - status = "ok"; -}; - -&pil_ssc { - status = "disabled"; -}; - -&pil_spss { - status = "ok"; -}; - -&pil_turing { - status = "ok"; -}; - -&pil_venus { - status = "ok"; -}; - -&pil_npu { - status = "ok"; -}; - -&glink_modem { - status = "disabled"; -}; - -&ssc_sensors { - status = "disabled"; -}; - -&pcie2 { - qcom,boot-option = <0x0>; -}; - -&pcie_rc2 { - nvme_x8: qcom,nvme@pcie_rc2 { - reg = <0 0 0 0 0>; - compatible = "qcom,nvme"; - pci-ids = - "8086:0953", - "8086:0a54", - "8086:0a55", - "8086:f1a5", - "8086:f1a5", - "1c58:0003", - "1c58:0023", - "1c5c:1327", - "1c5f:0540", - "144d:a821", - "144d:a822", - "144d:a808", - "1d1d:1f1f", - "1d1d:2807", - "1d1d:2601", - "106b:2001", - "106b:2003", - "1179:0115", - "1179:0116"; - - qcom,smmu; - qcom,smmu-iova-base = /bits/ 64 <0x20000000>; - qcom,smmu-iova-size = /bits/ 64 <0x40000000>; - - qcom,smmu-attr-atomic; - qcom,smmu-attr-s1-bypass; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-camera.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-camera.dtsi index 7a3bd743658a5bc0921717e19ef8d4f5b366a2a1..b869b06b6f974063a3cc7c79a839b0d7c1aaff34 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-camera.dtsi @@ -532,14 +532,22 @@ msm_cam_smmu_ife { compatible = "qcom,msm-cam-smmu-cb"; - iommus = <&apps_smmu 0xAA0 0x4E0>, - <&apps_smmu 0xA20 0x4E0>, - <&apps_smmu 0xA00 0x4E0>, + iommus = <&apps_smmu 0xA00 0x4E0>, + <&apps_smmu 0xAA0 0x4E0>, + <&apps_smmu 0xA40 0x4E0>, + <&apps_smmu 0xA60 0x4E0>, <&apps_smmu 0xA80 0x4E0>, + <&apps_smmu 0xA20 0x4E0>, + <&apps_smmu 0xAC0 0x4E0>, + <&apps_smmu 0xAE0 0x4E0>, + <&apps_smmu 0xE00 0x4E0>, <&apps_smmu 0xEA0 0x4E0>, + <&apps_smmu 0xE40 0x4E0>, + <&apps_smmu 0xE60 0x4E0>, + <&apps_smmu 0xE80 0x4E0>, <&apps_smmu 0xE20 0x4E0>, - <&apps_smmu 0xE00 0x4E0>, - <&apps_smmu 0xE80 0x4E0>; + <&apps_smmu 0xEC0 0x4E0>, + <&apps_smmu 0xEE0 0x4E0>; label = "ife"; ife_iova_mem_map: iova-mem-map { /* IO region is approximately 3.4 GB */ @@ -553,6 +561,38 @@ }; }; + msm_cam_smmu_ife_cp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0xA01 0x5E0>, + <&apps_smmu 0xAA1 0x5E0>, + <&apps_smmu 0xA41 0x5E0>, + <&apps_smmu 0xA61 0x5E0>, + <&apps_smmu 0xA81 0x5E0>, + <&apps_smmu 0xA21 0x5E0>, + <&apps_smmu 0xAC1 0x5E0>, + <&apps_smmu 0xAE1 0x5E0>, + <&apps_smmu 0xE01 0x5E0>, + <&apps_smmu 0xEA1 0x5E0>, + <&apps_smmu 0xE41 0x5E0>, + <&apps_smmu 0xE61 0x5E0>, + <&apps_smmu 0xE81 0x5E0>, + <&apps_smmu 0xE21 0x5E0>, + <&apps_smmu 0xEC1 0x5E0>, + <&apps_smmu 0xEE1 0x5E0>; + label = "ife-cp"; + qcom,secure-pixel-cb; + ife_cp_iova_mem_map: iova-mem-map { + /* IO region is approximately 2.5 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0x98C00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + msm_cam_smmu_jpeg { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x2100 0x20>, diff --git a/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air-overlay.dts b/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air-overlay.dts index 92debaa650a1f4e68e6e228d2a6dc682601bf04c..1f59cbbc5f706705a710bdec50967bf9ef78fe4c 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air-overlay.dts @@ -13,7 +13,7 @@ /dts-v1/; /plugin/; -#include "sa8195p.dtsi" +#include "sa8195p-adp-common.dtsi" #include "sa8195p-adp-star-display.dtsi" / { @@ -23,3 +23,8 @@ qcom,board-id = <0x02010019 0>; }; +&qupv3_se0_spi { + can-controller@0 { + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air.dts b/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air.dts index b0854f5b1f5e1db6d61d291f8e1b0254f3cc5217..fce5996c3f0311d873fd6306441df9b1b898c4d0 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air.dts +++ b/arch/arm64/boot/dts/qcom/sa8195p-v2-adp-air.dts @@ -13,6 +13,7 @@ /dts-v1/; #include "sa8195p.dtsi" +#include "sa8195p-adp-common.dtsi" #include "sa8195p-adp-star-display.dtsi" / { @@ -21,3 +22,8 @@ qcom,board-id = <0x02010019 0>; }; +&qupv3_se0_spi { + can-controller@0 { + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dtsi b/arch/arm64/boot/dts/qcom/sa8195p.dtsi index 3e31e5d48b2ac383febd5eac85b7b4ec31c3897e..62728a00074892ec37b43a54b13ae77b5c615a76 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p.dtsi @@ -774,3 +774,8 @@ }; }; }; + +&qupv3_se2_i2c { + qcom,clk-freq-out = <400000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts index 03c3a00fa5ade81682ef7232aba6f201c5f02a80..449691b4c68d502fabb3cef8c6b43af9ad10fbb7 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts @@ -16,15 +16,69 @@ #include #include "sda429-bg-dvt2-wtp.dtsi" +#include "sdm429-mdss-panels.dtsi" +#include "sdm429-spyro-qrd-evt-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDA429 QRD BG WTP Overlay"; compatible = "qcom,sdm429w-qrd", "qcom,sdm429w", "qcom,qrd"; qcom,msm-id = <437 0x0>; - qcom,board-id = <0x00010b 8>; + qcom,board-id = <0x00010b 0xA>; qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>; }; +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + /delete-property/ vdda-supply; + /delete-property/ vddio-supply; + vdda-supply = <&L6A>; /* 0.8v */ + vddio-supply = <&L13A>; /* 1.8v */ + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <800000>; + qcom,supply-max-voltage = <800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_416p_amoled_cmd>; + /delete-property/ vdd-supply; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_te_active>; + pinctrl-1 = <&mdss_te_suspend>; + vddio-supply = <&L11A>; + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; + qcom,platform-enable-gpio = <&pm660_gpios 12 0>; + +}; + +&mdss_dsi0_pll { + /delete-property/ vddio-supply; + vddio-supply = <&L13A>; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + +&mdss_dsi1_pll { + status = "disabled"; +}; + &i2c_4 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sda429-wdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-wdp-overlay.dts index 5e1ba25527ff1ab0e3f8a4929bb904ad96fecfd7..62d2a33ec20ec726c5df31be62fefe1b8f649252 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-wdp-overlay.dts @@ -15,6 +15,7 @@ /plugin/; #include "sda429-wdp.dtsi" +#include "sdm429-spyro-qrd-evt-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDA429 QRD BG WDP Overlay"; diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts index 7bbdfa9ae059821dde85da69022fce35fef8413c..8b141c392fdf19bfcdcba000401fc255c2fd174f 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts @@ -16,6 +16,8 @@ #include #include "sda429-wtp.dtsi" +#include "sdm429-mdss-panels.dtsi" +#include "sdm429-spyro-qrd-evt-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDA429 QRD BG WTP Overlay"; @@ -25,6 +27,58 @@ qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>; }; +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + /delete-property/ vdda-supply; + /delete-property/ vddio-supply; + vdda-supply = <&L6A>; /* 0.8v */ + vddio-supply = <&L13A>; /* 1.8v */ + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <800000>; + qcom,supply-max-voltage = <800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_416p_amoled_cmd>; + /delete-property/ vdd-supply; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_te_active>; + pinctrl-1 = <&mdss_te_suspend>; + vddio-supply = <&L11A>; + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; + qcom,platform-enable-gpio = <&pm660_gpios 12 0>; + +}; + +&mdss_dsi0_pll { + /delete-property/ vddio-supply; + vddio-supply = <&L13A>; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + +&mdss_dsi1_pll { + status = "disabled"; +}; + &i2c_4 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm429-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..42204b3cdae300299b0941b15f3b93128463dc6f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-audio.dtsi @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_iommu 0x2001 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&soc { + qcom,avtimer@c0a300c { + compatible = "qcom,avtimer"; + reg = <0x0c0a300c 0x4>, + <0x0c0a3010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <27>; + }; + + audio_apr: qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + q6core: q6core { + compatible = "qcom,q6core-audio"; + }; + }; + + int_codec: sound { + status = "disabled"; + compatible = "qcom,msm8952-audio-codec"; + qcom,model = "msm8952-snd-card-mtp"; + reg = <0xc051000 0x4>, + <0xc051004 0x4>, + <0xc055000 0x4>, + <0xc052000 0x4>; + reg-names = "csr_gp_io_mux_mic_ctl", + "csr_gp_io_mux_spkr_ctl", + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel", + "csr_gp_io_mux_quin_ctl"; + + qcom,msm-ext-pa = "primary"; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-hs-micbias-type = "external"; + qcom,msm-micbias1-ext-cap; + + qcom,audio-routing = + "RX_BIAS", "MCLK", + "SPK_RX_BIAS", "MCLK", + "INT_LDO_H", "MCLK", + "RX_I2S_CLK", "MCLK", + "TX_I2S_CLK", "MCLK", + "MIC BIAS External", "Handset Mic", + "MIC BIAS External2", "Headset Mic", + "MIC BIAS External", "Secondary Mic", + "AMIC1", "MIC BIAS External", + "AMIC2", "MIC BIAS External2", + "AMIC3", "MIC BIAS External", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "WSA_SPK OUT", "VDD_WSA_SWITCH", + "SpkrMono WSA_IN", "WSA_SPK OUT"; + + qcom,cdc-us-euro-gpios = <&tlmm 63 0>; + qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_pri_auxpcm>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_mi2s5>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, + <&bt_sco_rx>, <&bt_sco_tx>, + <&int_fm_rx>, <&int_fm_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>; + + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.6", + "msm-dai-q6-dev.16384", "msmdai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770"; + + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; + + cdc_us_euro_sw: msm_cdc_pinctrl_us_euro_sw { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cross_conn_det_act>; + pinctrl-1 = <&cross_conn_det_sus>; + }; + + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act>; + pinctrl-1 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus>; + }; + + cdc_quin_mi2s_gpios: msm_cdc_pinctrl_quin { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_tlmm_lines_act &pri_tlmm_ws_act>; + pinctrl-1 = <&pri_tlmm_lines_sus &pri_tlmm_ws_sus>; + }; + + i2c@78b6000 { + status = "okay"; + }; + + cpe: qcom,msm-cpe-lsm { + compatible = "qcom,msm-cpe-lsm"; + }; + + clock_audio: audio_ext_clk { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + pinctrl-0 = <&cdc_mclk2_sleep>; + pinctrl-1 = <&cdc_mclk2_active>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts index 5f21ceecaaa231fd6f537f6ab152a697c9464791..1127126a912475c7106eb5cd83164409e1ebab9b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts @@ -17,6 +17,7 @@ #include #include "sdm429-bg-dvt2-wtp.dtsi" #include "sdm429-mdss-panels.dtsi" +#include "sdm429-spyro-qrd-evt-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDM429 QRD BG WTP Overlay"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi index 6ac3d71f82f59a9ac6881f4cdec310b2eb6b6b9a..6f0e3622081d5904eb4fb9f90795f645f77855a5 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi @@ -26,6 +26,7 @@ spi_3: spi@78b7000 { /* BLSP1 QUP3*/ status = "ok"; + qcom,shared_ee; qcom,bg-spi { compatible = "qcom,bg-spi"; reg = <0>; @@ -78,12 +79,6 @@ qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data"; }; - qcom,glinkpkt-bg-rsb-ctrl { - qcom,glinkpkt-edge = "bg"; - qcom,glinkpkt-ch-name = "RSB_CTRL"; - qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl"; - }; - qcom,glinkpkt-bg-sso-ctrl { qcom,glinkpkt-edge = "bg"; qcom,glinkpkt-ch-name = "sso-ctrl"; @@ -97,4 +92,17 @@ }; }; + qcom,bg-rsb { + compatible = "qcom,bg-rsb"; + vdd-ldo1-supply = <&pm660_l11>; + qcom,bg-rsb-gpio = <&tlmm 40 1>; + qcom,rsb-use-msm-gpio; + }; + qcom,bgrsb-rpmsg { + compatible = "qcom,bgrsb-rpmsg"; + qcom,glink-channels = "RSB_CTRL"; + qcom,glinkpkt-edge = "bg"; + intents = <0x200 20>; + }; + }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi index e661a4f1db0bc6355fa9b25d952e77369955c02b..06f9e76d7983bf96096cac74a1c4d867e591d9bc 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi @@ -198,6 +198,7 @@ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; spi-max-frequency = <50000000>; + qcom,use-bam; qcom,ver-reg-exists; qcom,bam-consumer-pipe-index = <8>; qcom,bam-producer-pipe-index = <9>; diff --git a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi index e5c016ee8f0ec203f2840f1277c9b805000a2f53..8632471a74cd167de17e3d2d26f609eb6217c546 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi @@ -43,7 +43,7 @@ reg = <0x100>; enable-method = "psci"; cpu-release-addr = <0x0 0x90000000>; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; next-level-cache = <&L2_1>; #cooling-cells = <2>; @@ -69,7 +69,7 @@ reg = <0x101>; enable-method = "psci"; cpu-release-addr = <0x0 0x90000000>; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; next-level-cache = <&L2_1>; #cooling-cells = <2>; @@ -89,7 +89,7 @@ reg = <0x102>; enable-method = "psci"; cpu-release-addr = <0x0 0x90000000>; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; next-level-cache = <&L2_1>; #cooling-cells = <2>; @@ -109,7 +109,7 @@ reg = <0x103>; enable-method = "psci"; cpu-release-addr = <0x0 0x90000000>; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; next-level-cache = <&L2_1>; #cooling-cells = <2>; @@ -134,9 +134,6 @@ 1305600 207 1497600 256 1708800 327 - 1804800 343 - 1958400 445 - 2016000 470 >; idle-cost-data = < 100 80 60 40 @@ -148,9 +145,6 @@ 1305600 61 1497600 71 1708800 85 - 1804800 88 - 1958400 110 - 2016000 120 >; idle-cost-data = < 4 3 2 1 diff --git a/arch/arm64/boot/dts/qcom/sdm429-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/sdm429-mdss-panels.dtsi index c564239c6988e7c24148379bca23156b76628f69..fe112f060f7d8cd46254e280cb8f17ecc35c100e 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-mdss-panels.dtsi @@ -45,6 +45,7 @@ qcom,mdss-dsi-panel-status-check-mode = "te_signal_check"; qcom,mdss-dsi-power-off-disable; qcom,mdss-dsi-tear-disable; + qcom,mdss-skip-panel-reset; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi index 5ede5718b03811df8c62f0560501b7e08699ca37..ebd655db3e99fa42ca81f6854284f7b190ff50c0 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi @@ -1044,5 +1044,274 @@ }; }; }; + + pmx_quat_mi2s { + label = "quat_mi2s"; + quat_mi2s_active: quat_mi2s_active { + mux { + pins = "gpio94", "gpio95"; + function = "sec_mi2s"; + }; + configs { + pins = "gpio94", "gpio95"; + drive-strength = <8>; /* 8 MA */ + bias-disable; /* No PULL */ + }; + }; + quat_mi2s_sleep: quat_mi2s_sleep { + mux { + pins = "gpio94", "gpio95"; + function = "sec_mi2s"; + }; + configs { + pins = "gpio94", "gpio95"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_quat_mi2s_din { + label = "quat_mi2s_din"; + quat_mi2s_din_active: quat_mi2s_din_active { + mux { + pins = "gpio12", "gpio13"; + function = "sec_mi2s"; + }; + configs { + pins = "gpio12", "gpio13"; + drive-strength = <8>; /* 8 MA */ + bias-disable; /* No PULL */ + output-high; + }; + }; + quat_mi2s_din_sleep: quat_mi2s_din_sleep { + mux { + pins = "gpio12", "gpio13"; + function = "sec_mi2s"; + }; + configs { + pins = "gpio12", "gpio13"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + cdc-dmic-lines { + cdc_dmic0_clk_act: dmic0_clk_on { + mux { + pins = "gpio89"; + function = "dmic0_clk"; + }; + + config { + pins = "gpio89"; + drive-strength = <8>; + bias-pull-none; + }; + }; + + cdc_dmic0_clk_sus: dmic0_clk_off { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <2>; + bias-disable; + }; + }; + + cdc_dmic0_data_act: dmic0_data_on { + mux { + pins = "gpio90"; + function = "dmic0_data"; + }; + + config { + pins = "gpio90"; + drive-strength = <8>; + bias-pull-none; + }; + }; + + cdc_dmic0_data_sus: dmic0_data_off { + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + cdc_mclk2_pin { + cdc_mclk2_sleep: cdc_mclk2_sleep { + mux { + pins = "gpio66"; + function = "pri_mi2s"; + }; + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + cdc_mclk2_active: cdc_mclk2_active { + mux { + pins = "gpio66"; + function = "pri_mi2s"; + }; + config { + pins = "gpio66"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + cross-conn-det { + cross_conn_det_act: lines_on { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <8>; + output-low; + bias-pull-down; + }; + }; + + cross_conn_det_sus: lines_off { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + cdc-pdm-lines { + cdc_pdm_lines_act: pdm_lines_on { + mux { + pins = "gpio69", "gpio73", "gpio74"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio69", "gpio73", "gpio74"; + drive-strength = <8>; + }; + }; + cdc_pdm_lines_sus: pdm_lines_off { + mux { + pins = "gpio69", "gpio73", "gpio74"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio69", "gpio73", "gpio74"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + cdc-pdm-2-lines { + cdc_pdm_lines_2_act: pdm_lines_2_on { + mux { + pins = "gpio70", "gpio71", "gpio72"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio70", "gpio71", "gpio72"; + drive-strength = <8>; + }; + }; + + cdc_pdm_lines_2_sus: pdm_lines_2_off { + mux { + pins = "gpio70", "gpio71", "gpio72"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio70", "gpio71", "gpio72"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pri-tlmm-lines { + pri_tlmm_lines_act: pri_tlmm_lines_act { + mux { + pins = "gpio85", "gpio88"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio85", "gpio88"; + drive-strength = <8>; + }; + }; + + pri_tlmm_lines_sus: pri_tlmm_lines_sus { + mux { + pins = "gpio85", "gpio88"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio85", "gpio88"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pri-tlmm-ws-lines { + pri_tlmm_ws_act: pri_tlmm_ws_act { + mux { + pins = "gpio87"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio87"; + drive-strength = <8>; + }; + }; + + pri_tlmm_ws_sus: pri_tlmm_ws_sus { + mux { + pins = "gpio87"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio87"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8f506004f8e9b698dc84ba5562441ec992161ae0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-spyro-qrd-evt-audio.dtsi @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&int_codec { + compatible = "qcom,msm8952-dig-asoc-snd"; + status = "okay"; + qcom,model = "sdm429w-snd-card"; + qcom,msm-ext-pa = "quaternary"; + qcom,split-a2dp; + asoc-wsa-codec-names; + asoc-wsa-codec-prefixes; + ext_pa_tfa98xx; + qcom,audio-routing = + "CDC_CONN", "MCLK", + "QUAT_MI2S_RX", "DIGITAL_REGULATOR", + "TX_I2S_CLK", "DIGITAL_REGULATOR", + "DMIC1", "Digital Mic1", + "DMIC2", "Digital Mic2"; + qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>; + qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>; + qcom,msm-gpios = + "quat_i2s", + "dmic"; + qcom,pinctrl-names = + "all_off", + "quat_i2s_act", + "dmic_act", + "quat_i2s_dmic_act"; + pinctrl-names = + "all_off", + "quat_i2s_act", + "dmic_act", + "quat_i2s_dmic_act"; + pinctrl-0 = <&quat_mi2s_sleep &quat_mi2s_din_sleep + &cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + pinctrl-1 = <&quat_mi2s_active &quat_mi2s_din_active + &cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + pinctrl-2 = <&quat_mi2s_sleep &quat_mi2s_din_sleep + &cdc_dmic0_clk_act &cdc_dmic0_data_act>; + pinctrl-3 = <&quat_mi2s_active &quat_mi2s_din_active + &cdc_dmic0_clk_act &cdc_dmic0_data_act>; + /delete-property/qcom,cdc-us-euro-gpios; + /delete-property/qcom,pri-mi2s-gpios; + /delete-property/qcom,cdc-us-eu-gpios; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_pri_auxpcm>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_mi2s5>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, + <&bt_sco_rx>, <&bt_sco_tx>, <&bt_a2dp_rx>, + <&int_fm_rx>, <&int_fm_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>; + + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.6", + "msm-dai-q6-dev.16384", "msmdai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12290", + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770"; + asoc-codec = <&stub_codec>, <&msm_dig_codec>, <&ext_smart_pa>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec", "ext-smart-pa"; +}; + +&soc { + msm_dig_codec: msm_dig_codec { + compatible = "qcom,msm-digital-codec"; + reg = <0xc0f0000 0x0>; + qcom,no-analog-codec; + cdc-vdd-digital-supply = <&pm660_l9>; + qcom,cdc-vdd-digital-voltage = <1800000 1800000>; + qcom,cdc-vdd-digital-current = <10000>; + qcom,cdc-on-demand-supplies = "cdc-vdd-digital"; + }; + + cdc_dmic_gpios: cdc_dmic_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic0_clk_act &cdc_dmic0_data_act>; + pinctrl-1 = <&cdc_dmic0_clk_sus &cdc_dmic0_data_sus>; + }; + + cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + bt_a2dp_rx: qcom,msm-dai-q6-bt-a2dp-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12290>; + }; + }; +}; + +&tlmm { + smart_pa_int { + pa_int_default: pa_int_default { + mux { + pins = "gpio73", "gpio73"; + function = "gpio"; + }; + + config { + pins = "gpio73", "gpio73"; + drive-strength = <4>; + bias-disable; + }; + }; + }; + + smart_pa_rst { + pa_rst_default: pa_rst_default { + mux { + pins = "gpio68", "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68", "gpio68"; + drive-strength = <4>; + bias-disable; + }; + }; + }; +}; + +&cdc_us_euro_sw { + status = "disabled"; +}; + +&cdc_pri_mi2s_gpios { + status = "disabled"; +}; + +&cdc_quin_mi2s_gpios { + status = "disabled"; +}; + +&i2c_2 { + ext_smart_pa: nxp_smartpa@34 { + status = "okay"; + compatible = "nxp,tfa98xx"; + reg = <0x34>; + reset-gpio = <&tlmm 68 0>; + irq-gpio = <&tlmm 73 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pa_int_default &pa_rst_default>; + dvdd-supply = <&pm660_l9>; + dvdd-voltage = <1800000 1800000>; + dvdd-current = <15000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm429-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a7d1b7635fc81372ed4b0b80664a0f7d4c7cbad1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-thermal.dtsi @@ -0,0 +1,706 @@ +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + aoss0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + lpass-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-step { + polling-delay-passive = <250>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gpu_step_trip: gpu-step-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + gpu_cdev0 { + trip = <&gpu_step_trip>; + cooling-device = + <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + hexa-cpu-max-step { + polling-delay-passive = <50>; + polling-delay = <100>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu_trip:cpu-trip { + temperature = <85000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu1_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU1 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu2_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU2 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu3_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU3 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; + + apc1-cpu0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + apc1_cpu0_trip: apc1-cpu0-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&apc1_cpu0_trip>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc1-cpu1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + apc1_cpu1_trip: apc1-cpu1-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu1_cdev { + trip = <&apc1_cpu1_trip>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc1-cpu2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + apc1_cpu2_trip: apc1-cpu2-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu2_cdev { + trip = <&apc1_cpu2_trip>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc1-cpu3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + apc1_cpu3_trip: apc1-cpu3-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu3_cdev { + trip = <&apc1_cpu3_trip>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + aoss0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + trips { + aoss0_trip: aoss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + mdm-core-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + tracks-low; + trips { + mdm_core_trip: mdm-core-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + lpass-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + tracks-low; + trips { + qdsp_trip: qdsp-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + camera-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + tracks-low; + trips { + camera_trip: camera-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + cpuss1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + tracks-low; + trips { + cpuss1_trip: cpuss1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpuss1_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&cpuss1_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpuss1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + tracks-low; + trips { + cpu0_trip: apc1-cpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + tracks-low; + trips { + cpu1_trip: apc1-cpu1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu2-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + tracks-low; + trips { + cpu2_trip: apc1-cpu2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu3-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + tracks-low; + trips { + cpu3_trip: apc1-cpu3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + cpuss0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + tracks-low; + trips { + cpuss0_lowf_trip: cpuss0-lowf-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpuss0_lowf_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&cpuss0_lowf_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpuss0_lowf_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + gpu-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + tracks-low; + trips { + gpu_lowf_trip: gpu-lowf-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu_lowf_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&gpu_lowf_trip>; + cooling-device = <&pm660_cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu_lowf_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-wdp-overlay.dts index c676f097905fc846b4dc9adcc6995ffda15c49d4..a8f40500b4831d0f1e05c68cc32dd14dcf9f445b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-wdp-overlay.dts @@ -15,6 +15,7 @@ /plugin/; #include "sdm429-wdp.dtsi" +#include "sdm429-spyro-qrd-evt-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDM429 QRD BG WDP Overlay"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts index 1a802084a9e3c2b156efb2d0cfe270549c3dc7ee..ba93b0485677f286c7feed34b19830ed137c429c 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts @@ -17,6 +17,7 @@ #include #include "sdm429-wtp.dtsi" #include "sdm429-mdss-panels.dtsi" +#include "sdm429-spyro-qrd-evt-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDM429 QRD BG WTP Overlay"; diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 899b9f6e41cf50e57ad1fa8bec7289f3ba9be47b..22955a639d930e4e2b2228cd70533b1515475a40 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -19,6 +19,9 @@ #include #include +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + / { model = "Qualcomm Technologies, Inc. SDM429"; compatible = "qcom,sdm429"; @@ -32,6 +35,11 @@ firmware: firmware { android { compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo,recovery"; + }; + fstab { compatible = "android,fstab"; vendor { @@ -418,7 +426,33 @@ cpu-pmu { compatible = "arm,armv8-pmuv3"; interrupts = <1 7 0xff00>; - status = "disabled"; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x200000>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; }; qcom,sps { @@ -466,7 +500,6 @@ qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */ - status = "disabled"; }; qcom,rmtfs_sharedmem@00000000 { @@ -608,6 +641,46 @@ }; }; + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <0x85>; + + rpm_sw_dump { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic_dump { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xe4>; + }; + + vsense_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe9>; + }; + + tmc_etf_dump { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf0>; + }; + + tmc_etr_reg_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + tmc_etf_reg_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x101>; + }; + + misc_data_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + }; + qcom,lpass@c000000 { compatible = "qcom,pil-tz-generic"; reg = <0xc000000 0x00100>; @@ -700,7 +773,44 @@ qcom,smem-state-names = "qcom,force-stop"; memory-region = <&wcnss_fw_mem>; }; + qcom,venus@1de0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x1de0000 0x4000>; + + vdd-supply = <&venus_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, + <&gcc GCC_VENUS0_AHB_CLK>, + <&gcc GCC_VENUS0_AXI_CLK>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>, + <&gcc CRYPTO_CLK_SRC>; + + clock-names = "core_clk", "iface_clk", "bus_clk", + "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + + qcom,proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "scm_core_clk", + "scm_iface_clk", "scm_bus_clk", + "scm_core_clk_src"; + qcom,scm_core_clk_src-freq = <80000000>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + + qcom,mas-crypto = <&mas_crypto>; + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&venus_mem>; + }; pil_modem: qcom,mss@4080000 { compatible = "qcom,pil-q6v55-mss"; reg = <0x4080000 0x100>, @@ -939,6 +1049,7 @@ qcom,smd-edge = <1>; qcom,ipc = <&apcs 0 8>; qcom,remote-pid = <2>; + mbox-names = "adsp_smem"; interrupts = ; label = "adsp"; @@ -947,6 +1058,9 @@ qcom,net-id = <1>; qcom,low-latency; }; + qcom,apr_tal_rpmsg { + qcom,smd-channels = "apr_audio_svc"; + }; }; rpm { @@ -1262,6 +1376,21 @@ qcom,has-vsys-adc-channel; }; + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-3P3-en-gpio = <&tlmm 47 0>; /* WCN3980_3P3_EN_*/ + qca,bt-1P3-en-gpio = <&tlmm 57 0>; /* WCN3980_1P3_EN */ + + qca,bt-vdd-xtal-supply = <&pm660_l12>; + qca,bt-vdd-io-supply = <&pm660_l13>; + + qca,bt-vdd-xtal-voltage-level = <1800000 1900000>; + qca,bt-vdd-io-voltage-level = <1800000 1900000>; + + qca,bt-vdd-xtal-current-level = <80000>; + qca,bt-vdd-io-current-level = <10000>; + }; + qcom,bam_dmux@4044000 { compatible = "qcom,bam_dmux"; reg = <0x4044000 0x19000>; @@ -1291,13 +1420,89 @@ interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,apps-ch-pipes = <0x600000>; qcom,ea-pc = <0x230>; - status = "disabled"; + status = "okay"; + + /* Slimbus Slave DT for WCN3980 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; }; + qcom,msm-adsp-loader { status = "ok"; compatible = "qcom,adsp-loader"; qcom,adsp-state = <0>; }; + + msm_cpufreq: qcom,msm-cpufreq { + compatible = "qcom,msm-cpufreq"; + clock-names = "cpu0_clk"; + clocks = <&cpu APCS_MUX_C1_CLK>; + + qcom,cpufreq-table = + < 960000 >, + < 1305600 >, + < 1497600 >, + < 1708800 >; + }; + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 211,8); /* 2265 MB/s */ + BW_OPP_ENTRY( 384, 8); /* 4539 MB/s */ + BW_OPP_ENTRY( 662, 8); /* 5416 MB/s */ + BW_OPP_ENTRY( 749, 8); + }; + + cpubw: qcom,cpubw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + com,cpu-bwmon { + compatible = "qcom,bimc-bwmon2"; + reg = <0x408000 0x300>, <0x401000 0x200>; + reg-names = "base", "global_base"; + interrupts = <0 183 4>; + qcom,mport = <0>; + qcom,target-dev = <&cpubw>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 960000 MHZ_TO_MBPS( 211, 8) >, + < 1305600 MHZ_TO_MBPS( 384, 8) >, + < 1497600 MHZ_TO_MBPS( 662, 8) >, + < 1708800 MHZ_TO_MBPS( 749, 8) >; + }; + + tsens0: tsens@4a8000 { + compatible = "qcom,msm8937-tsens"; + reg = <0x4a8000 0x1000>, + <0x4a9000 0x1000>, + <0xa4000 0x1000>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical", "tsens_eeprom_physical"; + interrupts = <0 184 0>; + interrupt-names = "tsens-upper-lower"; + #thermal-sensor-cells = <1>; + }; }; #include "sdm429-gdsc.dtsi" @@ -1305,6 +1510,8 @@ #include "sdm429w-regulator.dtsi" #include "sdm429-mdss.dtsi" #include "sdm429-mdss-pll.dtsi" +#include "sdm429-audio.dtsi" +#include "sdm429-thermal.dtsi" &venus_gdsc { clock-names = "bus_clk", "core_clk"; @@ -1375,3 +1582,8 @@ clocks = <&gcc GCC_OXILI_GFX3D_CLK>; status = "okay"; }; + +&blsp2_uart2_hs { + status = "okay"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429w-bg-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-bg-pm660.dtsi index 5ceebb2c9b30cc71e33890691901495129f1aec5..21004c2dbc1d73e51da30cfdca1a7dbd7d5c1b14 100644 --- a/arch/arm64/boot/dts/qcom/sdm429w-bg-pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429w-bg-pm660.dtsi @@ -29,7 +29,3 @@ &pm660_fg { qcom,fg-disable-in-twm; }; - -&pm660_haptics { - qcom,haptics-ext-pin-twm; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi index 1cf4c8ad62a05c0aa3fce78bca48ec1f839e46ee..eb338f2af52fc4a37befe928bd37e37a39c3c8ef 100644 --- a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi @@ -122,7 +122,7 @@ qcom,fg-bmd-en-delay-ms = <300>; qcom,fg-force-load-profile; qcom,fg-jeita-thresholds = <0 20 45 60>; - status = "disabled"; + status = "ok"; }; &pm660_haptics { @@ -131,7 +131,6 @@ /delete-property/ qcom,lra-allow-variable-play; /delete-property/ qcom,lra-allow-variable-play-rate; qcom,actuator-type = "erm"; - qcom,ilim-ma = <400>; qcom,play-rate-us = <10000>; wf_0 { @@ -165,6 +164,8 @@ }; }; +#include + &thermal_zones { xo-therm-adc { polling-delay-passive = <0>; @@ -245,6 +246,164 @@ }; }; }; + + quiet-therm-step { + polling-delay-passive = <1000>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x51>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + quiet_batt_439_trip1: quiet-batt-trip1 { + temperature = <38000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_batt_439_trip2: quiet-batt-trip2 { + temperature = <40000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_batt_439_trip3: quiet-batt-trip3 { + temperature = <42000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_batt_439_trip4: quiet-batt-trip4 { + temperature = <44000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_modem_439_trip1: quiet-modem-trip0 { + temperature = <44000>; + hysteresis = <4000>; + type = "passive"; + }; + + quiet_modem_439_trip2: quiet-modem-trip1 { + temperature = <46000>; + hysteresis = <4000>; + type = "passive"; + }; + + quiet_batt_439_trip5: quiet-batt-trip5 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_modem_439_trip3: quiet-modem-trp3 { + temperature = <48000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_cpus_439_trip: quiet-cpus-trip { + temperature = <48000>; + hysteresis = <0>; + type = "passive"; + }; + + quiet_batt_439_trip6: quiet-batt-trip6 { + temperature = <55000>; + hysteresis = <2000>; + type = "passive"; + }; + + quiet_modem_439_trip4: quiet-modem-trip3 { + temperature = <55000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + skin_cpu0 { + trip = <&quiet_cpus_439_trip>; + /* throttle from fmax to 1497600KHz */ + cooling-device = <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu1 { + trip = <&quiet_cpus_439_trip>; + cooling-device = <&CPU1 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu2 { + trip = <&quiet_cpus_439_trip>; + cooling-device = <&CPU2 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu3 { + trip = <&quiet_cpus_439_trip>; + cooling-device = <&CPU3 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + modem_proc_lvl1 { + trip = <&quiet_modem_439_trip1>; + cooling-device = <&modem_proc 1 1>; + }; + + modem_proc_lvl2 { + trip = <&quiet_modem_439_trip4>; + cooling-device = <&modem_proc 3 3>; + }; + + modem_lvl1 { + trip = <&quiet_modem_439_trip2>; + cooling-device = <&modem_pa 1 1>; + }; + + modem_lvl2 { + trip = <&quiet_modem_439_trip3>; + cooling-device = <&modem_pa 2 2>; + }; + + modem_lvl3 { + trip = <&quiet_modem_439_trip4>; + cooling-device = <&modem_pa 3 3>; + }; + + battery_lvl1 { + trip = <&quiet_batt_439_trip1>; + cooling-device = <&pm660_charger 1 1>; + }; + + battery_lvl2 { + trip = <&quiet_batt_439_trip2>; + cooling-device = <&pm660_charger 2 2>; + }; + + battery_lvl3 { + trip = <&quiet_batt_439_trip3>; + cooling-device = <&pm660_charger 3 3>; + }; + + battery_lvl4 { + trip = <&quiet_batt_439_trip4>; + cooling-device = <&pm660_charger 4 4>; + }; + + battery_lvl5 { + trip = <&quiet_batt_439_trip5>; + cooling-device = <&pm660_charger 5 5>; + }; + + battery_lvl6 { + trip = <&quiet_batt_439_trip6>; + cooling-device = <&pm660_charger 6 6>; + }; + }; + }; }; &usb_otg { diff --git a/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi index e3c95e217f2101e92ca1a263ab714f2c0046412a..8d154467c1ec12a9ba146a2446e9fd1a4088780d 100644 --- a/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429w-regulator.dtsi @@ -56,7 +56,7 @@ qcom,use-voltage-level; }; - pm660_cx_cdev: regulator-cx-cdev { + pm660_cx_cdev: cx { compatible = "qcom,regulator-cooling-device"; regulator-cdev-supply = <&pm660_s1_floor_level>; regulator-levels = +#include #include "sdm660-mtp.dtsi" #include "sdm660-external-codec.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 86098aa8ccbabffb1a4a2b09c67a2ddfd28c550e..da9805d4cd816033dee6cb76f98a14229bcecd53 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -2121,13 +2121,12 @@ sdhc_1: sdhci@7c4000 { compatible = "qcom,sdhci-msm-v5"; - reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>; - reg-names = "hc_mem", "cmdq_mem"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>, <0x7C8000 0x8000>; + reg-names = "hc_mem", "cmdq_mem", "cmdq_ice"; interrupts = , ; interrupt-names = "hc_irq", "pwr_irq"; - sdhc-msm-crypto = <&sdcc1_ice>; qcom,bus-width = <8>; qcom,large-address-bus; @@ -2339,11 +2338,11 @@ ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; - reg = <0x1d84000 0x3000>; + reg = <0x1d84000 0x3000>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; interrupts = <0 265 0>; phys = <&ufsphy_mem>; phy-names = "ufsphy"; - ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <1>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ @@ -2631,8 +2630,16 @@ qcom,smem-id = <421>; qcom,signal-aop; qcom,minidump-id = <3>; + qcom,aux-minidump-ids = <4>; qcom,complete-ramdump; + qcom,msm-bus,name = "pil-modem"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 7000000>; + /* Inputs from mss */ interrupts-extended = <&pdc GIC_SPI 266 IRQ_TYPE_EDGE_RISING>, <&modem_smp2p_in 0 IRQ_TYPE_NONE>, diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi index f942b85415e757aeb49024546b6f1847ae83579e..d6eb08d068d18448f526b151bd294409f887a878 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-qupv3.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,6 +29,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -348,6 +349,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -616,6 +618,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_2_geni_se_cb: qcom,iommu_qupv3_2_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -871,6 +874,11 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + qcom,subsys-name = "slpi"; + clock-names = "corex", "core2x"; + clocks = <&clock_scc SCC_QUPV3_CORE_CLK>, + <&clock_scc SCC_QUPV3_2XCORE_CLK>; + status = "disabled"; iommu_qupv3_3_geni_se_cb: qcom,iommu_qupv3_3_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi index 9ad7c2c33df441e5f1fdb75866288f28fe82f2d0..1068389f58984a9fb3231831c35e859c2ee47dec 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi @@ -618,6 +618,7 @@ qcom,phy-index = <0>; qcom,bond-dual-ctrl = <1 0>; + qcom,bond-tri-ctrl = <2 0 1>; reg = <0xae90000 0x0dc>, <0xae90200 0x0c0>, @@ -653,13 +654,15 @@ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, <&mdss_dp0_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, - <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>, + <&mdss_dp2_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; clock-names = "core_aux_clk", "core_usb_ref_clk_src", "core_usb_ref_clk", "core_usb_pipe_clk", "link_clk", "link_iface_clk", "crypto_clk", "pixel_clk_rcg", "pixel_parent", "pixel1_clk_rcg", "pixel1_parent", - "strm0_pixel_clk", "strm1_pixel_clk"; + "strm0_pixel_clk", "strm1_pixel_clk", + "bond_pixel_parent"; qcom,phy-version = <0x420>; qcom,phy-mode = "dp"; @@ -766,13 +769,15 @@ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, <&mdss_dp1_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL2_CLK>, - <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>, + <&mdss_dp2_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; clock-names = "core_aux_clk", "core_usb_ref_clk_src", "core_usb_ref_clk", "core_usb_pipe_clk", "link_clk", "link_iface_clk", "crypto_clk", "pixel_clk_rcg", "pixel_parent", "pixel1_clk_rcg", "pixel1_parent", - "strm0_pixel_clk", "strm1_pixel_clk"; + "strm0_pixel_clk", "strm1_pixel_clk", + "bond_pixel_parent"; qcom,phy-version = <0x420>; qcom,phy-mode = "dp"; @@ -872,11 +877,13 @@ <&clock_dispcc DISP_CC_MDSS_EDP_LINK_INTF_CLK>, <&clock_dispcc DISP_CC_MDSS_EDP_PIXEL_CLK_SRC>, <&mdss_edp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, - <&clock_dispcc DISP_CC_MDSS_EDP_PIXEL_CLK>; + <&clock_dispcc DISP_CC_MDSS_EDP_PIXEL_CLK>, + <&mdss_dp2_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; clock-names = "core_aux_clk", "core_ref_clk", "link_clk", "link_iface_clk", "pixel_clk_rcg", "pixel_parent", - "strm0_pixel_clk"; + "strm0_pixel_clk", + "bond_pixel_parent"; qcom,phy-version = <0x500>; qcom,phy-mode = "edp"; @@ -895,6 +902,7 @@ qcom,dsc-feature-enable; qcom,fec-feature-enable; + qcom,widebus-enable; qcom,max-dp-dsc-blks = <2>; qcom,max-dp-dsc-input-width-pixs = <2048>; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index d417ff891224e8e8fe06ec759c221e1da26da266..405429ac83a7c89fcc83e8dec55cef61b15d9785 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -46,6 +46,7 @@ hsuart0 = &qupv3_se13_4uart; spi0 = &qupv3_se3_spi; i2c0 = &qupv3_se4_i2c; + i2c2 = &qupv3_se2_i2c; }; cpus { @@ -719,7 +720,7 @@ alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; reusable; alignment = <0x0 0x400000>; - size = <0x0 0x2800000>; + size = <0x0 0x3c00000>; linux,cma-default; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi index dd63984d819f03546ce8eef96255055d644c6437..d33b845500ae608c7b4fec033e27091dd684f085 100644 --- a/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi @@ -216,8 +216,8 @@ qcom,msm-dai-tdm-pri-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37120>; - qcom,msm-cpudai-tdm-group-num-ports = <1>; - qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-group-num-ports = <2>; + qcom,msm-cpudai-tdm-group-port-id = <36864 36866>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <0>; @@ -232,13 +232,18 @@ qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36866>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,msm-dai-tdm-pri-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37121>; - qcom,msm-cpudai-tdm-group-num-ports = <1>; - qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-group-num-ports = <2>; + qcom,msm-cpudai-tdm-group-port-id = <36865 36867>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; qcom,msm-cpudai-tdm-clk-internal = <1>; qcom,msm-cpudai-tdm-sync-mode = <0>; @@ -252,44 +257,61 @@ qcom,msm-cpudai-tdm-dev-id = <36865>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36867>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,msm-dai-tdm-sec-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37136>; - qcom,msm-cpudai-tdm-group-num-ports = <1>; - qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-group-num-ports = <2>; + qcom,msm-cpudai-tdm-group-port-id = <36880 36882>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; qcom,msm-cpudai-tdm-clk-internal = <1>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36880>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_sec_tdm_rx_1: qcom,msm-dai-q6-tdm-sec-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36882>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,msm-dai-tdm-sec-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37137>; - qcom,msm-cpudai-tdm-group-num-ports = <1>; - qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-group-num-ports = <2>; + qcom,msm-cpudai-tdm-group-port-id = <36881 36883>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; qcom,msm-cpudai-tdm-clk-internal = <1>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; qcom,msm-cpudai-tdm-data-out = <0>; qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36881>; qcom,msm-cpudai-tdm-data-align = <0>; }; + dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36883>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; }; qcom,msm-dai-mi2s { diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi index 0b2d3db10874dd7510cbeb9a422a313696aea238..7a313693678eccfef5e546835141a027dafdd505 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-aqc.dtsi @@ -96,72 +96,6 @@ }; }; -&pcie0_bus2_dev1_fn0 { - aquantia,aqc107@pcie0_bus2_dev1_fn0 { - reg = <0 0 0 0 0>; - - compatible = "aquantia,aqc-107"; - - pci-ids = - "1d6a:0001", - "1d6a:d107", - "1d6a:07b1", - "1d6a:87b1", - "1d6a:d108", - "1d6a:08b1", - "1d6a:88b1", - "1d6a:d109", - "1d6a:09b1", - "1d6a:89b1", - "1d6a:d100", - "1d6a:00b1", - "1d6a:80b1", - "1d6a:11b1", - "1d6a:91b1", - "1d6a:12b1", - "1d6a:92b1", - "1d6a:00c0", - "1d6a:04c0", - "1d6a:12c0", - "1d6a:14c0", - "1d6a:93c0", - "1d6a:94c0"; - - qcom,smmu; - - /* IOVA range is restricted to avoid conflicts with PCI BAR - * space, Q6 SMEM and IOVA spaces used by peripherals that are - * currently attached to IPA. - */ - qcom,smmu-iova-base = /bits/ 64 <0x80000000>; - qcom,smmu-iova-size = /bits/ 64 <0x0FE40000>; - - qcom,smmu-attr-atomic; - qcom,smmu-attr-fastmap; - - /* AQC IPA offload driver */ - qcom,rx-proxy = <&aqo_proxy_host>, - <&aqo_proxy_uc>; - qcom,rx-proxy-mode = "counter"; - - qcom,rx-ring-size = <4096>; - qcom,rx-buff-size = <2048>; - qcom,rx-int-mod-usecs = <64>; - - qcom,rx-gsi-mod-pc = <10>; - qcom,rx-gsi-mod-timer = <32>; - - qcom,tx-ring-size = <4096>; - qcom,tx-buff-size = <2048>; - qcom,tx-wrb-mod-pc = <25>; - - qcom,tx-gsi-mod-pc = <10>; - qcom,tx-gsi-mod-timer = <32>; - - qcom,use-pci-direct; - }; -}; - &pcie0_bus2_dev2_fn0 { aquantia,aqc107@pcie0_bus2_dev1_fn0 { reg = <0 0 0 0 0>; @@ -210,14 +144,14 @@ <&aqo_proxy_uc>; qcom,rx-proxy-mode = "counter"; - qcom,rx-ring-size = <4096>; + qcom,rx-ring-size = <512>; qcom,rx-buff-size = <2048>; qcom,rx-int-mod-usecs = <64>; qcom,rx-gsi-mod-pc = <10>; qcom,rx-gsi-mod-timer = <32>; - qcom,tx-ring-size = <4096>; + qcom,tx-ring-size = <512>; qcom,tx-buff-size = <2048>; qcom,tx-wrb-mod-pc = <25>; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi index 26204b4f6814ef485f04c9a11353f2863d411e00..589e790f9e78544aece936f8c190e9607a7d0ffc 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi @@ -38,7 +38,9 @@ <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_tx_1>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_sec_tdm_rx_1>, <&dai_sec_tdm_tx_1>, <&dai_sec_auxpcm>, <&incall2_record_rx>, <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", @@ -50,7 +52,9 @@ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36866", "msm-dai-q6-tdm.36867", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36882", "msm-dai-q6-tdm.36883", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi index aaf72774fa188354b99778c8c424eb87abde17d7..edba1fd6cdbb397160ef58b33abcec738df82986 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi @@ -1685,18 +1685,5 @@ bias-pull-down; }; }; - - wakeup_gpio_default: wakeup_gpio_default { - mux { - pins = "gpio22"; - function = "gpio"; - }; - - config { - pins = "gpio22"; - drive-strength = <2>; - bias-pull-down; - }; - }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-smp2p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f31c53b3506eac81de043cfe5bc7c14bf4026b3f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-smp2p.dtsi @@ -0,0 +1,132 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + qcom,smp2p-modem@17811008 { + compatible = "qcom,smp2p"; + reg = <0x17811008 0x4>; + qcom,remote-pid = <1>; + qcom,irq-bitmask = <0x4000>; + interrupts = ; + }; + + smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_in { + compatible = "qcom,smp2pgpio_test_smp2p_15_in"; + gpios = <&smp2pgpio_smp2p_15_in 0 0>; + }; + + smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_out { + compatible = "qcom,smp2pgpio_test_smp2p_15_out"; + gpios = <&smp2pgpio_smp2p_15_out 0 0>; + }; + + smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_in { + compatible = "qcom,smp2pgpio_test_smp2p_1_in"; + gpios = <&smp2pgpio_smp2p_1_in 0 0>; + }; + + smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_out { + compatible = "qcom,smp2pgpio_test_smp2p_1_out"; + gpios = <&smp2pgpio_smp2p_1_out 0 0>; + }; + + /* ssr - inbound entry from mss */ + smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to mss */ + smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - outbound entry to mss */ + smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - inbound entry from mss */ + smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts index 165a3275f2afaf9fc6e0af46e86ebd856bbf9fdb..271348b2067ac853a62dce55a1bae37d2d8ddc1c 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts @@ -22,6 +22,17 @@ qcom,board-id = <0x6010001 0x0>; }; +&soc { + qmi-tmd-devices { + modem { + modem_v2x: modem_v2x { + qcom,qmi-dev-name = "modem_v2x"; + #cooling-cells = <2>; + }; + }; + }; +}; + /* delete pm8150b nodes */ &thermal_zones { /delete-node/ pm8150b-wp-therm; @@ -35,6 +46,71 @@ /delete-node/ pm8150b-bcl-lvl1; /delete-node/ pm8150b-bcl-lvl2; /delete-node/ soc; + + /* update Tj thresholds */ + mdm-core-0-step { + trips { + active-config0 { + temperature = <95000>; + hysteresis = <5000>; + }; + + active-config1 { + temperature = <100000>; + hysteresis = <5000>; + }; + + active-config2 { + temperature = <105000>; + hysteresis = <5000>; + }; + }; + }; + + mdm-core-0-v2x-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + tj_v2x_config0: active-config0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config1: active-config1 { + temperature = <110000>; + hysteresis = <5000>; + type = "passive"; + }; + + tj_v2x_config2: active-config2 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj0_v2x_cdev { + trip = <&tj_v2x_config0>; + cooling-device = <&modem_v2x 1 1>; + }; + + modem_tj1_v2x_cdev { + trip = <&tj_v2x_config1>; + cooling-device = <&modem_v2x 2 2>; + }; + + modem_tj2_v2x_cdev { + trip = <&tj_v2x_config2>; + cooling-device = <&modem_v2x 3 3>; + }; + }; + }; }; &usb { @@ -79,3 +155,7 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; + +&mpss_adsp_mem { + reg = <0x90800000 0xf800000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2-ttp-cpe.dts b/arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-au-dsda.dts similarity index 75% rename from arch/arm64/boot/dts/qcom/sdxprairie-v2-ttp-cpe.dts rename to arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-au-dsda.dts index e8c478d1593b3cd32b1925f791eff77cef8ee2b5..8ed717eb02d4f2380f9806676675f58e1bf24949 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2-ttp-cpe.dts +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-au-dsda.dts @@ -15,10 +15,16 @@ #include "sdxprairie-v2-mtp-cpe.dtsi" / { - model = "Qualcomm Technologies, Inc. SDXPRAIRIE V2 TTP (CPE)"; - compatible = "qcom,sdxprairie-ttp", - "qcom,sdxprairie", "qcom,ttp"; + model = "Qualcomm Technologies, Inc. SDXPRAIRIE V2 AU DSDA"; + compatible = "qcom,sdxprairie-mtp", + "qcom,sdxprairie", "qcom,mtp"; qcom,board-id = <0x08010008 0x0>; }; +&usb { + extcon = <&vbus_detect>; +}; +&vbus_detect { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-le-cpe.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-le-cpe.dtsi index 0150fb2eef74e3d34838a775a220737386dd3da0..b078b9d38ef054fe747619aa75f9d51ab7713675 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-le-cpe.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2-mtp-le-cpe.dtsi @@ -37,3 +37,27 @@ status = "disabled"; }; }; + +&cnss_qca6390 { + status = "disabled"; +}; + +&ipa_hw { + qcom,use-ipa-in-mhi-mode; +}; + +&pcie0 { + status = "disabled"; +}; + +&pcie_ep { + status = "ok"; +}; + +&mhi_device { + status = "ok"; +}; + +&mhi_net_device { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 0edcac4c5c0cbde0041c24292b7b754a6adf289d..2345e0f6e9df6ec3b11949e2a9e9200506b2e364 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -264,7 +264,7 @@ reg-names = "wdt-base"; interrupts = <1 3 0>, <1 2 0>; qcom,bark-time = <11000>; - qcom,pet-time = <10000>; + qcom,pet-time = <9360>; qcom,wakeup-enable; }; @@ -480,6 +480,16 @@ qcom,smem-states = <&modem_smp2p_out 0>; qcom,smem-state-names = "qcom,force-stop"; + /* GPIO intput to mss */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>; + qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>; + + /* GPIO output to mss */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + status = "ok"; }; @@ -694,6 +704,12 @@ qcom,net-id = <3>; }; + eth_dev_qrtr: qcom,eth_dev_qrtr { + compatible = "qcom,qrtr-ethernet-dev"; + qcom,net-id = <4>; + qcom,low-latency; + }; + qcom,glinkpkt { compatible = "qcom,glinkpkt"; @@ -1443,7 +1459,7 @@ }; mtl_tx_setup: tx-queues-config { - snps,tx-queues-to-use = <5>; + snps,tx-queues-to-use = <4>; snps,tx-sched-sp; queue0 { snps,dcb-algorithm; @@ -1535,7 +1551,7 @@ qcom,arm-smmu; emac-phy-addr = <7>; reg = <0x20000 0x10000>, - <0x36000 0x100>, + <0x36000 0x4A>, <0xf100000 0x300000>; reg-names = "emac-base", "rgmii-base", "tlmm-central-base"; interrupts-extended = <&pdc 0 62 4>, <&pdc 0 60 4>, @@ -1597,10 +1613,6 @@ qcom,status-in-gpio = <&tlmm 64 0x00>; qcom,status-out-gpio = <&tlmm 63 0x00>; qcom,status-out2-gpio = <&tlmm 66 0x00>; - qcom,wakeup-gpio-in = <&tlmm 87 0x00>; - qcom,wakeup-gpio-out = <&tlmm 22 0x00>; - pinctrl-names = "default"; - pinctrl-0 = <&wakeup_gpio_default>; status = "disabled"; }; }; @@ -1619,6 +1631,7 @@ #include "sdxprairie-aqc.dtsi" #include "sdxprairie-thermal.dtsi" #include "sdxprairie-qcom-smmu.dtsi" +#include "sdxprairie-smp2p.dtsi" &gdsc_usb30 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi index f0acba4999048989b477496ee398739c589af4d6..7ce2aec6b3a8c810e75a765354fb92a06b9dc4a5 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -227,7 +227,7 @@ }; }; - qcom,cam_smmu { + cam_smmu: qcom,cam_smmu { compatible = "qcom,msm-cam-smmu"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index 51d0f1baab6d2010a90d423be96deedb9eb38775..02a8141a6fb009a45ee1e8071d6b945128ba7c71 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -1146,6 +1146,35 @@ }; }; + + gpio_jack_det_line_in { + jack_det_linein_default: jack_det_linein_default { + mux { + pins = "gpio1"; + function = "gpio"; + }; + config { + pins = "gpio1"; + bias-pull-up; /* pull up */ + input-enable; + }; + }; + }; + + gpio_jack_det_line_out { + jack_det_lineout_default: jack_det_lineout_default { + mux { + pins = "gpio60"; + function = "gpio"; + }; + config { + pins = "gpio60"; + bias-pull-up; /* pull up */ + input-enable; + }; + }; + }; + ter_i2s_sck_ws { ter_i2s_sck_sleep: ter_i2s_sck_sleep { mux { diff --git a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi index cc6dd19ab2270bcc681f20770f77dc7631ceeec0..4a013abe62e31b7289450d1023bc185981a39911 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,6 +32,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -147,6 +148,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -350,6 +352,11 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + qcom,subsys-name = "adsp"; + clock-names = "corex", "core2x"; + clocks = <&clock_scc SCC_QUPV3_CORE_CLK>, + <&clock_scc SCC_QUPV3_2XCORE_CLK>; + status = "disabled"; iommu_qupv3_2_geni_se_cb: qcom,iommu_qupv3_2_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index fae82d8413309f85275d4f3e6d5beb5f217f0e40..6822b9dc4ce06095d2770f03af165b7f40565733 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -651,7 +651,7 @@ alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0x2000000>; + size = <0 0x2800000>; linux,cma-default; }; }; @@ -1409,12 +1409,11 @@ sdhc_1: sdhci@7c4000 { compatible = "qcom,sdhci-msm-v5"; - reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>; - reg-names = "hc_mem", "cmdq_mem"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>, <0x7C8000 0x8000>; + reg-names = "hc_mem", "cmdq_mem", "cmdq_ice"; interrupts = <0 641 0>, <0 644 0>; interrupt-names = "hc_irq", "pwr_irq"; - sdhc-msm-crypto = <&sdcc1_ice>; qcom,bus-width = <8>; qcom,large-address-bus; @@ -1623,11 +1622,11 @@ ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; - reg = <0x1d84000 0x3000>; + reg = <0x1d84000 0x3000>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; interrupts = <0 265 0>; phys = <&ufsphy_mem>; phy-names = "ufsphy"; - ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <1>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ @@ -2428,6 +2427,7 @@ qcom,smem-id = <421>; qcom,signal-aop; qcom,minidump-id = <3>; + qcom,aux-minidump-ids = <4>; qcom,complete-ramdump; /* Inputs from mss */ diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi index c5bef86838eaff354b4b99db01581f724d331205..666fa3ffa8182f1f9fc3356caf1adeed3cc4488b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi @@ -316,7 +316,7 @@ }; }; - qcom,cam_smmu { + cam_smmu: qcom,cam_smmu { compatible = "qcom,msm-cam-smmu"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi index 90d7d8d911ecd59a86cb491cc2946f278e99bb35..99045e871fd0a847870c547a3978b18d5468464d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qupv3.dtsi @@ -20,6 +20,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -385,6 +386,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -713,6 +715,7 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + status = "ok"; iommu_qupv3_2_geni_se_cb: qcom,iommu_qupv3_2_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; @@ -981,6 +984,11 @@ qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; + qcom,subsys-name = "slpi"; + clock-names = "corex", "core2x"; + clocks = <&clock_scc SCC_QUPV3_CORE_CLK>, + <&clock_scc SCC_QUPV3_2XCORE_CLK>; + status = "disabled"; iommu_qupv3_3_geni_se_cb: qcom,iommu_qupv3_3_geni_se_cb { compatible = "qcom,qupv3-geni-se-cb"; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index bcc15b5f454eab49bcb1f25ec797f73205d24941..8428b869d76819c8adceb1c7b6cf5fb1fbc3f4d8 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2281,7 +2281,6 @@ reg = <0x1d87000 0xda8>; /* PHY regs */ reg-names = "phy_mem"; #phy-cells = <0>; - ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <2>; @@ -2297,11 +2296,11 @@ ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; - reg = <0x1d84000 0x2500>; + reg = <0x1d84000 0x2500>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; interrupts = <0 265 0>; phys = <&ufsphy_mem>; phy-names = "ufsphy"; - ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <2>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ diff --git a/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi b/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi index e991d4159b1af129a894d6b7626b30201e7b41b1..3c46db0a9c7b54e5f740bf1dde9adf470f5cea54 100644 --- a/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-coresight.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2219,6 +2219,7 @@ coresight-name = "coresight-cti-gpu_isdb_cti"; + status = "disabled"; clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, <&clock_gpucc GPU_CC_CX_APB_CLK>; clock-names = "apb_pclk", "gpu_apb_clk"; diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 885cd4ea3d3b57f1e5fb059945dabc6732943e61..56e6526205416f893a2ad7afa7504e0ecf1c7b88 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -12,12 +12,14 @@ CONFIG_IKCONFIG_PROC=y CONFIG_IKHEADERS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y # CONFIG_PROC_PID_CPUSET is not set CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y CONFIG_DEFAULT_USE_ENERGY_AWARE=y @@ -26,7 +28,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set -# CONFIG_RD_LZ4 is not set CONFIG_SGETMASK_SYSCALL=y # CONFIG_SYSFS_SYSCALL is not set CONFIG_KALLSYMS_ALL=y @@ -37,7 +38,6 @@ CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set # CONFIG_SLAB_MERGE_DEFAULT is not set CONFIG_PROFILING=y -CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_LTO_CLANG=y @@ -47,6 +47,8 @@ CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PCI=y CONFIG_PCI_HOST_GENERIC=y CONFIG_PREEMPT=y @@ -67,6 +69,9 @@ CONFIG_RANDOMIZE_BASE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_MISC=y CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y @@ -219,6 +224,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y @@ -300,6 +306,8 @@ CONFIG_SERIAL_DEV_BUS=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y # CONFIG_HW_RANDOM_CAVIUM is not set +CONFIG_TCG_TPM=y +CONFIG_TCG_VTPM_PROXY=y # CONFIG_DEVPORT is not set # CONFIG_I2C_COMPAT is not set # CONFIG_I2C_HELPER_AUTO is not set @@ -353,6 +361,7 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y @@ -413,6 +422,7 @@ CONFIG_MAILBOX=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_LIBNVDIMM=y # CONFIG_ND_BLK is not set CONFIG_ARM_SCPI_PROTOCOL=y @@ -423,6 +433,7 @@ CONFIG_EXT4_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y # CONFIG_DNOTIFY is not set @@ -439,6 +450,7 @@ CONFIG_SDCARD_FS=y CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_RAM=y +CONFIG_UNICODE=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y # CONFIG_ENABLE_MUST_CHECK is not set @@ -451,17 +463,22 @@ CONFIG_SOFTLOCKUP_DETECTOR=y # CONFIG_DETECT_HUNG_TASK is not set CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y +CONFIG_DEBUG_LIST=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ENABLE_DEFAULT_TRACERS=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_TEST_MEMINIT=y +CONFIG_TEST_STACKINIT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=65536 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y +CONFIG_INIT_STACK_ALL=y +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y CONFIG_CRYPTO_ADIANTUM=y CONFIG_CRYPTO_LZ4=y CONFIG_CRYPTO_ZSTD=y CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_CRYPTO_DEV_VIRTIO=y +# CONFIG_CRYPTO_DEV_VIRTIO is not set CONFIG_XZ_DEC=y diff --git a/arch/arm64/configs/vendor/atoll-perf_defconfig b/arch/arm64/configs/vendor/atoll-perf_defconfig index 79f67c9a835014bd06b92d628ec70f587e950f4b..1298d7b34fba69d580e23f717e8336a0da2c31b2 100644 --- a/arch/arm64/configs/vendor/atoll-perf_defconfig +++ b/arch/arm64/configs/vendor/atoll-perf_defconfig @@ -17,18 +17,17 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -39,6 +38,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -48,11 +48,12 @@ CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_ARCH_QCOM=y @@ -78,6 +79,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set @@ -245,6 +247,7 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -279,7 +282,8 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -292,6 +296,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_SKY2=y CONFIG_RMNET=y CONFIG_SMSC911X=y @@ -319,6 +324,8 @@ CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ATMEL_MXT=y CONFIG_TOUCHSCREEN_ST=y @@ -452,10 +459,10 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y CONFIG_HID_QVR=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -505,8 +512,9 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y +CONFIG_MMC_CQ_HCI_CRYPTO=y +CONFIG_MMC_CQ_HCI_CRYPTO_QTI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y @@ -635,6 +643,8 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y CONFIG_QCOM_CX_IPEAK=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -658,6 +668,7 @@ CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_QCOM_QFPROM=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y @@ -669,18 +680,21 @@ CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -696,6 +710,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_CORESIGHT=y @@ -710,22 +725,20 @@ CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/atoll_defconfig b/arch/arm64/configs/vendor/atoll_defconfig index b3b4b1bb63ddbf352318f51d6864dec42b5f5933..f60a0c9906ed3e2d0cf8a52ad43e577fef3f7490 100644 --- a/arch/arm64/configs/vendor/atoll_defconfig +++ b/arch/arm64/configs/vendor/atoll_defconfig @@ -16,12 +16,12 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y @@ -29,7 +29,6 @@ CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -41,6 +40,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -50,12 +50,13 @@ CONFIG_KPROBES=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_CFQ_GROUP_IOSCHED=y @@ -84,6 +85,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_KRYO_PMU_WORKAROUND=y @@ -253,6 +255,7 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -289,8 +292,9 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -303,6 +307,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_RMNET=y CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y @@ -329,6 +334,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ATMEL_MXT=y CONFIG_TOUCHSCREEN_ST=y @@ -467,10 +473,10 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y CONFIG_HID_QVR=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -521,8 +527,9 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y +CONFIG_MMC_CQ_HCI_CRYPTO=y +CONFIG_MMC_CQ_HCI_CRYPTO_QTI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y @@ -663,6 +670,8 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y CONFIG_QCOM_CX_IPEAK=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -688,6 +697,7 @@ CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_QCOM_QFPROM=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y @@ -700,18 +710,21 @@ CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -797,23 +810,21 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/debugfs.config b/arch/arm64/configs/vendor/debugfs.config new file mode 100644 index 0000000000000000000000000000000000000000..059013b6a88ad5f04baff671ae526dcf03bf7547 --- /dev/null +++ b/arch/arm64/configs/vendor/debugfs.config @@ -0,0 +1,2 @@ +CONFIG_PAGE_OWNER=n +CONFIG_DEBUG_FS=n diff --git a/arch/arm64/configs/vendor/gen3auto-capture_defconfig b/arch/arm64/configs/vendor/gen3auto-capture_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..db99f7087d9e0657e1125141b82503dec36c3236 --- /dev/null +++ b/arch/arm64/configs/vendor/gen3auto-capture_defconfig @@ -0,0 +1,744 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_DEBUG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_DEBUG=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y +CONFIG_PANIC_ON_REFCOUNT_ERROR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SM8150=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +CONFIG_CRASH_DUMP=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_PRINT_VMEMLAYOUT=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_VLAN=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_VLAN_8021Q=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_QCOM=y +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_BOW=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AQFWD=y +CONFIG_ATLFWD_FWD=y +CONFIG_AQFWD_QCOM=y +CONFIG_RMNET=y +CONFIG_MICREL_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y +CONFIG_USB_USBNET=y +CONFIG_WIL6210=m +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS2=y +CONFIG_CNSS2_DEBUG=y +CONFIG_CNSS2_QMI=y +CONFIG_CNSS_ASYNC=y +CONFIG_CNSS_GENL=y +CONFIG_NVM=y +CONFIG_NVM_RRPC=y +CONFIG_NVM_PBLK=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=y +CONFIG_HVC_DCC=y +CONFIG_HVC_DCC_SERIALIZE_SMP=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_PM8150_PMIC_SIMULATOR=y +CONFIG_PM8150B_PMIC_SIMULATOR=y +CONFIG_PM8150L_PMIC_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SM8150=y +CONFIG_PINCTRL_SLPI=y +CONFIG_GPIO_SYSFS=y +CONFIG_GNSS_SIRF=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_SMB5=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_AIS=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +# CONFIG_DSI_PARSER is not set +CONFIG_DRM_SDE_SHD=y +CONFIG_DRM_SDE_SHP=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_DRM_MSM_LEASE=y +CONFIG_DRM_ANALOGIX_ANX7625=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_EDAC_QCOM_LLCC=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_QCOM_PCI_EDMA=y +CONFIG_QCOM_PCI_EDMA_DEBUG=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_EP_PCIE=y +CONFIG_EP_PCIE_HW=y +CONFIG_USB_BAM=y +CONFIG_MSM_MHI_DEV=y +CONFIG_IPA3=y +CONFIG_IPA_DEBUG=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_MSM_11AD=m +CONFIG_QCOM_MDSS_PLL=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SM8150=y +CONFIG_MSM_NPUCC_SM8150=y +CONFIG_MSM_SCC_SM8150=y +CONFIG_MSM_VIDEOCC_SM8150=y +CONFIG_MSM_CAMCC_SM8150=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_DISPCC_SM8150=y +CONFIG_MSM_DEBUGCC_SM8150=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_GPUCC_SM8150=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y +CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_IIO_ST_ASM330LHH=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_QCOM_QFPROM=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_DEBUG_SECTION_MISMATCH=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=-1 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_LOCK_TORTURE_TEST=m +CONFIG_DEBUG_SG=y +CONFIG_DEBUG_NOTIFIERS=y +CONFIG_DEBUG_CREDENTIALS=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_PREEMPTIRQ_EVENTS=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=m +CONFIG_ATOMIC64_SELFTEST=m +CONFIG_TEST_USER_COPY=m +CONFIG_MEMTEST=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_XZ_DEC=y diff --git a/arch/arm64/configs/vendor/gen3auto-perf_defconfig b/arch/arm64/configs/vendor/gen3auto-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..186548b8bb69c54cb821d92a3bced82b419ff4fb --- /dev/null +++ b/arch/arm64/configs/vendor/gen3auto-perf_defconfig @@ -0,0 +1,672 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SM8150=y +CONFIG_ARCH_SDMSHRIKE=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_HIBERNATION=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_VLAN=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_VLAN_8021Q=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_QCOM=y +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_BOW=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AQFWD=y +CONFIG_ATLFWD_FWD=y +CONFIG_AQFWD_QCOM=y +CONFIG_SKY2=y +CONFIG_RMNET=y +CONFIG_SMSC911X=y +CONFIG_MICREL_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y +CONFIG_USB_USBNET=y +CONFIG_WIL6210=m +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS2=y +CONFIG_CNSS2_DEBUG=y +CONFIG_CNSS2_QMI=y +CONFIG_CNSS_ASYNC=y +CONFIG_CNSS_GENL=y +CONFIG_NVM=y +CONFIG_NVM_RRPC=y +CONFIG_NVM_PBLK=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_PM8150_PMIC_SIMULATOR=y +CONFIG_PM8150B_PMIC_SIMULATOR=y +CONFIG_PM8150L_PMIC_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SM8150=y +CONFIG_PINCTRL_SDMSHRIKE=y +CONFIG_PINCTRL_SLPI=y +CONFIG_GPIO_SYSFS=y +CONFIG_GNSS_SIRF=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y +CONFIG_QPNP_SMB5=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L2_LOOPBACK=m +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_AIS=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m +CONFIG_DRM=y +# CONFIG_DRM_MSM is not set +CONFIG_DRM_ANALOGIX_ANX7625=y +CONFIG_FB_ARMCLCD=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_EDAC_QCOM_LLCC=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_PCI_EDMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_EP_PCIE=y +CONFIG_EP_PCIE_HW=y +CONFIG_USB_BAM=y +CONFIG_MSM_MHI_DEV=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_MSM_11AD=m +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SM8150=y +CONFIG_MSM_NPUCC_SM8150=y +CONFIG_MSM_SCC_SM8150=y +CONFIG_MSM_VIDEOCC_SM8150=y +CONFIG_MSM_CAMCC_SM8150=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_DISPCC_SM8150=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_GPUCC_SM8150=y +CONFIG_MSM_GCC_SDMSHRIKE=y +CONFIG_MSM_CAMCC_SDMSHRIKE=y +CONFIG_MSM_DEBUGCC_SDMSHRIKE=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_SDMSHRIKE_LLCC=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_BOOT_TIME_MARKER=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y +CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_DRM_TECHPACK=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_IIO_ST_ASM330LHH=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_QCOM_QFPROM=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y diff --git a/arch/arm64/configs/vendor/gen3auto_defconfig b/arch/arm64/configs/vendor/gen3auto_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..80c473bb6fddbe3011ea9b9d17a876a7c6171314 --- /dev/null +++ b/arch/arm64/configs/vendor/gen3auto_defconfig @@ -0,0 +1,774 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_DEBUG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_DEBUG=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y +CONFIG_PANIC_ON_REFCOUNT_ERROR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SM8150=y +CONFIG_ARCH_SDMSHRIKE=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_PRINT_VMEMLAYOUT=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_HIBERNATION=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_VLAN=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_VLAN_8021Q=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_QCOM=y +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_BOW=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_AQFWD=y +CONFIG_ATLFWD_FWD=y +CONFIG_AQFWD_QCOM=y +CONFIG_RMNET=y +CONFIG_MICREL_PHY=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y +CONFIG_USB_USBNET=y +CONFIG_WIL6210=m +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS2=y +CONFIG_CNSS2_DEBUG=y +CONFIG_CNSS2_QMI=y +CONFIG_CNSS_ASYNC=y +CONFIG_CNSS_GENL=y +CONFIG_NVM=y +CONFIG_NVM_RRPC=y +CONFIG_NVM_PBLK=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_PM8150_PMIC_SIMULATOR=y +CONFIG_PM8150B_PMIC_SIMULATOR=y +CONFIG_PM8150L_PMIC_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SM8150=y +CONFIG_PINCTRL_SDMSHRIKE=y +CONFIG_PINCTRL_SLPI=y +CONFIG_GPIO_SYSFS=y +CONFIG_GNSS_SIRF=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y +CONFIG_QPNP_SMB5=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L2_LOOPBACK=m +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_AIS=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m +CONFIG_DRM=y +# CONFIG_DRM_MSM is not set +# CONFIG_DSI_PARSER is not set +CONFIG_DRM_ANALOGIX_ANX7625=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_EDAC_QCOM_LLCC=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_QCOM_PCI_EDMA=y +CONFIG_QCOM_PCI_EDMA_DEBUG=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_EP_PCIE=y +CONFIG_EP_PCIE_HW=y +CONFIG_USB_BAM=y +CONFIG_MSM_MHI_DEV=y +CONFIG_IPA3=y +CONFIG_IPA_DEBUG=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_MSM_11AD=m +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SM8150=y +CONFIG_MSM_NPUCC_SM8150=y +CONFIG_MSM_SCC_SM8150=y +CONFIG_MSM_VIDEOCC_SM8150=y +CONFIG_MSM_CAMCC_SM8150=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_DISPCC_SM8150=y +CONFIG_MSM_DEBUGCC_SM8150=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_GPUCC_SM8150=y +CONFIG_MSM_GCC_SDMSHRIKE=y +CONFIG_MSM_CAMCC_SDMSHRIKE=y +CONFIG_MSM_DEBUGCC_SDMSHRIKE=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_SDMSHRIKE_LLCC=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_BOOT_TIME_MARKER=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y +CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_DRM_TECHPACK=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_IIO_ST_ASM330LHH=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_QCOM_QFPROM=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_DEBUG=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_ESOC_MDM_DBG_ENG=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_DEBUG_SECTION_MISMATCH=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK_PANIC_ON_BUG=y +CONFIG_PROVE_LOCKING=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_LOCK_TORTURE_TEST=m +CONFIG_DEBUG_SG=y +CONFIG_DEBUG_NOTIFIERS=y +CONFIG_DEBUG_CREDENTIALS=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=m +CONFIG_ATOMIC64_SELFTEST=m +CONFIG_TEST_USER_COPY=m +CONFIG_MEMTEST=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_TGU=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_XZ_DEC=y diff --git a/arch/arm64/configs/vendor/qcs403-perf_defconfig b/arch/arm64/configs/vendor/qcs403-perf_defconfig index bf405ee3c748521026863410b50bc134e78b00b8..c30b99e11678b1e2276e8181a0db09951b46b50a 100644 --- a/arch/arm64/configs/vendor/qcs403-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs403-perf_defconfig @@ -408,7 +408,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -550,5 +549,4 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/qcs403_defconfig b/arch/arm64/configs/vendor/qcs403_defconfig index 5cc12640652cda7c55a9c678b410bfc980563cf6..4d1ebdb00b841dd2d7b286cd566fa460b1218bff 100644 --- a/arch/arm64/configs/vendor/qcs403_defconfig +++ b/arch/arm64/configs/vendor/qcs403_defconfig @@ -422,7 +422,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -600,4 +599,3 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm64/configs/vendor/qcs405-perf_defconfig b/arch/arm64/configs/vendor/qcs405-perf_defconfig index 969733cf1aae32f8f9e376bd08899f1d4dd2865a..433dcaf105f1cd7474d96cc91c08d43f7c8e6e51 100644 --- a/arch/arm64/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs405-perf_defconfig @@ -408,7 +408,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -436,6 +435,7 @@ CONFIG_HWSPINLOCK_QCOM=y CONFIG_ARM_ARCH_TIMER_VCT_ACCESS=y CONFIG_MAILBOX=y CONFIG_QCOM_APCS_IPC=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y @@ -550,5 +550,4 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/qcs405_defconfig b/arch/arm64/configs/vendor/qcs405_defconfig index 9560912924fd4b9e3a23978b7447b64733e5c1e9..0dac911cb584cede530db3e5f0c513f66d8fdc7f 100644 --- a/arch/arm64/configs/vendor/qcs405_defconfig +++ b/arch/arm64/configs/vendor/qcs405_defconfig @@ -421,7 +421,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -449,6 +448,7 @@ CONFIG_HWSPINLOCK_QCOM=y CONFIG_ARM_ARCH_TIMER_VCT_ACCESS=y CONFIG_MAILBOX=y CONFIG_QCOM_APCS_IPC=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y @@ -599,4 +599,3 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm64/configs/vendor/qcs610-minimal-perf_defconfig b/arch/arm64/configs/vendor/qcs610-minimal-perf_defconfig index 159b155d5142c4c03047c03209a2a01c7d226daa..ae508a225e02a99180460fc687c0e6192f4074b9 100644 --- a/arch/arm64/configs/vendor/qcs610-minimal-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs610-minimal-perf_defconfig @@ -265,7 +265,6 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -426,7 +425,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -563,8 +561,6 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y @@ -599,7 +595,6 @@ CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y @@ -615,7 +610,6 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig index eae30c1b4fb02d0536b7f3ce01792cffac453a86..4368321f97483d464ad418668f0308847d4ad878 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig @@ -463,6 +463,7 @@ CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y CONFIG_QCOM_HGSL_TCSR_SIGNAL=y CONFIG_QCOM_HGSL=y +CONFIG_RENAME_BLOCK_DEVICE=y CONFIG_PM_DEVFREQ=y CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_EXTCON_USB_GPIO=y @@ -472,8 +473,6 @@ CONFIG_ANDROID_BINDER_IPC=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y @@ -496,9 +495,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=-1 CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set -CONFIG_PFK=y -CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y -CONFIG_PFK_VIRTUALIZED=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig index 1559e097deeb37f8e388461c7702738c1da3b17d..fe39b2f6d43c622d6bebbd331bbd995ada0b9600 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig @@ -474,6 +474,7 @@ CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y CONFIG_QCOM_HGSL_TCSR_SIGNAL=y CONFIG_QCOM_HGSL=y +CONFIG_RENAME_BLOCK_DEVICE=y CONFIG_PM_DEVFREQ=y CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_EXTCON_USB_GPIO=y @@ -483,8 +484,6 @@ CONFIG_ANDROID_BINDER_IPC=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y @@ -540,9 +539,6 @@ CONFIG_ATOMIC64_SELFTEST=m CONFIG_TEST_USER_COPY=m CONFIG_MEMTEST=y CONFIG_PID_IN_CONTEXTIDR=y -CONFIG_PFK=y -CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y -CONFIG_PFK_VIRTUALIZED=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index 8949cf9519a04b6bf250a465c6720977b04442a7..d78c6d646281f007bf0c3ed38c30b8527cbf3d00 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -238,6 +238,9 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_DWMAC_IPQ806X is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_PPP=y @@ -276,11 +279,11 @@ CONFIG_I2C_MUX=y CONFIG_I2C_MSM_V2=y CONFIG_SPI=y CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y @@ -350,7 +353,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -492,5 +494,4 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index 1f8ddc2423f679c30aa8846486f7564be8f6863c..6194d3f50c3ffb71471311fe2768eec9b6c8391f 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -6,7 +6,6 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y @@ -20,7 +19,6 @@ CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_DEBUG=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set @@ -47,9 +45,7 @@ CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y CONFIG_NR_CPUS=4 CONFIG_PREEMPT=y -CONFIG_CLEANCACHE=y CONFIG_CMA=y -CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y # CONFIG_HARDEN_BRANCH_PREDICTOR is not set @@ -66,7 +62,6 @@ CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y @@ -187,7 +182,6 @@ CONFIG_BRIDGE_EBT_ARPREPLY=y CONFIG_BRIDGE_EBT_DNAT=y CONFIG_BRIDGE_EBT_SNAT=y CONFIG_L2TP=y -CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y CONFIG_L2TP_IP=y CONFIG_L2TP_ETH=y @@ -244,6 +238,9 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_DWMAC_IPQ806X is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_PPP=y @@ -282,15 +279,12 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y CONFIG_I2C_MSM_V2=y CONFIG_SPI=y -CONFIG_SPI_DEBUG=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y @@ -321,7 +315,6 @@ CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_STUB=y # CONFIG_RC_CORE is not set # CONFIG_VGA_ARB is not set -# CONFIG_DSI_PARSER is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -347,8 +340,6 @@ CONFIG_USB_MSM_SSPHY=y CONFIG_USB_QCOM_EMU_PHY=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_F_FS=y @@ -358,13 +349,11 @@ CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=m -CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -395,12 +384,10 @@ CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y -CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_RPM=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_MSM_RPM_SMD=y -CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y @@ -408,7 +395,6 @@ CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y -CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y @@ -421,7 +407,6 @@ CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y -CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y CONFIG_QTI_NOTIFY_SIDEBAND=y @@ -429,6 +414,7 @@ CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_MSM_JTAGV8=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_QCOM_SMCINVOKE=y @@ -458,7 +444,6 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y # CONFIG_PRINT_QUOTA_WARNING is not set CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y @@ -474,49 +459,19 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_PAGEALLOC=y -CONFIG_SLUB_DEBUG_PANIC_ON=y -CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_PAGE_POISONING=y CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y -CONFIG_DEBUG_OBJECTS=y -CONFIG_DEBUG_OBJECTS_FREE=y -CONFIG_DEBUG_OBJECTS_TIMERS=y -CONFIG_DEBUG_OBJECTS_WORK=y -CONFIG_DEBUG_OBJECTS_RCU_HEAD=y -CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y -CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 -CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y -CONFIG_DEBUG_STACK_USAGE=y -CONFIG_DEBUG_MEMORY_INIT=y CONFIG_PANIC_ON_RECURSIVE_FAULT=y CONFIG_PANIC_ON_OOPS=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_ATOMIC_SLEEP=y -CONFIG_FAULT_INJECTION=y -CONFIG_FAIL_PAGE_ALLOC=y -CONFIG_UFS_FAULT_INJECTION=y -CONFIG_FAULT_INJECTION_DEBUG_FS=y -CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_IPC_LOGGING=y -CONFIG_QCOM_RTB=y -CONFIG_QCOM_RTB_SEPARATE_CPUS=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_LKDTM=y CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y -CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_CTI=y @@ -524,8 +479,6 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y -CONFIG_CORESIGHT_REMOTE_ETM=y -CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y @@ -542,4 +495,4 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/sa2150p-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-perf_defconfig index 8999e9e723b141f13754508eca92f54872de1d49..3a0a2ed3cb337a4fa7522bf479de800c2e673108 100644 --- a/arch/arm64/configs/vendor/sa2150p-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-perf_defconfig @@ -290,6 +290,7 @@ CONFIG_I2C_MUX=y CONFIG_I2C_MSM_V2=y CONFIG_SPI=y CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y @@ -362,7 +363,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -439,6 +439,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -502,5 +503,4 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/sa2150p_defconfig b/arch/arm64/configs/vendor/sa2150p_defconfig index dc423314434cb9ccfc1cec2777f267fc1c5b00a1..4a65bc770fc53a3f8fcd3530c1e484a8aa8d918b 100644 --- a/arch/arm64/configs/vendor/sa2150p_defconfig +++ b/arch/arm64/configs/vendor/sa2150p_defconfig @@ -6,7 +6,6 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y @@ -20,7 +19,6 @@ CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_DEBUG=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set @@ -47,9 +45,7 @@ CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y CONFIG_NR_CPUS=4 CONFIG_PREEMPT=y -CONFIG_CLEANCACHE=y CONFIG_CMA=y -CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y # CONFIG_HARDEN_BRANCH_PREDICTOR is not set @@ -66,7 +62,6 @@ CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set -CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y @@ -187,7 +182,6 @@ CONFIG_BRIDGE_EBT_ARPREPLY=y CONFIG_BRIDGE_EBT_DNAT=y CONFIG_BRIDGE_EBT_SNAT=y CONFIG_L2TP=y -CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y CONFIG_L2TP_IP=y CONFIG_L2TP_ETH=y @@ -296,11 +290,9 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y CONFIG_I2C_MSM_V2=y CONFIG_SPI=y -CONFIG_SPI_DEBUG=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y -CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PINCTRL_QCS405=y @@ -333,7 +325,6 @@ CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_STUB=y # CONFIG_RC_CORE is not set # CONFIG_VGA_ARB is not set -# CONFIG_DSI_PARSER is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -359,8 +350,6 @@ CONFIG_USB_MSM_SSPHY=y CONFIG_USB_QCOM_EMU_PHY=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_F_FS=y @@ -370,13 +359,11 @@ CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=m -CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -407,12 +394,10 @@ CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y -CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_RPM=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_MSM_RPM_SMD=y -CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y @@ -420,7 +405,6 @@ CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y -CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y @@ -433,7 +417,6 @@ CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y -CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y CONFIG_QTI_NOTIFY_SIDEBAND=y @@ -441,6 +424,7 @@ CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_MSM_JTAGV8=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_QCOM_SMCINVOKE=y @@ -456,6 +440,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -469,7 +454,6 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y # CONFIG_PRINT_QUOTA_WARNING is not set CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y @@ -485,49 +469,19 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_PAGEALLOC=y -CONFIG_SLUB_DEBUG_PANIC_ON=y -CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_PAGE_POISONING=y CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y -CONFIG_DEBUG_OBJECTS=y -CONFIG_DEBUG_OBJECTS_FREE=y -CONFIG_DEBUG_OBJECTS_TIMERS=y -CONFIG_DEBUG_OBJECTS_WORK=y -CONFIG_DEBUG_OBJECTS_RCU_HEAD=y -CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y -CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 -CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y -CONFIG_DEBUG_STACK_USAGE=y -CONFIG_DEBUG_MEMORY_INIT=y CONFIG_PANIC_ON_RECURSIVE_FAULT=y CONFIG_PANIC_ON_OOPS=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_ATOMIC_SLEEP=y -CONFIG_FAULT_INJECTION=y -CONFIG_FAIL_PAGE_ALLOC=y -CONFIG_UFS_FAULT_INJECTION=y -CONFIG_FAULT_INJECTION_DEBUG_FS=y -CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_IPC_LOGGING=y -CONFIG_QCOM_RTB=y -CONFIG_QCOM_RTB_SEPARATE_CPUS=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_LKDTM=y CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y -CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_CTI=y @@ -535,8 +489,6 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y -CONFIG_CORESIGHT_REMOTE_ETM=y -CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y @@ -552,4 +504,4 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index e15c2f8b3418704b65be70618e9b83c2abb4f3cc..1a8b42da637a0fbffd3544bab4a19a72a1e298cb 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -52,6 +52,8 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_ARCH_QCOM=y @@ -278,9 +280,11 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -318,6 +322,7 @@ CONFIG_CNSS2=y CONFIG_CNSS2_DEBUG=y CONFIG_CNSS2_QMI=y CONFIG_CNSS_ASYNC=y +CONFIG_CNSS_UTILS=y CONFIG_CNSS_GENL=y CONFIG_NVM=y CONFIG_NVM_RRPC=y @@ -578,6 +583,8 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_DRM_TECHPACK=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_CDSP_RM=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -608,8 +615,7 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y @@ -632,7 +638,6 @@ CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -647,7 +652,6 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sa8155_defconfig b/arch/arm64/configs/vendor/sa8155_defconfig index cbcc183d8f090642f10f920191f7b15745b80d59..b7f96a3555da66837ad5630c0e065b67fd0d903d 100644 --- a/arch/arm64/configs/vendor/sa8155_defconfig +++ b/arch/arm64/configs/vendor/sa8155_defconfig @@ -54,6 +54,8 @@ CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_CFQ_GROUP_IOSCHED=y @@ -71,6 +73,7 @@ CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y +CONFIG_KEXEC=y # CONFIG_HARDEN_BRANCH_PREDICTOR is not set CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y @@ -289,10 +292,12 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -328,6 +333,7 @@ CONFIG_CNSS2=y CONFIG_CNSS2_DEBUG=y CONFIG_CNSS2_QMI=y CONFIG_CNSS_ASYNC=y +CONFIG_CNSS_UTILS=y CONFIG_CNSS_GENL=y CONFIG_NVM=y CONFIG_NVM_RRPC=y @@ -610,6 +616,8 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_DRM_TECHPACK=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_CDSP_RM=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -641,8 +649,7 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y @@ -729,7 +736,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -745,7 +751,6 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdm660-perf_defconfig b/arch/arm64/configs/vendor/sdm660-perf_defconfig index 072cd837bfb1effdac2a22535904d4f1a0665e04..699621a225bb965bc2dbea54e2f44095bd146aae 100644 --- a/arch/arm64/configs/vendor/sdm660-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm660-perf_defconfig @@ -279,13 +279,11 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -508,7 +506,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QTI_TRI_LED=y @@ -637,8 +634,6 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y @@ -675,7 +670,6 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -691,7 +685,6 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem" CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdm660_defconfig b/arch/arm64/configs/vendor/sdm660_defconfig index 695a5619c0e352278845a0c06f2ed2743be4cf06..901b1c3b70a7ab8b317dbab638ba13921d4233be 100644 --- a/arch/arm64/configs/vendor/sdm660_defconfig +++ b/arch/arm64/configs/vendor/sdm660_defconfig @@ -287,14 +287,12 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -522,7 +520,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QTI_TRI_LED=y @@ -668,8 +665,6 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y @@ -764,7 +759,6 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -781,7 +775,6 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_SYSTEM_TRUSTED_KEYS="verity.x509.pem" CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdmshrike-perf_defconfig b/arch/arm64/configs/vendor/sdmshrike-perf_defconfig index 1d6ef880eaa8a4e93d43c880e1f336213983615c..98a1c46dea3a4ab37ba85f960bb6fd0279bbf028 100644 --- a/arch/arm64/configs/vendor/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmshrike-perf_defconfig @@ -76,6 +76,7 @@ CONFIG_SETEND_EMULATION=y CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_WAKELOCKS=y diff --git a/arch/arm64/configs/vendor/sdmshrike_defconfig b/arch/arm64/configs/vendor/sdmshrike_defconfig index cb315f41648e6837f2b74aac95ba6171aaa1f208..5325e4aeb38e90af379aed20fc25411cdf7c035d 100644 --- a/arch/arm64/configs/vendor/sdmshrike_defconfig +++ b/arch/arm64/configs/vendor/sdmshrike_defconfig @@ -82,6 +82,7 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_WAKELOCKS=y @@ -284,7 +285,6 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y @@ -635,8 +635,6 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y @@ -715,7 +713,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -729,7 +726,6 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig index 3ed484a1a0c45aa6b6391533cddf3f460fe4811b..541777f5b2adec6b1efe07c8e753080d7a9b302c 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-auto-perf_defconfig @@ -280,7 +280,6 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -491,7 +490,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -641,8 +639,6 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y @@ -651,6 +647,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -668,7 +665,6 @@ CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -683,7 +679,6 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig b/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig index c7b325846756e98a8eb7377efebc39261eebf776..f806daee1e59309e0f9313b38401b68e02ab3ef5 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-auto_defconfig @@ -292,7 +292,6 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y @@ -513,7 +512,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -679,8 +677,6 @@ CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y @@ -689,6 +685,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -778,7 +775,6 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y @@ -794,7 +790,6 @@ CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index b8c0a33903e4df6095f7f2ad553a1d8020ae2929..825622c8c55ab6e8375bb4ab57845229741291ed 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -16,18 +16,17 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -38,6 +37,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -47,11 +47,12 @@ CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_ARCH_QCOM=y @@ -73,6 +74,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set @@ -240,6 +242,7 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -273,7 +276,8 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -287,6 +291,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_SKY2=y CONFIG_RMNET=y CONFIG_SMSC911X=y @@ -314,6 +319,8 @@ CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ST=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y @@ -436,10 +443,10 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y CONFIG_HID_QVR=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -491,8 +498,9 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y +CONFIG_MMC_CQ_HCI_CRYPTO=y +CONFIG_MMC_CQ_HCI_CRYPTO_QTI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y @@ -614,6 +622,8 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y CONFIG_QCOM_CX_IPEAK=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -637,6 +647,7 @@ CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_ESOC=y @@ -647,18 +658,21 @@ CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -674,6 +688,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_CORESIGHT=y @@ -688,22 +703,20 @@ CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 4c1c7996e8b004b3ae49718956372c17593f0ed1..f7c6eefdc4cd95955a39c682e6587acfdb1d005b 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -15,12 +15,12 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y @@ -28,7 +28,6 @@ CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -40,6 +39,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -48,12 +48,13 @@ CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_CFQ_GROUP_IOSCHED=y @@ -79,6 +80,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_KRYO_PMU_WORKAROUND=y @@ -248,6 +250,7 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -283,8 +286,9 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -298,6 +302,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_RMNET=y CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y @@ -324,6 +329,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ST=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y @@ -460,10 +466,10 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y CONFIG_HID_QVR=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -516,8 +522,9 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y +CONFIG_MMC_CQ_HCI_CRYPTO=y +CONFIG_MMC_CQ_HCI_CRYPTO_QTI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y @@ -650,6 +657,8 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y CONFIG_QCOM_CX_IPEAK=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -674,6 +683,7 @@ CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_ESOC=y @@ -685,18 +695,21 @@ CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -782,23 +795,21 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index d4ca9133d945924e1f9f37ac93b5d90961896f48..16fcd3c04a7fc392bf7a7ec45ad5a50dd40360bc 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -17,18 +17,17 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -39,6 +38,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -49,11 +49,12 @@ CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_ARCH_QCOM=y @@ -78,6 +79,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set @@ -249,6 +251,7 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y CONFIG_QRTR_FIFO=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -284,7 +287,8 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -298,6 +302,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_SKY2=y CONFIG_RMNET=y CONFIG_SMSC911X=y @@ -324,6 +329,8 @@ CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ST=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM=y @@ -445,11 +452,11 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y CONFIG_HID_QVR=y CONFIG_USB_HIDDEV=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -622,6 +629,8 @@ CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y CONFIG_QCOM_AOP_DDR_MESSAGING=y CONFIG_QCOM_AOP_DDRSS_COMMANDS=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_QCOM_HYP_CORE_CTL=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y @@ -645,6 +654,7 @@ CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_ESOC=y @@ -655,18 +665,21 @@ CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -682,6 +695,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=-1 CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_CORESIGHT=y @@ -697,23 +711,20 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y -CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index d4492644383bad38ecf55a86737736649a1fdfac..3a528fdee801cbc8eef9e50e92356154c6526f0f 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -16,12 +16,12 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y @@ -29,7 +29,6 @@ CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -41,6 +40,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -51,12 +51,13 @@ CONFIG_REFCOUNT_FULL=y CONFIG_PANIC_ON_REFCOUNT_ERROR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_CFQ_GROUP_IOSCHED=y @@ -85,6 +86,7 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y @@ -258,6 +260,7 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y CONFIG_QRTR_FIFO=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -296,8 +299,9 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -311,6 +315,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_RMNET=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y @@ -336,6 +341,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ST=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM=y @@ -461,11 +467,11 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y CONFIG_HID_QVR=y CONFIG_USB_HIDDEV=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -651,6 +657,8 @@ CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y CONFIG_QCOM_AOP_DDR_MESSAGING=y CONFIG_QCOM_AOP_DDRSS_COMMANDS=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y CONFIG_QCOM_HYP_CORE_CTL=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y @@ -675,6 +683,7 @@ CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_ESOC=y @@ -686,18 +695,21 @@ CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -783,24 +795,21 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y -CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/trinket-perf_defconfig b/arch/arm64/configs/vendor/trinket-perf_defconfig index 8b34e9fd3e20433dfc92f16419395e7196253254..67aea57b7d55574b45cc36bbd1b00a63b90bc495 100644 --- a/arch/arm64/configs/vendor/trinket-perf_defconfig +++ b/arch/arm64/configs/vendor/trinket-perf_defconfig @@ -17,18 +17,17 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -39,6 +38,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -47,7 +47,6 @@ CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y @@ -244,6 +243,7 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -279,11 +279,9 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y @@ -292,6 +290,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_RMNET=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y @@ -315,6 +314,8 @@ CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y @@ -454,9 +455,9 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -507,7 +508,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y @@ -629,20 +629,25 @@ CONFIG_QTI_MPM=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_QCOM_QFPROM=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -660,6 +665,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_CORESIGHT=y @@ -674,22 +680,20 @@ CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig index 714b5cfa7d80e1a8609a10b28b706729a7d893ab..65fa34db016b6c6a0b52389fb03a026fa784fc3e 100644 --- a/arch/arm64/configs/vendor/trinket_defconfig +++ b/arch/arm64/configs/vendor/trinket_defconfig @@ -16,12 +16,12 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y @@ -29,7 +29,6 @@ CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y -# CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -41,6 +40,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y @@ -49,7 +49,6 @@ CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y @@ -253,6 +252,7 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -289,12 +289,10 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y @@ -303,6 +301,7 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_VETH=y CONFIG_RMNET=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y @@ -327,6 +326,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y @@ -470,9 +470,9 @@ CONFIG_HID_ELECOM=y CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_PLANTRONICS=y CONFIG_HID_SONY=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -523,7 +523,6 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y @@ -661,20 +660,25 @@ CONFIG_PHY_XGENE=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_QCOM_QFPROM=y CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y @@ -761,23 +765,21 @@ CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y -CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index 5d08ab07df33b4f80db1b29c87c133ff64e0f05f..4ed869845a23bdf889aaaf2e326667f7e0201c88 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -37,7 +37,7 @@ void apply_alternatives(void *start, size_t length); " .byte 662b-661b\n" /* source len */ \ " .byte 664f-663f\n" /* replacement len */ -#define ALTINSTR_ENTRY_CB(feature,cb) \ +#define ALTINSTR_ENTRY_CB(feature, cb) \ " .word 661b - .\n" /* label */ \ " .word " __stringify(cb) "- .\n" /* callback */ \ " .hword " __stringify(feature) "\n" /* feature bit */ \ @@ -83,7 +83,7 @@ void apply_alternatives(void *start, size_t length); oldinstr "\n" \ "662:\n" \ ".pushsection .altinstructions,\"a\"\n" \ - ALTINSTR_ENTRY_CB(feature,cb) \ + ALTINSTR_ENTRY_CB(feature, cb) \ ".popsection\n" \ "663:\n\t" \ "664:\n\t" \ @@ -216,7 +216,7 @@ alternative_endif .macro user_alt, label, oldinstr, newinstr, cond 9999: alternative_insn "\oldinstr", "\newinstr", \cond - _ASM_EXTABLE 9999b, \label + _asm_extable 9999b, \label .endm /* diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 2b55aee7c051844b7ac705f75b85c62301748697..92f70a34c5e60ddc80d49f3c5c03862df18e321b 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -188,6 +188,11 @@ static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu) return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE); } +static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu) +{ + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SF); +} + static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu) { return (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT; diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h index 75ea4207975760f92a1b8d091a7e04b8c7dd0e7a..0240290cf7641fb5c3d331ede431c7f6b7fc3712 100644 --- a/arch/arm64/include/asm/kvm_mmio.h +++ b/arch/arm64/include/asm/kvm_mmio.h @@ -21,13 +21,11 @@ #include #include -/* - * This is annoying. The mmio code requires this, even if we don't - * need any decoding. To be fixed. - */ struct kvm_decode { unsigned long rt; bool sign_extend; + /* Witdth of the register accessed by the faulting instruction is 64-bits */ + bool sixty_four; }; void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data); diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 2d04e37fc114bddf6c610c9eba7c5968f88aced6..bbd30a860077e50352d3c12c8f0a1c21045b1280 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -227,7 +227,7 @@ static inline unsigned long kaslr_offset(void) ((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55)) #define untagged_addr(addr) ({ \ - u64 __addr = (__force u64)addr; \ + u64 __addr = (__force u64)(addr); \ __addr &= __untagged_addr(__addr); \ (__force __typeof__(addr))__addr; \ }) diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h index 60d02c81a3a2c02a6d41de1721a529a4881b507e..6b9c3025c8179c0aa2cb0629ec2e85116bd28864 100644 --- a/arch/arm64/include/asm/page.h +++ b/arch/arm64/include/asm/page.h @@ -32,6 +32,10 @@ extern void __cpu_copy_user_page(void *to, const void *from, extern void copy_page(void *to, const void *from); extern void clear_page(void *to); +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \ + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr) +#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE + #define clear_user_page(addr,vaddr,pg) __cpu_clear_user_page(addr, vaddr) #define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index ea73bdb278fdf521b81bb9c71b354006c2864520..fed87bc3177561810772efea584638695ca00df0 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -60,7 +60,9 @@ #ifndef CONFIG_BROKEN_GAS_INST #ifdef __ASSEMBLY__ -#define __emit_inst(x) .inst (x) +// The space separator is omitted so that __emit_inst(x) can be parsed as +// either an assembler directive or an assembler macro argument. +#define __emit_inst(x) .inst(x) #else #define __emit_inst(x) ".inst " __stringify((x)) "\n\t" #endif diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index a4dc115d765941afde81e9feed053d994e038fbe..092046704cbc90f620442f309d468ca0a48a3f5a 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -607,7 +607,7 @@ static struct undef_hook setend_hooks[] = { }, { /* Thumb mode */ - .instr_mask = 0x0000fff7, + .instr_mask = 0xfffffff7, .instr_val = 0x0000b650, .pstate_mask = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK), .pstate_val = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR), diff --git a/arch/arm64/kernel/cpu-reset.h b/arch/arm64/kernel/cpu-reset.h index d3c60c0c121b5831b5621df8cf7f089679f31fd0..8059439ebd56e8a4b2acae420922145c21c20819 100644 --- a/arch/arm64/kernel/cpu-reset.h +++ b/arch/arm64/kernel/cpu-reset.h @@ -16,7 +16,7 @@ void __cpu_soft_restart(unsigned long el2_switch, unsigned long entry, unsigned long arg0, unsigned long arg1, unsigned long arg2); -static inline void __noreturn cpu_soft_restart(unsigned long el2_switch, +static inline void __noreturn cpu_soft_restart_kexec(unsigned long el2_switch, unsigned long entry, unsigned long arg0, unsigned long arg1, unsigned long arg2) { diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 3cfc64d1060cd1e0d0294a3ad2211761bc064234..4a5eb4c57fe45db746efb494f9ff3def954ea63e 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -41,9 +41,7 @@ EXPORT_SYMBOL_GPL(elf_hwcap); #define COMPAT_ELF_HWCAP_DEFAULT \ (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ - COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ - COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ - COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\ + COMPAT_HWCAP_TLS|COMPAT_HWCAP_IDIV|\ COMPAT_HWCAP_LPAE) unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; unsigned int compat_elf_hwcap2 __read_mostly; @@ -1182,7 +1180,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { { /* FP/SIMD is not implemented */ .capability = ARM64_HAS_NO_FPSIMD, - .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .type = ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE, .min_field_value = 0, .matches = has_no_fpsimd, }, @@ -1233,17 +1231,30 @@ static const struct arm64_cpu_capabilities arm64_features[] = { {}, }; -#define HWCAP_CAP(reg, field, s, min_value, cap_type, cap) \ - { \ - .desc = #cap, \ - .type = ARM64_CPUCAP_SYSTEM_FEATURE, \ + +#define HWCAP_CPUID_MATCH(reg, field, s, min_value) \ .matches = has_cpuid_feature, \ .sys_reg = reg, \ .field_pos = field, \ .sign = s, \ .min_field_value = min_value, \ + +#define __HWCAP_CAP(name, cap_type, cap) \ + .desc = name, \ + .type = ARM64_CPUCAP_SYSTEM_FEATURE, \ .hwcap_type = cap_type, \ .hwcap = cap, \ + +#define HWCAP_CAP(reg, field, s, min_value, cap_type, cap) \ + { \ + __HWCAP_CAP(#cap, cap_type, cap) \ + HWCAP_CPUID_MATCH(reg, field, s, min_value) \ + } + +#define HWCAP_CAP_MATCH(match, cap_type, cap) \ + { \ + __HWCAP_CAP(#cap, cap_type, cap) \ + .matches = match, \ } static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { @@ -1276,8 +1287,35 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { {}, }; +#ifdef CONFIG_COMPAT +static bool compat_has_neon(const struct arm64_cpu_capabilities *cap, int scope) +{ + /* + * Check that all of MVFR1_EL1.{SIMDSP, SIMDInt, SIMDLS} are available, + * in line with that of arm32 as in vfp_init(). We make sure that the + * check is future proof, by making sure value is non-zero. + */ + u32 mvfr1; + + WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible()); + if (scope == SCOPE_SYSTEM) + mvfr1 = read_sanitised_ftr_reg(SYS_MVFR1_EL1); + else + mvfr1 = read_sysreg_s(SYS_MVFR1_EL1); + + return cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDSP_SHIFT) && + cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDINT_SHIFT) && + cpuid_feature_extract_unsigned_field(mvfr1, MVFR1_SIMDLS_SHIFT); +} +#endif + static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = { #ifdef CONFIG_COMPAT + HWCAP_CAP_MATCH(compat_has_neon, CAP_COMPAT_HWCAP, COMPAT_HWCAP_NEON), + HWCAP_CAP(SYS_MVFR1_EL1, MVFR1_SIMDFMAC_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv4), + /* Arm v8 mandates MVFR0.FPDP == {0, 2}. So, piggy back on this for the presence of VFP support */ + HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_FPDP_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFP), + HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_FPDP_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv3), HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL), HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES), HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1), diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index f4fdf6420ac5ca54145c004a223c0d502faaabd4..4cd962f6c4302a8763847f4c2178631709342a97 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -206,8 +206,19 @@ void fpsimd_preserve_current_state(void) */ void fpsimd_restore_current_state(void) { - if (!system_supports_fpsimd()) + /* + * For the tasks that were created before we detected the absence of + * FP/SIMD, the TIF_FOREIGN_FPSTATE could be set via fpsimd_thread_switch(), + * e.g, init. This could be then inherited by the children processes. + * If we later detect that the system doesn't support FP/SIMD, + * we must clear the flag for all the tasks to indicate that the + * FPSTATE is clean (as we can't have one) to avoid looping for ever in + * do_notify_resume(). + */ + if (!system_supports_fpsimd()) { + clear_thread_flag(TIF_FOREIGN_FPSTATE); return; + } local_bh_disable(); @@ -229,7 +240,7 @@ void fpsimd_restore_current_state(void) */ void fpsimd_update_current_state(struct fpsimd_state *state) { - if (!system_supports_fpsimd()) + if (WARN_ON(!system_supports_fpsimd())) return; local_bh_disable(); diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index 11121f608eb52718a3f490bb0eddec83486493ad..bfc4deac14455fcfd15a62e8b9612b666b2b8573 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -207,7 +207,7 @@ void machine_kexec(struct kimage *kimage) * relocation is complete. */ - cpu_soft_restart(kimage != kexec_crash_image, + cpu_soft_restart_kexec(kimage != kexec_crash_image, reboot_code_buffer_phys, kimage->head, kimage->start, 0); BUG(); /* Should never get here. */ diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index e0a80e230c5ee887e760e6fe3c23f934c4743ab5..e322a49a79a3376e38fda0762f7c962805dc34ed 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -264,12 +264,6 @@ static const unsigned armv8_a73_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, - - [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, - [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, - - [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, - [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, }; static const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index aa1d6377f992289459b67865a065a24fe3b43779..423a02bf0cde64df64de43c385df1b22e570373b 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -433,6 +433,13 @@ static void ssbs_thread_switch(struct task_struct *next) if (unlikely(next->flags & PF_KTHREAD)) return; + /* + * If all CPUs implement the SSBS extension, then we just need to + * context-switch the PSTATE field. + */ + if (cpu_have_feature(cpu_feature(SSBS))) + return; + /* If the mitigation is enabled, then we leave SSBS clear. */ if ((arm64_get_ssbd_state() == ARM64_SSBD_FORCE_ENABLE) || test_tsk_thread_flag(next, TIF_SSBD)) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 242527f29c410549ef75b9b6875e3d5ff3a28855..e8574b95bda8693a2652ed240ebe8448d19691be 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -624,6 +624,13 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, return 0; } +static int fpr_active(struct task_struct *target, const struct user_regset *regset) +{ + if (!system_supports_fpsimd()) + return -ENODEV; + return regset->n; +} + /* * TODO: update fp accessors for lazy context switching (sync/flush hwstate) */ @@ -634,6 +641,9 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, struct user_fpsimd_state *uregs; uregs = &target->thread.fpsimd_state.user_fpsimd; + if (!system_supports_fpsimd()) + return -EINVAL; + if (target == current) fpsimd_preserve_current_state(); @@ -648,6 +658,9 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, struct user_fpsimd_state newstate = target->thread.fpsimd_state.user_fpsimd; + if (!system_supports_fpsimd()) + return -EINVAL; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1); if (ret) return ret; @@ -740,6 +753,7 @@ static const struct user_regset aarch64_regsets[] = { */ .size = sizeof(u32), .align = sizeof(u32), + .active = fpr_active, .get = fpr_get, .set = fpr_set }, @@ -819,6 +833,7 @@ static int compat_gpr_get(struct task_struct *target, break; case 16: reg = task_pt_regs(target)->pstate; + reg = pstate_to_compat_psr(reg); break; case 17: reg = task_pt_regs(target)->orig_x0; @@ -886,6 +901,7 @@ static int compat_gpr_set(struct task_struct *target, newregs.pc = reg; break; case 16: + reg = compat_psr_to_pstate(reg); newregs.pstate = reg; break; case 17: @@ -914,6 +930,9 @@ static int compat_vfp_get(struct task_struct *target, compat_ulong_t fpscr; int ret, vregs_end_pos; + if (!system_supports_fpsimd()) + return -EINVAL; + uregs = &target->thread.fpsimd_state.user_fpsimd; if (target == current) @@ -947,6 +966,9 @@ static int compat_vfp_set(struct task_struct *target, compat_ulong_t fpscr; int ret, vregs_end_pos; + if (!system_supports_fpsimd()) + return -EINVAL; + uregs = &target->thread.fpsimd_state.user_fpsimd; vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t); @@ -1004,6 +1026,7 @@ static const struct user_regset aarch32_regsets[] = { .n = VFP_STATE_SIZE / sizeof(compat_ulong_t), .size = sizeof(compat_ulong_t), .align = sizeof(compat_ulong_t), + .active = fpr_active, .get = compat_vfp_get, .set = compat_vfp_set }, diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index e09bf5d1560606405e25175d69d8b67929f02657..3832750cee8b49d11a7a808cb2c30d8da780ef93 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -321,6 +321,7 @@ static int compat_restore_sigframe(struct pt_regs *regs, int err; sigset_t set; struct compat_aux_sigframe __user *aux; + unsigned long psr; err = get_sigset_t(&set, &sf->uc.uc_sigmask); if (err == 0) { @@ -344,7 +345,9 @@ static int compat_restore_sigframe(struct pt_regs *regs, __get_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err); __get_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err); __get_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err); - __get_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err); + __get_user_error(psr, &sf->uc.uc_mcontext.arm_cpsr, err); + + regs->pstate = compat_psr_to_pstate(psr); /* * Avoid compat_sys_sigreturn() restarting. @@ -500,6 +503,7 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { struct compat_aux_sigframe __user *aux; + unsigned long psr = pstate_to_compat_psr(regs->pstate); int err = 0; __put_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err); @@ -518,7 +522,7 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf, __put_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err); __put_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err); __put_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err); - __put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err); + __put_user_error(psr, &sf->uc.uc_mcontext.arm_cpsr, err); __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err); /* set the compat FSR WnR */ diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index da2d254004d3fb9650b59c5ad7fe6786f0f0c9a3..379ff1366ef2c1b320dd1bbbc1b61217b59da296 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -949,11 +949,22 @@ void tick_broadcast(const struct cpumask *mask) } #endif +/* + * The number of CPUs online, not counting this CPU (which may not be + * fully online and so not counted in num_online_cpus()). + */ +static inline unsigned int num_other_online_cpus(void) +{ + unsigned int this_cpu_online = cpu_online(smp_processor_id()); + + return num_online_cpus() - this_cpu_online; +} + void smp_send_stop(void) { unsigned long timeout; - if (num_online_cpus() > 1) { + if (num_other_online_cpus()) { cpumask_t mask; cpumask_copy(&mask, cpu_online_mask); @@ -990,13 +1001,17 @@ void crash_smp_send_stop(void) cpus_stopped = 1; - if (num_online_cpus() == 1) + /* + * If this cpu is the only one alive at this point in time, online or + * not, there are no stop messages to be sent around, so just back out. + */ + if (num_other_online_cpus() == 0) return; cpumask_copy(&mask, cpu_online_mask); cpumask_clear_cpu(smp_processor_id(), &mask); - atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + atomic_set(&waiting_for_crash_ipi, num_other_online_cpus()); pr_crit("SMP: stopping secondary CPUs\n"); smp_cross_call(&mask, IPI_CPU_CRASH_STOP); diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index 0bde47e4fa694264256c1e8d2498436acc66320b..dcba53803fa5f9867eba2a0178c48ee5ed924c20 100644 --- a/arch/microblaze/kernel/cpu/cache.c +++ b/arch/microblaze/kernel/cpu/cache.c @@ -92,7 +92,8 @@ static inline void __disable_dcache_nomsr(void) #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \ do { \ int align = ~(cache_line_length - 1); \ - end = min(start + cache_size, end); \ + if (start < UINT_MAX - cache_size) \ + end = min(start + cache_size, end); \ start &= align; \ } while (0) diff --git a/arch/mips/Makefile.postlink b/arch/mips/Makefile.postlink index 4eea4188cb204a2b789ef0bdb4d8ce11d4d201f4..13e0beb9eee3330a6107d5e9b0d0cd9156e2f184 100644 --- a/arch/mips/Makefile.postlink +++ b/arch/mips/Makefile.postlink @@ -12,7 +12,7 @@ __archpost: include scripts/Kbuild.include CMD_RELOCS = arch/mips/boot/tools/relocs -quiet_cmd_relocs = RELOCS $@ +quiet_cmd_relocs = RELOCS $@ cmd_relocs = $(CMD_RELOCS) $@ # `@true` prevents complaint when there is nothing to be done diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index b3aec101a65d4ed96f4f986ea22c2210b297cdef..a27b3d70393f7927c2206113ce49164e79c44c53 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -2199,6 +2199,9 @@ static int octeon_irq_cib_map(struct irq_domain *d, } cd = kzalloc(sizeof(*cd), GFP_KERNEL); + if (!cd) + return -ENOMEM; + cd->host_data = host_data; cd->bit = hw; diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 544ea21bfef9cdae6361c964d5cdd91c56f57c88..b2683aca401f61f84770317be2358065100f567a 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -134,7 +134,7 @@ void release_vpe(struct vpe *v) { list_del(&v->list); if (v->load_addr) - release_progmem(v); + release_progmem(v->load_addr); kfree(v); } diff --git a/arch/mips/loongson64/loongson-3/platform.c b/arch/mips/loongson64/loongson-3/platform.c index 25a97cc0ee33664f79f16e3ffb4d350a4b033dae..0db4cc3196ebdcc92b98791e139f652636b83c9f 100644 --- a/arch/mips/loongson64/loongson-3/platform.c +++ b/arch/mips/loongson64/loongson-3/platform.c @@ -31,6 +31,9 @@ static int __init loongson3_platform_init(void) continue; pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + pdev->name = loongson_sysconf.sensors[i].name; pdev->id = loongson_sysconf.sensors[i].id; pdev->dev.platform_data = &loongson_sysconf.sensors[i]; diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index de3b07c7be30b0970e2d0217d2538da2740b3255..277e4ffb928bc5f1bb8cc663ed9f8ac4c31fb84d 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -225,6 +225,7 @@ config PPC select MODULES_USE_ELF_RELA select NO_BOOTMEM select OF + select OF_DMA_DEFAULT_COHERENT if !NOT_COHERENT_CACHE select OF_EARLY_FLATTREE select OF_RESERVED_MEM select OLD_SIGACTION if PPC32 diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c index f7da651691249f30798f3f5dc0e4d569b6a0e45b..3c8774163c7ec684beeb6fb21d649d4d51ed1c1c 100644 --- a/arch/powerpc/boot/4xx.c +++ b/arch/powerpc/boot/4xx.c @@ -232,7 +232,7 @@ void ibm4xx_denali_fixup_memsize(void) dpath = 8; /* 64 bits */ /* get address pins (rows) */ - val = SDRAM0_READ(DDR0_42); + val = SDRAM0_READ(DDR0_42); row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT); if (row > max_row) diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h index 197ced1eaaa0932d59d214a469e25f53b79fa483..4a16115b47eb06bb0fc54fc8e775ae9499090a37 100644 --- a/arch/powerpc/include/asm/book3s/64/hash-4k.h +++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h @@ -108,6 +108,12 @@ extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm, extern int hash__has_transparent_hugepage(void); #endif +static inline pmd_t hash__pmd_mkdevmap(pmd_t pmd) +{ + BUG(); + return pmd; +} + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_BOOK3S_64_HASH_4K_H */ diff --git a/arch/powerpc/include/asm/book3s/64/hash-64k.h b/arch/powerpc/include/asm/book3s/64/hash-64k.h index 8d40cf03cb67d10a691bc2d0b92071dbccc0c8e8..2194866225f84b2422160a3d5b335e2e1fa37cb0 100644 --- a/arch/powerpc/include/asm/book3s/64/hash-64k.h +++ b/arch/powerpc/include/asm/book3s/64/hash-64k.h @@ -181,7 +181,7 @@ static inline void mark_hpte_slot_valid(unsigned char *hpte_slot_array, */ static inline int hash__pmd_trans_huge(pmd_t pmd) { - return !!((pmd_val(pmd) & (_PAGE_PTE | H_PAGE_THP_HUGE)) == + return !!((pmd_val(pmd) & (_PAGE_PTE | H_PAGE_THP_HUGE | _PAGE_DEVMAP)) == (_PAGE_PTE | H_PAGE_THP_HUGE)); } @@ -209,6 +209,12 @@ extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp); extern int hash__has_transparent_hugepage(void); #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +static inline pmd_t hash__pmd_mkdevmap(pmd_t pmd) +{ + return __pmd(pmd_val(pmd) | (_PAGE_PTE | H_PAGE_THP_HUGE | _PAGE_DEVMAP)); +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_POWERPC_BOOK3S_64_HASH_64K_H */ diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 4dd13b503dbbd8f265f271d4bcf7cd3761e84701..bcb79a96a6c836bd9b2c81ceb3579ed62e96befd 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -1179,7 +1179,9 @@ extern void serialize_against_pte_lookup(struct mm_struct *mm); static inline pmd_t pmd_mkdevmap(pmd_t pmd) { - return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_DEVMAP)); + if (radix_enabled()) + return radix__pmd_mkdevmap(pmd); + return hash__pmd_mkdevmap(pmd); } static inline int pmd_devmap(pmd_t pmd) diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index 19c44e1495aefe8b1170385f87e0877dedb92341..7a1fc49aaf99f36e9254a97e0e561010ee0fa720 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h @@ -289,6 +289,11 @@ extern pmd_t radix__pmdp_huge_get_and_clear(struct mm_struct *mm, extern int radix__has_transparent_hugepage(void); #endif +static inline pmd_t radix__pmd_mkdevmap(pmd_t pmd) +{ + return __pmd(pmd_val(pmd) | (_PAGE_PTE | _PAGE_DEVMAP)); +} + extern int __meminit radix__vmemmap_create_mapping(unsigned long start, unsigned long page_size, unsigned long phys); diff --git a/arch/powerpc/include/asm/setjmp.h b/arch/powerpc/include/asm/setjmp.h index 279d03a1eec625b12d93632ce7586796835bee97..6941fe202bc822b57ef115d2e51d97c8ed83e576 100644 --- a/arch/powerpc/include/asm/setjmp.h +++ b/arch/powerpc/include/asm/setjmp.h @@ -12,7 +12,9 @@ #define JMP_BUF_LEN 23 -extern long setjmp(long *); -extern void longjmp(long *, long); +typedef long jmp_buf[JMP_BUF_LEN]; + +extern int setjmp(jmp_buf env) __attribute__((returns_twice)); +extern void longjmp(jmp_buf env, int val) __attribute__((noreturn)); #endif /* _ASM_POWERPC_SETJMP_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 5607ce67d178b14c055f8918a18cae97ea19fbf8..681f966b7211d0bd8af7c750ddaf7bc527e37898 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -5,9 +5,6 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' -# Avoid clang warnings around longjmp/setjmp declarations -CFLAGS_crash.o += -ffreestanding - subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ifeq ($(CONFIG_PPC64),y) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index da4b0e37923802dad23a3dfe7316eb8b7d4e2cef..6ef41e823013fed8bf60c7f31d08cea2a588b5e7 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -2232,11 +2232,13 @@ static struct cpu_spec * __init setup_cpu_spec(unsigned long offset, * oprofile_cpu_type already has a value, then we are * possibly overriding a real PVR with a logical one, * and, in that case, keep the current value for - * oprofile_cpu_type. + * oprofile_cpu_type. Futhermore, let's ensure that the + * fix for the PMAO bug is enabled on compatibility mode. */ if (old.oprofile_cpu_type != NULL) { t->oprofile_cpu_type = old.oprofile_cpu_type; t->oprofile_type = old.oprofile_type; + t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG; } } diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 470284f9e4f6661f6716b0be1a78b14bae9f33b3..5a48c93aaa1b35b6bacb326fb65976ff8541af0a 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -520,12 +520,6 @@ static void *eeh_rmv_device(void *data, void *userdata) pci_iov_remove_virtfn(edev->physfn, pdn->vf_index, 0); edev->pdev = NULL; - - /* - * We have to set the VF PE number to invalid one, which is - * required to plug the VF successfully. - */ - pdn->pe_number = IODA_INVALID_PE; #endif if (rmv_data) list_add(&edev->rmv_list, &rmv_data->edev_list); diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index 74fc2043108261ebc183c270001a826ad846e5ae..01b823bdb49c2a4ff0a66e0e2b45722ba79014a8 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -163,8 +163,11 @@ core_idle_lock_held: bne- core_idle_lock_held blr -/* Reuse an unused pt_regs slot for IAMR */ +/* Reuse some unused pt_regs slots for AMR/IAMR/UAMOR/UAMOR */ +#define PNV_POWERSAVE_AMR _TRAP #define PNV_POWERSAVE_IAMR _DAR +#define PNV_POWERSAVE_UAMOR _DSISR +#define PNV_POWERSAVE_AMOR RESULT /* * Pass requested state in r3: @@ -198,8 +201,16 @@ pnv_powersave_common: SAVE_NVGPRS(r1) BEGIN_FTR_SECTION + mfspr r4, SPRN_AMR mfspr r5, SPRN_IAMR + mfspr r6, SPRN_UAMOR + std r4, PNV_POWERSAVE_AMR(r1) std r5, PNV_POWERSAVE_IAMR(r1) + std r6, PNV_POWERSAVE_UAMOR(r1) +BEGIN_FTR_SECTION_NESTED(42) + mfspr r7, SPRN_AMOR + std r7, PNV_POWERSAVE_AMOR(r1) +END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfcr r5 @@ -951,12 +962,20 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) REST_GPR(2, r1) BEGIN_FTR_SECTION - /* IAMR was saved in pnv_powersave_common() */ + /* These regs were saved in pnv_powersave_common() */ + ld r4, PNV_POWERSAVE_AMR(r1) ld r5, PNV_POWERSAVE_IAMR(r1) + ld r6, PNV_POWERSAVE_UAMOR(r1) + mtspr SPRN_AMR, r4 mtspr SPRN_IAMR, r5 + mtspr SPRN_UAMOR, r6 +BEGIN_FTR_SECTION_NESTED(42) + ld r7, PNV_POWERSAVE_AMOR(r1) + mtspr SPRN_AMOR, r7 +END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42) /* - * We don't need an isync here because the upcoming mtmsrd is - * execution synchronizing. + * We don't need an isync here after restoring IAMR because the upcoming + * mtmsrd is execution synchronizing. */ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 10b46b35c059fe0c01424e3e0b1b1d90260abb76..07d3f3b402463fad208abc9819c40092fe4f3ac7 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -279,6 +279,9 @@ int kprobe_handler(struct pt_regs *regs) if (user_mode(regs)) return 0; + if (!(regs->msr & MSR_IR) || !(regs->msr & MSR_DR)) + return 0; + /* * We don't want to be preempted for the entire * duration of kprobe processing diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index 0e395afbf0f498a89f2fd66a8f8b6ed74f381f24..0e45a446a8c78794e3035822db96f0d43657d8ee 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -261,9 +261,22 @@ void remove_dev_pci_data(struct pci_dev *pdev) continue; #ifdef CONFIG_EEH - /* Release EEH device for the VF */ + /* + * Release EEH state for this VF. The PCI core + * has already torn down the pci_dev for this VF, but + * we're responsible to removing the eeh_dev since it + * has the same lifetime as the pci_dn that spawned it. + */ edev = pdn_to_eeh_dev(pdn); if (edev) { + /* + * We allocate pci_dn's for the totalvfs count, + * but only only the vfs that were activated + * have a configured PE. + */ + if (edev->pe) + eeh_rmv_from_parent_pe(edev); + pdn->edev = NULL; kfree(edev); } diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 6ca1b3a1e19679d394e2610d9e0106b94f3e2746..54e949d5452d55ce44c6f9f0d295845f1d15d5d6 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -82,10 +82,16 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev) const __be32 *addrs; u32 i; int proplen; + bool mark_unset = false; addrs = of_get_property(node, "assigned-addresses", &proplen); - if (!addrs) - return; + if (!addrs || !proplen) { + addrs = of_get_property(node, "reg", &proplen); + if (!addrs || !proplen) + return; + mark_unset = true; + } + pr_debug(" parse addresses (%d bytes) @ %p\n", proplen, addrs); for (; proplen >= 20; proplen -= 20, addrs += 5) { flags = pci_parse_of_flags(of_read_number(addrs, 1), 0); @@ -110,6 +116,8 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev) continue; } res->flags = flags; + if (mark_unset) + res->flags |= IORESOURCE_UNSET; res->name = pci_name(dev); region.start = base; region.end = base + size - 1; diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 41b3b2787f23af9afe041e6c43e31f3f3839e58c..a1e336901cc83acd516065ca40dd4ba7c22d28f6 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -466,6 +466,8 @@ static bool __init parse_cache_info(struct device_node *np, lsizep = of_get_property(np, propnames[3], NULL); if (bsizep == NULL) bsizep = lsizep; + if (lsizep == NULL) + lsizep = bsizep; if (lsizep != NULL) lsize = be32_to_cpu(*lsizep); if (bsizep != NULL) diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index b75bf6e74209eb60b0a4c854034801a083fead45..3e8edb1387ccfc75f7cf19a058f1bab13247ee3e 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -469,8 +469,10 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, err |= __get_user(tsk->thread.ckpt_regs.ccr, &sc->gp_regs[PT_CCR]); + /* Don't allow userspace to set the trap value */ + regs->trap = 0; + /* These regs are not checkpointed; they can go in 'regs'. */ - err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]); err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]); diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index b0cf4af7ba840ea3ac261fb92e8fc4524f17ee40..e4da937d6cf919918277166f80e44c24b9575a34 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -317,6 +317,12 @@ SECTIONS *(.branch_lt) } +#ifdef CONFIG_DEBUG_INFO_BTF + .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) { + *(.BTF) + } +#endif + .opd : AT(ADDR(.opd) - LOAD_OFFSET) { *(.opd) } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 7de26809340a2f95f1c5c77b9302ee6aa6bf7195..e4f81f0142065fdbe3e5cbecb2bb89803f5a5d3e 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1997,7 +1997,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, mutex_unlock(&kvm->lock); if (!vcore) - goto free_vcpu; + goto uninit_vcpu; spin_lock(&vcore->lock); ++vcore->num_threads; @@ -2014,6 +2014,8 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, return vcpu; +uninit_vcpu: + kvm_vcpu_uninit(vcpu); free_vcpu: kmem_cache_free(kvm_vcpu_cache, vcpu); out: diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index e2ef1619845613ac809e5855cd0074a04d940b26..f5bbb188f18d6a38e7f2fa839320c58908240b3f 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -1482,10 +1482,12 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm, err = kvmppc_mmu_init(vcpu); if (err < 0) - goto uninit_vcpu; + goto free_shared_page; return vcpu; +free_shared_page: + free_page((unsigned long)vcpu->arch.shared); uninit_vcpu: kvm_vcpu_uninit(vcpu); free_shadow_vcpu: diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index 048b8e9f44928ebbe3d9892ae8f7154d56ff1954..63964af9a162ee24ec9a7e1ee0460d5632e54e12 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -400,7 +400,7 @@ _GLOBAL(set_context) * extern void loadcam_entry(unsigned int index) * * Load TLBCAM[index] entry in to the L2 CAM MMU - * Must preserve r7, r8, r9, and r10 + * Must preserve r7, r8, r9, r10 and r11 */ _GLOBAL(loadcam_entry) mflr r5 @@ -436,6 +436,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS) */ _GLOBAL(loadcam_multi) mflr r8 + /* Don't switch to AS=1 if already there */ + mfmsr r11 + andi. r11,r11,MSR_IS + bne 10f /* * Set up temporary TLB entry that is the same as what we're @@ -461,6 +465,7 @@ _GLOBAL(loadcam_multi) mtmsr r6 isync +10: mr r9,r3 add r10,r3,r4 2: bl loadcam_entry @@ -469,6 +474,10 @@ _GLOBAL(loadcam_multi) mr r3,r9 blt 2b + /* Don't return to AS=0 if we were in AS=1 at function start */ + andi. r11,r11,MSR_IS + bne 3f + /* Return to AS=0 and clear the temporary entry */ mfmsr r6 rlwinm. r6,r6,0,~(MSR_IS|MSR_DS) @@ -484,6 +493,7 @@ _GLOBAL(loadcam_multi) tlbwe isync +3: mtlr r8 blr #endif diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index b7f937563827d91a3f0e331d1b87f5a7ed536787..d1fee2d35b49c6d24552b52728d37916f8046b2d 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -299,23 +299,6 @@ static int __init maple_probe(void) return 1; } -define_machine(maple) { - .name = "Maple", - .probe = maple_probe, - .setup_arch = maple_setup_arch, - .init_IRQ = maple_init_IRQ, - .pci_irq_fixup = maple_pci_irq_fixup, - .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, - .restart = maple_restart, - .halt = maple_halt, - .get_boot_time = maple_get_boot_time, - .set_rtc_time = maple_set_rtc_time, - .get_rtc_time = maple_get_rtc_time, - .calibrate_decr = generic_calibrate_decr, - .progress = maple_progress, - .power_save = power4_idle, -}; - #ifdef CONFIG_EDAC /* * Register a platform device for CPC925 memory controller on @@ -372,3 +355,20 @@ static int __init maple_cpc925_edac_setup(void) } machine_device_initcall(maple, maple_cpc925_edac_setup); #endif + +define_machine(maple) { + .name = "Maple", + .probe = maple_probe, + .setup_arch = maple_setup_arch, + .init_IRQ = maple_init_IRQ, + .pci_irq_fixup = maple_pci_irq_fixup, + .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, + .restart = maple_restart, + .halt = maple_halt, + .get_boot_time = maple_get_boot_time, + .set_rtc_time = maple_set_rtc_time, + .get_rtc_time = maple_get_rtc_time, + .calibrate_decr = generic_calibrate_decr, + .progress = maple_progress, + .power_save = power4_idle, +}; diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index d3d5796f7df603da10143e87d40d1069eacc3f42..36ef504eeab32de5e63e9ba1274edb097ef5d9a8 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1523,6 +1523,10 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs) /* Reserve PE for each VF */ for (vf_index = 0; vf_index < num_vfs; vf_index++) { + int vf_devfn = pci_iov_virtfn_devfn(pdev, vf_index); + int vf_bus = pci_iov_virtfn_bus(pdev, vf_index); + struct pci_dn *vf_pdn; + if (pdn->m64_single_mode) pe_num = pdn->pe_num_map[vf_index]; else @@ -1535,13 +1539,11 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs) pe->pbus = NULL; pe->parent_dev = pdev; pe->mve_number = -1; - pe->rid = (pci_iov_virtfn_bus(pdev, vf_index) << 8) | - pci_iov_virtfn_devfn(pdev, vf_index); + pe->rid = (vf_bus << 8) | vf_devfn; pe_info(pe, "VF %04d:%02d:%02d.%d associated with PE#%x\n", hose->global_number, pdev->bus->number, - PCI_SLOT(pci_iov_virtfn_devfn(pdev, vf_index)), - PCI_FUNC(pci_iov_virtfn_devfn(pdev, vf_index)), pe_num); + PCI_SLOT(vf_devfn), PCI_FUNC(vf_devfn), pe_num); if (pnv_ioda_configure_pe(phb, pe)) { /* XXX What do we do here ? */ @@ -1555,6 +1557,15 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs) list_add_tail(&pe->list, &phb->ioda.pe_list); mutex_unlock(&phb->ioda.pe_list_mutex); + /* associate this pe to it's pdn */ + list_for_each_entry(vf_pdn, &pdn->parent->child_list, list) { + if (vf_pdn->busno == vf_bus && + vf_pdn->devfn == vf_devfn) { + vf_pdn->pe_number = pe_num; + break; + } + } + pnv_pci_ioda2_setup_dma_pe(phb, pe); } } diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 961c131a5b7e8cf0c5a234898dd9df7a6528916a..844ca1886063bd25b6843a7311e5bd80309d20cd 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -978,16 +978,12 @@ void pnv_pci_dma_dev_setup(struct pci_dev *pdev) struct pnv_phb *phb = hose->private_data; #ifdef CONFIG_PCI_IOV struct pnv_ioda_pe *pe; - struct pci_dn *pdn; /* Fix the VF pdn PE number */ if (pdev->is_virtfn) { - pdn = pci_get_pdn(pdev); - WARN_ON(pdn->pe_number != IODA_INVALID_PE); list_for_each_entry(pe, &phb->ioda.pe_list, list) { if (pe->rid == ((pdev->bus->number << 8) | (pdev->devfn & 0xff))) { - pdn->pe_number = pe->pe_number; pe->pdev = pdev; break; } diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index fdfce7a46d733f4b4b37e9b7fd08aaf06bbdf2b5..a0847be0b0358893174bc958eb9878ed8553f7b9 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -452,8 +452,10 @@ static bool lmb_is_removable(struct of_drconf_cell *lmb) for (i = 0; i < scns_per_block; i++) { pfn = PFN_DOWN(phys_addr); - if (!pfn_present(pfn)) + if (!pfn_present(pfn)) { + phys_addr += MIN_MEMORY_BLOCK_SIZE; continue; + } rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION); phys_addr += MIN_MEMORY_BLOCK_SIZE; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 7c181467d0ad9b14785291a8aa11c5d9b6284587..0e4e22dfa6b5fb86542d4ac527c91a50865f6ff4 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -168,10 +168,10 @@ static unsigned long tce_get_pseries(struct iommu_table *tbl, long index) return be64_to_cpu(*tcep); } -static void tce_free_pSeriesLP(struct iommu_table*, long, long); +static void tce_free_pSeriesLP(unsigned long liobn, long, long); static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long); -static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, +static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, long npages, unsigned long uaddr, enum dma_data_direction direction, unsigned long attrs) @@ -182,25 +182,25 @@ static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, int ret = 0; long tcenum_start = tcenum, npages_start = npages; - rpn = __pa(uaddr) >> TCE_SHIFT; + rpn = __pa(uaddr) >> tceshift; proto_tce = TCE_PCI_READ; if (direction != DMA_TO_DEVICE) proto_tce |= TCE_PCI_WRITE; while (npages--) { - tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; - rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce); + tce = proto_tce | (rpn & TCE_RPN_MASK) << tceshift; + rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, tce); if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) { ret = (int)rc; - tce_free_pSeriesLP(tbl, tcenum_start, + tce_free_pSeriesLP(liobn, tcenum_start, (npages_start - (npages + 1))); break; } if (rc && printk_ratelimit()) { printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc); - printk("\tindex = 0x%llx\n", (u64)tbl->it_index); + printk("\tindex = 0x%llx\n", (u64)liobn); printk("\ttcenum = 0x%llx\n", (u64)tcenum); printk("\ttce val = 0x%llx\n", tce ); dump_stack(); @@ -229,7 +229,8 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, unsigned long flags; if ((npages == 1) || !firmware_has_feature(FW_FEATURE_MULTITCE)) { - return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, + return tce_build_pSeriesLP(tbl->it_index, tcenum, + tbl->it_page_shift, npages, uaddr, direction, attrs); } @@ -245,8 +246,9 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, /* If allocation fails, fall back to the loop implementation */ if (!tcep) { local_irq_restore(flags); - return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, - direction, attrs); + return tce_build_pSeriesLP(tbl->it_index, tcenum, + tbl->it_page_shift, + npages, uaddr, direction, attrs); } __this_cpu_write(tce_page, tcep); } @@ -297,16 +299,16 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, return ret; } -static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) +static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long npages) { u64 rc; while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0); + rc = plpar_tce_put((u64)liobn, (u64)tcenum << 12, 0); if (rc && printk_ratelimit()) { printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc); - printk("\tindex = 0x%llx\n", (u64)tbl->it_index); + printk("\tindex = 0x%llx\n", (u64)liobn); printk("\ttcenum = 0x%llx\n", (u64)tcenum); dump_stack(); } @@ -321,7 +323,7 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n u64 rc; if (!firmware_has_feature(FW_FEATURE_MULTITCE)) - return tce_free_pSeriesLP(tbl, tcenum, npages); + return tce_free_pSeriesLP(tbl->it_index, tcenum, npages); rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages); @@ -436,6 +438,19 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, u64 rc = 0; long l, limit; + if (!firmware_has_feature(FW_FEATURE_MULTITCE)) { + unsigned long tceshift = be32_to_cpu(maprange->tce_shift); + unsigned long dmastart = (start_pfn << PAGE_SHIFT) + + be64_to_cpu(maprange->dma_base); + unsigned long tcenum = dmastart >> tceshift; + unsigned long npages = num_pfn << PAGE_SHIFT >> tceshift; + void *uaddr = __va(start_pfn << PAGE_SHIFT); + + return tce_build_pSeriesLP(be32_to_cpu(maprange->liobn), + tcenum, tceshift, npages, (unsigned long) uaddr, + DMA_BIDIRECTIONAL, 0); + } + local_irq_disable(); /* to protect tcep and the page behind it */ tcep = __this_cpu_read(tce_page); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index c0ae3847b8db55f7eca8184851b7b99f5a598249..215b14a373cb4a09238a00d312c0b5ddd4546aa7 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -1060,7 +1060,7 @@ static int __init vpa_debugfs_init(void) { char name[16]; long i; - static struct dentry *vpa_dir; + struct dentry *vpa_dir; if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return 0; diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index d86938260a86752b46536f4d40af2eec4a15cd77..fc778865a4124cf070679d6c3e8da0af27e74f60 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -1195,6 +1195,8 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) if (tbl == NULL) return NULL; + kref_init(&tbl->it_kref); + of_parse_dma_window(dev->dev.of_node, dma_window, &tbl->it_index, &offset, &size); diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index a820370883d9348c6fa43835b0e6f821f9cb3fc7..b7ae5a027714eabb75002033d431d195b0e13443 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -72,13 +72,6 @@ static u32 xive_ipi_irq; /* Xive state for each CPU */ static DEFINE_PER_CPU(struct xive_cpu *, xive_cpu); -/* - * A "disabled" interrupt should never fire, to catch problems - * we set its logical number to this - */ -#define XIVE_BAD_IRQ 0x7fffffff -#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1) - /* An invalid CPU target */ #define XIVE_INVALID_TARGET (-1) @@ -1073,7 +1066,7 @@ static int xive_setup_cpu_ipi(unsigned int cpu) xc = per_cpu(xive_cpu, cpu); /* Check if we are already setup */ - if (xc->hw_ipi != 0) + if (xc->hw_ipi != XIVE_BAD_IRQ) return 0; /* Grab an IPI from the backend, this will populate xc->hw_ipi */ @@ -1110,7 +1103,7 @@ static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc) /* Disable the IPI and free the IRQ data */ /* Already cleaned up ? */ - if (xc->hw_ipi == 0) + if (xc->hw_ipi == XIVE_BAD_IRQ) return; /* Mask the IPI */ @@ -1266,6 +1259,7 @@ static int xive_prepare_cpu(unsigned int cpu) if (np) xc->chip_id = of_get_ibm_chip_id(np); of_node_put(np); + xc->hw_ipi = XIVE_BAD_IRQ; per_cpu(xive_cpu, cpu) = xc; } diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index aac61374afebf581cae336b2de48f277f5a5ed8e..30cdcbfa1c04e519720d802194b53330700981eb 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -310,7 +310,7 @@ static void xive_native_put_ipi(unsigned int cpu, struct xive_cpu *xc) s64 rc; /* Free the IPI */ - if (!xc->hw_ipi) + if (xc->hw_ipi == XIVE_BAD_IRQ) return; for (;;) { rc = opal_xive_free_irq(xc->hw_ipi); @@ -318,7 +318,7 @@ static void xive_native_put_ipi(unsigned int cpu, struct xive_cpu *xc) msleep(1); continue; } - xc->hw_ipi = 0; + xc->hw_ipi = XIVE_BAD_IRQ; break; } } diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c index 7fc41bf30fd594f1c7d9515cf40c2de833e89828..10235098a726660c97eee2c9c7f618487acce0d1 100644 --- a/arch/powerpc/sysdev/xive/spapr.c +++ b/arch/powerpc/sysdev/xive/spapr.c @@ -443,11 +443,11 @@ static int xive_spapr_get_ipi(unsigned int cpu, struct xive_cpu *xc) static void xive_spapr_put_ipi(unsigned int cpu, struct xive_cpu *xc) { - if (!xc->hw_ipi) + if (xc->hw_ipi == XIVE_BAD_IRQ) return; xive_irq_bitmap_free(xc->hw_ipi); - xc->hw_ipi = 0; + xc->hw_ipi = XIVE_BAD_IRQ; } #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/sysdev/xive/xive-internal.h b/arch/powerpc/sysdev/xive/xive-internal.h index f34abed0c05fd3064bf0a2c45fb193b49079283f..48808dbb25dce60df08cf38ae7456619338c26cb 100644 --- a/arch/powerpc/sysdev/xive/xive-internal.h +++ b/arch/powerpc/sysdev/xive/xive-internal.h @@ -9,6 +9,13 @@ #ifndef __XIVE_INTERNAL_H #define __XIVE_INTERNAL_H +/* + * A "disabled" interrupt should never fire, to catch problems + * we set its logical number to this + */ +#define XIVE_BAD_IRQ 0x7fffffff +#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1) + /* Each CPU carry one of these with various per-CPU state */ struct xive_cpu { #ifdef CONFIG_SMP diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index a60c44b4a3e502c63b5c4e70042169f2b3246887..93974b0a5a99ef714c00774f1f8a50650b829a0d 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -1,9 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for xmon -# Avoid clang warnings around longjmp/setjmp declarations -subdir-ccflags-y := -ffreestanding - subdir-ccflags-$(CONFIG_PPC_WERROR) += -Werror GCOV_PROFILE := n diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 51a53fd5172290706e8475f51ec60e687e448126..0885993b2fb43217580d725098b5ae482645a31d 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -1830,15 +1830,14 @@ static void dump_300_sprs(void) printf("pidr = %.16lx tidr = %.16lx\n", mfspr(SPRN_PID), mfspr(SPRN_TIDR)); - printf("asdr = %.16lx psscr = %.16lx\n", - mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR) - : mfspr(SPRN_PSSCR_PR)); + printf("psscr = %.16lx\n", + hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR)); if (!hv) return; - printf("ptcr = %.16lx\n", - mfspr(SPRN_PTCR)); + printf("ptcr = %.16lx asdr = %.16lx\n", + mfspr(SPRN_PTCR), mfspr(SPRN_ASDR)); #endif } diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 41e3908b397f8f2faa5bab59266fec25c635a6a7..5f2e272895ff9c6841bd9a2eb111b5a7c884e41a 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -33,6 +33,8 @@ #define ARCH_HAS_PREPARE_HUGEPAGE #define ARCH_HAS_HUGEPAGE_CLEAR_FLUSH +#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA + #include #ifndef __ASSEMBLY__ @@ -40,7 +42,7 @@ void __storage_key_init_range(unsigned long start, unsigned long end); static inline void storage_key_init_range(unsigned long start, unsigned long end) { - if (PAGE_DEFAULT_KEY) + if (PAGE_DEFAULT_KEY != 0) __storage_key_init_range(start, end); } diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 2dc9eb4e1acca26f09f5aad4d2cb45a5e19833a2..b6a4ce9dafafbfbbf96cfaab42e4348a5277ca39 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -155,7 +155,7 @@ static inline void get_tod_clock_ext(char *clk) static inline unsigned long long get_tod_clock(void) { - unsigned char clk[STORE_CLOCK_EXT_SIZE]; + char clk[STORE_CLOCK_EXT_SIZE]; get_tod_clock_ext(clk); return *((unsigned long long *)&clk[1]); diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index 53a5316cc4b7e557b8eb4b71aa78738d2d2ecf11..4c7cf8787a8489af80b746af4a02cd89f949b9d7 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -79,7 +79,7 @@ static int show_diag_stat(struct seq_file *m, void *v) static void *show_diag_stat_start(struct seq_file *m, loff_t *pos) { - return *pos <= nr_cpu_ids ? (void *)((unsigned long) *pos + 1) : NULL; + return *pos <= NR_DIAG_STAT ? (void *)((unsigned long) *pos + 1) : NULL; } static void *show_diag_stat_next(struct seq_file *m, void *v, loff_t *pos) @@ -128,7 +128,7 @@ void diag_stat_inc(enum diag_stat_enum nr) } EXPORT_SYMBOL(diag_stat_inc); -void diag_stat_inc_norecursion(enum diag_stat_enum nr) +void notrace diag_stat_inc_norecursion(enum diag_stat_enum nr) { this_cpu_inc(diag_stat.counter[nr]); trace_s390_diagnose_norecursion(diag_map[nr].code); diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 27110f3294edcdf30935048d5553f712caf44116..0cfd5a83a1daa9d32127454b5fa18609076b094b 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -25,6 +25,12 @@ ENTRY(ftrace_stub) #define STACK_PTREGS (STACK_FRAME_OVERHEAD) #define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS) #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW) +#ifdef __PACK_STACK +/* allocate just enough for r14, r15 and backchain */ +#define TRACED_FUNC_FRAME_SIZE 24 +#else +#define TRACED_FUNC_FRAME_SIZE STACK_FRAME_OVERHEAD +#endif ENTRY(_mcount) BR_EX %r14 @@ -38,9 +44,16 @@ ENTRY(ftrace_caller) #ifndef CC_USING_HOTPATCH aghi %r0,MCOUNT_RETURN_FIXUP #endif - aghi %r15,-STACK_FRAME_SIZE + # allocate stack frame for ftrace_caller to contain traced function + aghi %r15,-TRACED_FUNC_FRAME_SIZE stg %r1,__SF_BACKCHAIN(%r15) + stg %r0,(__SF_GPRS+8*8)(%r15) + stg %r15,(__SF_GPRS+9*8)(%r15) + # allocate pt_regs and stack frame for ftrace_trace_function + aghi %r15,-STACK_FRAME_SIZE stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) + aghi %r1,-TRACED_FUNC_FRAME_SIZE + stg %r1,__SF_BACKCHAIN(%r15) stg %r0,(STACK_PTREGS_PSW+8)(%r15) stmg %r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15) #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 6fe2e1875058bec89419d680bef0110249ba9ed3..675d4be0c2b77f18e53865bc57c05d9244fc3137 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -157,8 +157,9 @@ static void show_cpu_mhz(struct seq_file *m, unsigned long n) static int show_cpuinfo(struct seq_file *m, void *v) { unsigned long n = (unsigned long) v - 1; + unsigned long first = cpumask_first(cpu_online_mask); - if (!n) + if (n == first) show_cpu_summary(m, v); if (!machine_has_cpu_mhz) return 0; @@ -171,6 +172,8 @@ static inline void *c_update(loff_t *pos) { if (*pos) *pos = cpumask_next(*pos - 1, cpu_online_mask); + else + *pos = cpumask_first(cpu_online_mask); return *pos < nr_cpu_ids ? (void *)*pos + 1 : NULL; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index b649a6538350da6f034200b137ba8138e6cb348c..808f4fbe869e7bc59fed410fbf12b05721e18a3a 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -406,7 +406,7 @@ int smp_find_processor_id(u16 address) return -1; } -bool arch_vcpu_is_preempted(int cpu) +bool notrace arch_vcpu_is_preempted(int cpu) { if (test_cpu_flag_of(CIF_ENABLED_WAIT, cpu)) return false; @@ -416,7 +416,7 @@ bool arch_vcpu_is_preempted(int cpu) } EXPORT_SYMBOL(arch_vcpu_is_preempted); -void smp_yield_cpu(int cpu) +void notrace smp_yield_cpu(int cpu) { if (MACHINE_HAS_DIAG9C) { diag_stat_inc_norecursion(DIAG_STAT_X09C); diff --git a/arch/s390/kernel/trace.c b/arch/s390/kernel/trace.c index 490b52e85014538937d0c67e73a8bf6bf11c7cf9..11a669f3cc93c17d5f69f281296e04c2a39cc2bb 100644 --- a/arch/s390/kernel/trace.c +++ b/arch/s390/kernel/trace.c @@ -14,7 +14,7 @@ EXPORT_TRACEPOINT_SYMBOL(s390_diagnose); static DEFINE_PER_CPU(unsigned int, diagnose_trace_depth); -void trace_s390_diagnose_norecursion(int diag_nr) +void notrace trace_s390_diagnose_norecursion(int diag_nr) { unsigned long flags; unsigned int *depth; diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 28f3796d23c8f884b17c8a299c359197eb1f1564..61d25e2c82efacc0ab02900bf0c94b1e509b2d38 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -1913,7 +1913,7 @@ static int flic_ais_mode_get_all(struct kvm *kvm, struct kvm_device_attr *attr) return -EINVAL; if (!test_kvm_facility(kvm, 72)) - return -ENOTSUPP; + return -EOPNOTSUPP; mutex_lock(&fi->ais_lock); ais.simm = fi->simm; @@ -2214,7 +2214,7 @@ static int modify_ais_mode(struct kvm *kvm, struct kvm_device_attr *attr) int ret = 0; if (!test_kvm_facility(kvm, 72)) - return -ENOTSUPP; + return -EOPNOTSUPP; if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req))) return -EFAULT; @@ -2294,7 +2294,7 @@ static int flic_ais_mode_set_all(struct kvm *kvm, struct kvm_device_attr *attr) struct kvm_s390_ais_all ais; if (!test_kvm_facility(kvm, 72)) - return -ENOTSUPP; + return -EOPNOTSUPP; if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais))) return -EFAULT; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 91c24e87fe10a19cddd27be11528de3b4204e0c0..46fee3f4deddac150549dc217a04f82fb935edef 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2384,9 +2384,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64)); vcpu->arch.sie_block->gcr[0] = 0xE0UL; vcpu->arch.sie_block->gcr[14] = 0xC2000000UL; - /* make sure the new fpc will be lazily loaded */ - save_fpu_regs(); - current->thread.fpu.fpc = 0; + vcpu->run->s.regs.fpc = 0; vcpu->arch.sie_block->gbea = 1; vcpu->arch.sie_block->pp = 0; vcpu->arch.sie_block->fpf &= ~FPF_BPBC; @@ -3753,7 +3751,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, } case KVM_S390_STORE_STATUS: idx = srcu_read_lock(&vcpu->kvm->srcu); - r = kvm_s390_vcpu_store_status(vcpu, arg); + r = kvm_s390_store_status_unloaded(vcpu, arg); srcu_read_unlock(&vcpu->kvm->srcu, idx); break; case KVM_S390_SET_INITIAL_PSW: { diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 061906f98dc5cc95cd3c965535d0dd9cb2083a9e..0120383219c038494ef3b1075dcad48d982d923c 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -1027,6 +1027,7 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->iprcc = PGM_ADDRESSING; scb_s->pgmilc = 4; scb_s->gpsw.addr = __rewind_psw(scb_s->gpsw, 4); + rc = 1; } return rc; } diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index ec9292917d3f24852ec931c5abb82eecc2e516a2..a29d2e88b00ef7ebb71f5736e8343e182a523446 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -762,14 +762,18 @@ static void gmap_call_notifier(struct gmap *gmap, unsigned long start, static inline unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level) { + const int asce_type = gmap->asce & _ASCE_TYPE_MASK; unsigned long *table; if ((gmap->asce & _ASCE_TYPE_MASK) + 4 < (level * 4)) return NULL; if (gmap_is_shadow(gmap) && gmap->removed) return NULL; - if (gaddr & (-1UL << (31 + ((gmap->asce & _ASCE_TYPE_MASK) >> 2)*11))) + + if (asce_type != _ASCE_TYPE_REGION1 && + gaddr & (-1UL << (31 + (asce_type >> 2) * 11))) return NULL; + table = gmap->table; switch (gmap->asce & _ASCE_TYPE_MASK) { case _ASCE_TYPE_REGION1: @@ -1683,6 +1687,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t, goto out_free; } else if (*table & _REGION_ENTRY_ORIGIN) { rc = -EAGAIN; /* Race with shadow */ + goto out_free; } crst_table_init(s_r3t, _REGION3_ENTRY_EMPTY); /* mark as invalid as long as the parent table is not protected */ diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index e804090f4470fce93446cdde89cd5170d6c25644..e19ea9ebe960bd0444a46b3d6fe39c67267f90e7 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -2,7 +2,7 @@ /* * IBM System z Huge TLB Page Support for Kernel. * - * Copyright IBM Corp. 2007,2016 + * Copyright IBM Corp. 2007,2020 * Author(s): Gerald Schaefer */ @@ -11,6 +11,9 @@ #include #include +#include +#include +#include /* * If the bit selected by single-bit bitmask "a" is set within "x", move @@ -243,3 +246,98 @@ static __init int setup_hugepagesz(char *opt) return 1; } __setup("hugepagesz=", setup_hugepagesz); + +static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, + unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags) +{ + struct hstate *h = hstate_file(file); + struct vm_unmapped_area_info info; + + info.flags = 0; + info.length = len; + info.low_limit = current->mm->mmap_base; + info.high_limit = TASK_SIZE; + info.align_mask = PAGE_MASK & ~huge_page_mask(h); + info.align_offset = 0; + return vm_unmapped_area(&info); +} + +static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, + unsigned long addr0, unsigned long len, + unsigned long pgoff, unsigned long flags) +{ + struct hstate *h = hstate_file(file); + struct vm_unmapped_area_info info; + unsigned long addr; + + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.length = len; + info.low_limit = max(PAGE_SIZE, mmap_min_addr); + info.high_limit = current->mm->mmap_base; + info.align_mask = PAGE_MASK & ~huge_page_mask(h); + info.align_offset = 0; + addr = vm_unmapped_area(&info); + + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + if (addr & ~PAGE_MASK) { + VM_BUG_ON(addr != -ENOMEM); + info.flags = 0; + info.low_limit = TASK_UNMAPPED_BASE; + info.high_limit = TASK_SIZE; + addr = vm_unmapped_area(&info); + } + + return addr; +} + +unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct hstate *h = hstate_file(file); + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + int rc; + + if (len & ~huge_page_mask(h)) + return -EINVAL; + if (len > TASK_SIZE - mmap_min_addr) + return -ENOMEM; + + if (flags & MAP_FIXED) { + if (prepare_hugepage_range(file, addr, len)) + return -EINVAL; + goto check_asce_limit; + } + + if (addr) { + addr = ALIGN(addr, huge_page_size(h)); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && + (!vma || addr + len <= vm_start_gap(vma))) + goto check_asce_limit; + } + + if (mm->get_unmapped_area == arch_get_unmapped_area) + addr = hugetlb_get_unmapped_area_bottomup(file, addr, len, + pgoff, flags); + else + addr = hugetlb_get_unmapped_area_topdown(file, addr, len, + pgoff, flags); + if (addr & ~PAGE_MASK) + return addr; + +check_asce_limit: + if (addr + len > current->mm->context.asce_limit && + addr + len <= TASK_SIZE) { + rc = crst_table_upgrade(mm, addr + len); + if (rc) + return (unsigned long) rc; + } + return addr; +} diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7269.h b/arch/sh/include/cpu-sh2a/cpu/sh7269.h index d516e5d488180db7b83bd7bc9cf8c0e80f75f4cf..b887cc402b71255712c54b29b26100f7b24c99fa 100644 --- a/arch/sh/include/cpu-sh2a/cpu/sh7269.h +++ b/arch/sh/include/cpu-sh2a/cpu/sh7269.h @@ -78,8 +78,15 @@ enum { GPIO_FN_WDTOVF, /* CAN */ - GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1, - GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1, GPIO_FN_CRX0_CRX1_CRX2, + GPIO_FN_CTX2, GPIO_FN_CRX2, + GPIO_FN_CTX1, GPIO_FN_CRX1, + GPIO_FN_CTX0, GPIO_FN_CRX0, + GPIO_FN_CTX0_CTX1, GPIO_FN_CRX0_CRX1, + GPIO_FN_CTX0_CTX1_CTX2, GPIO_FN_CRX0_CRX1_CRX2, + GPIO_FN_CTX2_PJ21, GPIO_FN_CRX2_PJ20, + GPIO_FN_CTX1_PJ23, GPIO_FN_CRX1_PJ22, + GPIO_FN_CTX0_CTX1_PJ23, GPIO_FN_CRX0_CRX1_PJ22, + GPIO_FN_CTX0_CTX1_CTX2_PJ21, GPIO_FN_CRX0_CRX1_CRX2_PJ20, /* DMAC */ GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0, diff --git a/arch/sparc/include/uapi/asm/ipcbuf.h b/arch/sparc/include/uapi/asm/ipcbuf.h index 9d0d125500e240bcd586eeb97a675e4f29ce5414..084b8949ddff6bbcb81a728160bdef5e5f58abad 100644 --- a/arch/sparc/include/uapi/asm/ipcbuf.h +++ b/arch/sparc/include/uapi/asm/ipcbuf.h @@ -15,19 +15,19 @@ struct ipc64_perm { - __kernel_key_t key; - __kernel_uid_t uid; - __kernel_gid_t gid; - __kernel_uid_t cuid; - __kernel_gid_t cgid; + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; #ifndef __arch64__ - unsigned short __pad0; + unsigned short __pad0; #endif - __kernel_mode_t mode; - unsigned short __pad1; - unsigned short seq; - unsigned long long __unused1; - unsigned long long __unused2; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned long long __unused1; + unsigned long long __unused2; }; #endif /* __SPARC_IPCBUF_H */ diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 5a2344574f39bc6ade2e2a8b3f8381f47362643c..4323dc4ae4c7a1a41c896fe1d3ec3789c3f250d1 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -167,12 +167,14 @@ SECTIONS } PERCPU_SECTION(SMP_CACHE_BYTES) -#ifdef CONFIG_JUMP_LABEL . = ALIGN(PAGE_SIZE); .exit.text : { EXIT_TEXT } -#endif + + .exit.data : { + EXIT_DATA + } . = ALIGN(PAGE_SIZE); __init_end = .; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fdc42d2bf7d99b91aadc6f00553702cc87279e25..a9b831061e84fd37aec13db40019ceff7b62e442 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -70,6 +70,7 @@ config X86 select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT select ARCH_SUPPORTS_NUMA_BALANCING if X86_64 + select ARCH_SUPPORTS_LTO_CLANG if X86_64 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS @@ -172,7 +173,7 @@ config X86 select HAVE_RCU_TABLE_INVALIDATE if HAVE_RCU_TABLE_FREE select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION - select HAVE_STACK_VALIDATION if X86_64 + select HAVE_STACK_VALIDATION if X86_64 && !LTO_CLANG select HAVE_SYSCALL_TRACEPOINTS select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_USER_RETURN_NOTIFIER diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 6ccc65edf7e34aedf98904021a315d7f20d40f5e..6449fc9f55d2ce69d0ab1745dfb5e4ae3c468f85 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -236,6 +236,11 @@ ifdef CONFIG_X86_64 LDFLAGS += $(call ld-option, -z max-page-size=0x200000) endif +ifdef CONFIG_LTO_CLANG +KBUILD_LDFLAGS += -plugin-opt=-code-model=kernel \ + -plugin-opt=-stack-alignment=$(if $(CONFIG_X86_32),4,8) +endif + # Speed up the build KBUILD_CFLAGS += -pipe # Workaround for a gcc prelease that unfortunately was shipped in a suse release diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 37380c0d59996b8ed688d0e350111343e5dca0ae..01d628ea34024c1a88192a2a19e12920bceaf196 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -106,7 +106,7 @@ ENTRY(startup_32) notl %eax andl %eax, %ebx cmpl $LOAD_PHYSICAL_ADDR, %ebx - jge 1f + jae 1f #endif movl $LOAD_PHYSICAL_ADDR, %ebx 1: diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 39fdede523f216042af652ce8098078b2706cec2..a25127916e67973faa03b06ed4f869beb86e4a68 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -105,7 +105,7 @@ ENTRY(startup_32) notl %eax andl %eax, %ebx cmpl $LOAD_PHYSICAL_ADDR, %ebx - jge 1f + jae 1f #endif movl $LOAD_PHYSICAL_ADDR, %ebx 1: @@ -280,7 +280,7 @@ ENTRY(startup_64) notq %rax andq %rax, %rbp cmpq $LOAD_PHYSICAL_ADDR, %rbp - jge 1f + jae 1f #endif movq $LOAD_PHYSICAL_ADDR, %rbp 1: diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c index e691ff734cb5adb5c9e5ff2c0da1c4bd790617ee..46573842d8c3ecb80a278be92ecbcfd91c02d02c 100644 --- a/arch/x86/boot/compressed/pagetable.c +++ b/arch/x86/boot/compressed/pagetable.c @@ -36,9 +36,6 @@ #define __PAGE_OFFSET __PAGE_OFFSET_BASE #include "../../mm/ident_map.c" -/* Used by pgtable.h asm code to force instruction serialization. */ -unsigned long __force_order; - /* Used to track our page table allocation area. */ struct alloc_pgt_data { unsigned char *pgt_buf; diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 015003dc8b2168b1efb5e4d0673a5c4781e113a9..5a03ff9b45dba5078bb0df09f0f6ce4130cf21c4 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -17,15 +17,19 @@ CONFIG_CGROUPS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_CGROUP_SCHED=y -CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set CONFIG_SCHED_TUNE=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_RD_LZ4 is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set CONFIG_KALLSYMS_ALL=y # CONFIG_PCSPKR_PLATFORM is not set CONFIG_BPF_SYSCALL=y @@ -34,13 +38,16 @@ CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=y -CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_LTO_CLANG=y +CONFIG_CFI_CLANG=y CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y CONFIG_SMP=y CONFIG_HYPERVISOR_GUEST=y @@ -65,6 +72,9 @@ CONFIG_PHYSICAL_START=0x200000 CONFIG_PHYSICAL_ALIGN=0x1000000 CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyS0 reboot=p" +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set CONFIG_PM_DEBUG=y CONFIG_ACPI_PROCFS_POWER=y # CONFIG_ACPI_FAN is not set @@ -233,6 +243,7 @@ CONFIG_SCSI_SPI_ATTRS=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_SNAPSHOT=y CONFIG_DM_MIRROR=y CONFIG_DM_ZERO=y @@ -318,6 +329,8 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y CONFIG_HPET=y # CONFIG_HPET_MMAP_DEFAULT is not set +CONFIG_TCG_TPM=y +CONFIG_TCG_VTPM_PROXY=y # CONFIG_DEVPORT is not set # CONFIG_ACPI_I2C_OPREGION is not set # CONFIG_I2C_COMPAT is not set @@ -374,6 +387,7 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y CONFIG_HID_NTRIG=y CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y @@ -412,7 +426,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_TEST=y -CONFIG_SW_SYNC=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_PMEM=y CONFIG_VIRTIO_INPUT=y @@ -427,6 +440,7 @@ CONFIG_ION_SYSTEM_HEAP=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y CONFIG_LIBNVDIMM=y # CONFIG_ND_BLK is not set # CONFIG_FIRMWARE_MEMMAP is not set @@ -437,6 +451,7 @@ CONFIG_EXT4_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y CONFIG_QUOTA=y @@ -462,6 +477,7 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y +CONFIG_UNICODE=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y # CONFIG_ENABLE_WARN_DEPRECATED is not set @@ -475,10 +491,12 @@ CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_HARDLOCKUP_DETECTOR=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y +CONFIG_DEBUG_LIST=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_TEST_MEMINIT=y +CONFIG_TEST_STACKINIT=y CONFIG_IO_DELAY_NONE=y -CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y CONFIG_UNWINDER_FRAME_POINTER=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y @@ -488,10 +506,12 @@ CONFIG_SECURITY_PATH=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_INIT_STACK_ALL=y +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_ADIANTUM=y CONFIG_CRYPTO_AES_NI_INTEL=y CONFIG_CRYPTO_LZ4=y CONFIG_CRYPTO_ZSTD=y -CONFIG_CRYPTO_DEV_VIRTIO=y +# CONFIG_CRYPTO_DEV_VIRTIO is not set CONFIG_SYSTEM_TRUSTED_KEYS="verity_dev_keys.x509" diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index c690ddc78c03631f56c84e0ce19d408bc94a630d..6dc0af7f2388e082872f282efaafde30afaaf1ee 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -74,10 +74,8 @@ struct aesni_xts_ctx { asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key, unsigned int key_len); -asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out, - const u8 *in); -asmlinkage void aesni_dec(struct crypto_aes_ctx *ctx, u8 *out, - const u8 *in); +asmlinkage void aesni_enc(void *ctx, u8 *out, const u8 *in); +asmlinkage void aesni_dec(void *ctx, u8 *out, const u8 *in); asmlinkage void aesni_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len); asmlinkage void aesni_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out, diff --git a/arch/x86/crypto/sha1_avx2_x86_64_asm.S b/arch/x86/crypto/sha1_avx2_x86_64_asm.S index 9f712a7dfd797cc499e1ef52ba7999078530494a..7e578fa5d0a7423f2804a5706d86529736e8a278 100644 --- a/arch/x86/crypto/sha1_avx2_x86_64_asm.S +++ b/arch/x86/crypto/sha1_avx2_x86_64_asm.S @@ -62,11 +62,11 @@ *Visit http://software.intel.com/en-us/articles/ *and refer to improving-the-performance-of-the-secure-hash-algorithm-1/ * - *Updates 20-byte SHA-1 record in 'hash' for even number of - *'num_blocks' consecutive 64-byte blocks + *Updates 20-byte SHA-1 record at start of 'state', from 'input', for + *even number of 'blocks' consecutive 64-byte blocks. * *extern "C" void sha1_transform_avx2( - * int *hash, const char* input, size_t num_blocks ); + * struct sha1_state *state, const u8* input, int blocks ); */ #include diff --git a/arch/x86/crypto/sha1_ssse3_asm.S b/arch/x86/crypto/sha1_ssse3_asm.S index 6204bd53528c65c0d4a70f05e76a60bcc476499e..5fc0bf7e6a0303f305a6641ef5df9c754517be24 100644 --- a/arch/x86/crypto/sha1_ssse3_asm.S +++ b/arch/x86/crypto/sha1_ssse3_asm.S @@ -461,9 +461,13 @@ W_PRECALC_SSSE3 movdqu \a,\b .endm -/* SSSE3 optimized implementation: - * extern "C" void sha1_transform_ssse3(u32 *digest, const char *data, u32 *ws, - * unsigned int rounds); +/* + * SSSE3 optimized implementation: + * + * extern "C" void sha1_transform_ssse3(struct sha1_state *state, + * const u8 *data, int blocks); + * + * Note that struct sha1_state is assumed to begin with u32 state[5]. */ SHA1_VECTOR_ASM sha1_transform_ssse3 @@ -549,8 +553,8 @@ W_PRECALC_AVX /* AVX optimized implementation: - * extern "C" void sha1_transform_avx(u32 *digest, const char *data, u32 *ws, - * unsigned int rounds); + * extern "C" void sha1_transform_avx(struct sha1_state *state, + * const u8 *data, int blocks); */ SHA1_VECTOR_ASM sha1_transform_avx diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c index fc61739150e7c2c5a484c020b14441551fe5403a..9691962756a7efd998907738974f25278381ed15 100644 --- a/arch/x86/crypto/sha1_ssse3_glue.c +++ b/arch/x86/crypto/sha1_ssse3_glue.c @@ -31,11 +31,8 @@ #include #include -typedef void (sha1_transform_fn)(u32 *digest, const char *data, - unsigned int rounds); - static int sha1_update(struct shash_desc *desc, const u8 *data, - unsigned int len, sha1_transform_fn *sha1_xform) + unsigned int len, sha1_block_fn *sha1_xform) { struct sha1_state *sctx = shash_desc_ctx(desc); @@ -43,48 +40,47 @@ static int sha1_update(struct shash_desc *desc, const u8 *data, (sctx->count % SHA1_BLOCK_SIZE) + len < SHA1_BLOCK_SIZE) return crypto_sha1_update(desc, data, len); - /* make sure casting to sha1_block_fn() is safe */ + /* + * Make sure struct sha1_state begins directly with the SHA1 + * 160-bit internal state, as this is what the asm functions expect. + */ BUILD_BUG_ON(offsetof(struct sha1_state, state) != 0); kernel_fpu_begin(); - sha1_base_do_update(desc, data, len, - (sha1_block_fn *)sha1_xform); + sha1_base_do_update(desc, data, len, sha1_xform); kernel_fpu_end(); return 0; } static int sha1_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out, sha1_transform_fn *sha1_xform) + unsigned int len, u8 *out, sha1_block_fn *sha1_xform) { if (!irq_fpu_usable()) return crypto_sha1_finup(desc, data, len, out); kernel_fpu_begin(); if (len) - sha1_base_do_update(desc, data, len, - (sha1_block_fn *)sha1_xform); - sha1_base_do_finalize(desc, (sha1_block_fn *)sha1_xform); + sha1_base_do_update(desc, data, len, sha1_xform); + sha1_base_do_finalize(desc, sha1_xform); kernel_fpu_end(); return sha1_base_finish(desc, out); } -asmlinkage void sha1_transform_ssse3(u32 *digest, const char *data, - unsigned int rounds); +asmlinkage void sha1_transform_ssse3(struct sha1_state *state, + const u8 *data, int blocks); static int sha1_ssse3_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha1_update(desc, data, len, - (sha1_transform_fn *) sha1_transform_ssse3); + return sha1_update(desc, data, len, sha1_transform_ssse3); } static int sha1_ssse3_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - return sha1_finup(desc, data, len, out, - (sha1_transform_fn *) sha1_transform_ssse3); + return sha1_finup(desc, data, len, out, sha1_transform_ssse3); } /* Add padding and return the message digest. */ @@ -124,21 +120,19 @@ static void unregister_sha1_ssse3(void) } #ifdef CONFIG_AS_AVX -asmlinkage void sha1_transform_avx(u32 *digest, const char *data, - unsigned int rounds); +asmlinkage void sha1_transform_avx(struct sha1_state *state, + const u8 *data, int blocks); static int sha1_avx_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha1_update(desc, data, len, - (sha1_transform_fn *) sha1_transform_avx); + return sha1_update(desc, data, len, sha1_transform_avx); } static int sha1_avx_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - return sha1_finup(desc, data, len, out, - (sha1_transform_fn *) sha1_transform_avx); + return sha1_finup(desc, data, len, out, sha1_transform_avx); } static int sha1_avx_final(struct shash_desc *desc, u8 *out) @@ -196,8 +190,8 @@ static inline void unregister_sha1_avx(void) { } #if defined(CONFIG_AS_AVX2) && (CONFIG_AS_AVX) #define SHA1_AVX2_BLOCK_OPTSIZE 4 /* optimal 4*64 bytes of SHA1 blocks */ -asmlinkage void sha1_transform_avx2(u32 *digest, const char *data, - unsigned int rounds); +asmlinkage void sha1_transform_avx2(struct sha1_state *state, + const u8 *data, int blocks); static bool avx2_usable(void) { @@ -209,28 +203,26 @@ static bool avx2_usable(void) return false; } -static void sha1_apply_transform_avx2(u32 *digest, const char *data, - unsigned int rounds) +static void sha1_apply_transform_avx2(struct sha1_state *state, + const u8 *data, int blocks) { /* Select the optimal transform based on data block size */ - if (rounds >= SHA1_AVX2_BLOCK_OPTSIZE) - sha1_transform_avx2(digest, data, rounds); + if (blocks >= SHA1_AVX2_BLOCK_OPTSIZE) + sha1_transform_avx2(state, data, blocks); else - sha1_transform_avx(digest, data, rounds); + sha1_transform_avx(state, data, blocks); } static int sha1_avx2_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha1_update(desc, data, len, - (sha1_transform_fn *) sha1_apply_transform_avx2); + return sha1_update(desc, data, len, sha1_apply_transform_avx2); } static int sha1_avx2_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - return sha1_finup(desc, data, len, out, - (sha1_transform_fn *) sha1_apply_transform_avx2); + return sha1_finup(desc, data, len, out, sha1_apply_transform_avx2); } static int sha1_avx2_final(struct shash_desc *desc, u8 *out) @@ -274,21 +266,19 @@ static inline void unregister_sha1_avx2(void) { } #endif #ifdef CONFIG_AS_SHA1_NI -asmlinkage void sha1_ni_transform(u32 *digest, const char *data, - unsigned int rounds); +asmlinkage void sha1_ni_transform(struct sha1_state *digest, const u8 *data, + int rounds); static int sha1_ni_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha1_update(desc, data, len, - (sha1_transform_fn *) sha1_ni_transform); + return sha1_update(desc, data, len, sha1_ni_transform); } static int sha1_ni_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - return sha1_finup(desc, data, len, out, - (sha1_transform_fn *) sha1_ni_transform); + return sha1_finup(desc, data, len, out, sha1_ni_transform); } static int sha1_ni_final(struct shash_desc *desc, u8 *out) diff --git a/arch/x86/crypto/sha256-avx-asm.S b/arch/x86/crypto/sha256-avx-asm.S index 001bbcf93c79ba08628abcf30dd49ad77158420d..b6e037ee66613eadc410a956b4aed01be422870f 100644 --- a/arch/x86/crypto/sha256-avx-asm.S +++ b/arch/x86/crypto/sha256-avx-asm.S @@ -341,8 +341,8 @@ a = TMP_ .endm ######################################################################## -## void sha256_transform_avx(void *input_data, UINT32 digest[8], UINT64 num_blks) -## arg 1 : pointer to digest +## void sha256_transform_avx(state sha256_state *state, const u8 *data, int blocks) +## arg 1 : pointer to state ## arg 2 : pointer to input data ## arg 3 : Num blocks ######################################################################## diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S index 1420db15dcddc8505b57faad5e6e6701f972b517..2e6ebc904a3a9fb5ff718d818f0539477b7d8d71 100644 --- a/arch/x86/crypto/sha256-avx2-asm.S +++ b/arch/x86/crypto/sha256-avx2-asm.S @@ -520,8 +520,8 @@ STACK_SIZE = _RSP + _RSP_SIZE .endm ######################################################################## -## void sha256_transform_rorx(void *input_data, UINT32 digest[8], UINT64 num_blks) -## arg 1 : pointer to digest +## void sha256_transform_rorx(struct sha256_state *state, const u8 *data, int blocks) +## arg 1 : pointer to state ## arg 2 : pointer to input data ## arg 3 : Num blocks ######################################################################## diff --git a/arch/x86/crypto/sha256-ssse3-asm.S b/arch/x86/crypto/sha256-ssse3-asm.S index c6c05ed2c16a593390ddf7617070f45e58a40ad4..ab7d9f05ff789399ad1feee5f77c3ea601e201e9 100644 --- a/arch/x86/crypto/sha256-ssse3-asm.S +++ b/arch/x86/crypto/sha256-ssse3-asm.S @@ -347,8 +347,10 @@ a = TMP_ .endm ######################################################################## -## void sha256_transform_ssse3(void *input_data, UINT32 digest[8], UINT64 num_blks) -## arg 1 : pointer to digest +## void sha256_transform_ssse3(struct sha256_state *state, const u8 *data, +## int blocks); +## arg 1 : pointer to state +## (struct sha256_state is assumed to begin with u32 state[8]) ## arg 2 : pointer to input data ## arg 3 : Num blocks ######################################################################## diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c index 9e79baf03a4b206ced0e5e2b0a1f055cd0ca73c6..2fd8bdaa66046d62982a669f8827272894c89622 100644 --- a/arch/x86/crypto/sha256_ssse3_glue.c +++ b/arch/x86/crypto/sha256_ssse3_glue.c @@ -40,12 +40,11 @@ #include #include -asmlinkage void sha256_transform_ssse3(u32 *digest, const char *data, - u64 rounds); -typedef void (sha256_transform_fn)(u32 *digest, const char *data, u64 rounds); +asmlinkage void sha256_transform_ssse3(struct sha256_state *state, + const u8 *data, int blocks); -static int sha256_update(struct shash_desc *desc, const u8 *data, - unsigned int len, sha256_transform_fn *sha256_xform) +static int _sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len, sha256_block_fn *sha256_xform) { struct sha256_state *sctx = shash_desc_ctx(desc); @@ -53,28 +52,29 @@ static int sha256_update(struct shash_desc *desc, const u8 *data, (sctx->count % SHA256_BLOCK_SIZE) + len < SHA256_BLOCK_SIZE) return crypto_sha256_update(desc, data, len); - /* make sure casting to sha256_block_fn() is safe */ + /* + * Make sure struct sha256_state begins directly with the SHA256 + * 256-bit internal state, as this is what the asm functions expect. + */ BUILD_BUG_ON(offsetof(struct sha256_state, state) != 0); kernel_fpu_begin(); - sha256_base_do_update(desc, data, len, - (sha256_block_fn *)sha256_xform); + sha256_base_do_update(desc, data, len, sha256_xform); kernel_fpu_end(); return 0; } static int sha256_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out, sha256_transform_fn *sha256_xform) + unsigned int len, u8 *out, sha256_block_fn *sha256_xform) { if (!irq_fpu_usable()) return crypto_sha256_finup(desc, data, len, out); kernel_fpu_begin(); if (len) - sha256_base_do_update(desc, data, len, - (sha256_block_fn *)sha256_xform); - sha256_base_do_finalize(desc, (sha256_block_fn *)sha256_xform); + sha256_base_do_update(desc, data, len, sha256_xform); + sha256_base_do_finalize(desc, sha256_xform); kernel_fpu_end(); return sha256_base_finish(desc, out); @@ -83,7 +83,7 @@ static int sha256_finup(struct shash_desc *desc, const u8 *data, static int sha256_ssse3_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_transform_ssse3); + return _sha256_update(desc, data, len, sha256_transform_ssse3); } static int sha256_ssse3_finup(struct shash_desc *desc, const u8 *data, @@ -146,13 +146,13 @@ static void unregister_sha256_ssse3(void) } #ifdef CONFIG_AS_AVX -asmlinkage void sha256_transform_avx(u32 *digest, const char *data, - u64 rounds); +asmlinkage void sha256_transform_avx(struct sha256_state *state, + const u8 *data, int blocks); static int sha256_avx_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_transform_avx); + return _sha256_update(desc, data, len, sha256_transform_avx); } static int sha256_avx_finup(struct shash_desc *desc, const u8 *data, @@ -230,13 +230,13 @@ static inline void unregister_sha256_avx(void) { } #endif #if defined(CONFIG_AS_AVX2) && defined(CONFIG_AS_AVX) -asmlinkage void sha256_transform_rorx(u32 *digest, const char *data, - u64 rounds); +asmlinkage void sha256_transform_rorx(struct sha256_state *state, + const u8 *data, int blocks); static int sha256_avx2_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_transform_rorx); + return _sha256_update(desc, data, len, sha256_transform_rorx); } static int sha256_avx2_finup(struct shash_desc *desc, const u8 *data, @@ -312,13 +312,13 @@ static inline void unregister_sha256_avx2(void) { } #endif #ifdef CONFIG_AS_SHA256_NI -asmlinkage void sha256_ni_transform(u32 *digest, const char *data, - u64 rounds); /*unsigned int rounds);*/ +asmlinkage void sha256_ni_transform(struct sha256_state *digest, + const u8 *data, int rounds); static int sha256_ni_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - return sha256_update(desc, data, len, sha256_ni_transform); + return _sha256_update(desc, data, len, sha256_ni_transform); } static int sha256_ni_finup(struct shash_desc *desc, const u8 *data, diff --git a/arch/x86/crypto/sha512-avx-asm.S b/arch/x86/crypto/sha512-avx-asm.S index 39235fefe6f7c0c8e15c39c5828d9ff93e2609d6..8f6fe09cba54601f921811e2a09ca2405d74beaf 100644 --- a/arch/x86/crypto/sha512-avx-asm.S +++ b/arch/x86/crypto/sha512-avx-asm.S @@ -271,11 +271,12 @@ frame_size = frame_GPRSAVE + GPRSAVE_SIZE .endm ######################################################################## -# void sha512_transform_avx(void* D, const void* M, u64 L) -# Purpose: Updates the SHA512 digest stored at D with the message stored in M. -# The size of the message pointed to by M must be an integer multiple of SHA512 -# message blocks. -# L is the message length in SHA512 blocks +# void sha512_transform_avx(sha512_state *state, const u8 *data, int blocks) +# Purpose: Updates the SHA512 digest stored at "state" with the message +# stored in "data". +# The size of the message pointed to by "data" must be an integer multiple +# of SHA512 message blocks. +# "blocks" is the message length in SHA512 blocks ######################################################################## ENTRY(sha512_transform_avx) cmp $0, msglen diff --git a/arch/x86/crypto/sha512-avx2-asm.S b/arch/x86/crypto/sha512-avx2-asm.S index b16d560051629a1c6d518321b93be2672b861c9e..43d4d641804c73752b5c131282f755a167b2dce7 100644 --- a/arch/x86/crypto/sha512-avx2-asm.S +++ b/arch/x86/crypto/sha512-avx2-asm.S @@ -563,11 +563,12 @@ frame_size = frame_GPRSAVE + GPRSAVE_SIZE .endm ######################################################################## -# void sha512_transform_rorx(void* D, const void* M, uint64_t L)# -# Purpose: Updates the SHA512 digest stored at D with the message stored in M. -# The size of the message pointed to by M must be an integer multiple of SHA512 -# message blocks. -# L is the message length in SHA512 blocks +# void sha512_transform_rorx(sha512_state *state, const u8 *data, int blocks) +# Purpose: Updates the SHA512 digest stored at "state" with the message +# stored in "data". +# The size of the message pointed to by "data" must be an integer multiple +# of SHA512 message blocks. +# "blocks" is the message length in SHA512 blocks ######################################################################## ENTRY(sha512_transform_rorx) # Allocate Stack Space diff --git a/arch/x86/crypto/sha512-ssse3-asm.S b/arch/x86/crypto/sha512-ssse3-asm.S index 66bbd9058a90d67f51a44340e66ddfcd3801ec60..46da903f5538f4d9470154fde12338935328518c 100644 --- a/arch/x86/crypto/sha512-ssse3-asm.S +++ b/arch/x86/crypto/sha512-ssse3-asm.S @@ -269,11 +269,14 @@ frame_size = frame_GPRSAVE + GPRSAVE_SIZE .endm ######################################################################## -# void sha512_transform_ssse3(void* D, const void* M, u64 L)# -# Purpose: Updates the SHA512 digest stored at D with the message stored in M. -# The size of the message pointed to by M must be an integer multiple of SHA512 -# message blocks. -# L is the message length in SHA512 blocks. +## void sha512_transform_ssse3(struct sha512_state *state, const u8 *data, +## int blocks); +# (struct sha512_state is assumed to begin with u64 state[8]) +# Purpose: Updates the SHA512 digest stored at "state" with the message +# stored in "data". +# The size of the message pointed to by "data" must be an integer multiple +# of SHA512 message blocks. +# "blocks" is the message length in SHA512 blocks. ######################################################################## ENTRY(sha512_transform_ssse3) diff --git a/arch/x86/crypto/sha512_ssse3_glue.c b/arch/x86/crypto/sha512_ssse3_glue.c index 2b0e2a6825f337f2defe72d6a4bc7760ee9b587b..1db6c4ed53cd1893abf009616cd1b50b64192451 100644 --- a/arch/x86/crypto/sha512_ssse3_glue.c +++ b/arch/x86/crypto/sha512_ssse3_glue.c @@ -39,13 +39,11 @@ #include -asmlinkage void sha512_transform_ssse3(u64 *digest, const char *data, - u64 rounds); - -typedef void (sha512_transform_fn)(u64 *digest, const char *data, u64 rounds); +asmlinkage void sha512_transform_ssse3(struct sha512_state *state, + const u8 *data, int blocks); static int sha512_update(struct shash_desc *desc, const u8 *data, - unsigned int len, sha512_transform_fn *sha512_xform) + unsigned int len, sha512_block_fn *sha512_xform) { struct sha512_state *sctx = shash_desc_ctx(desc); @@ -53,28 +51,29 @@ static int sha512_update(struct shash_desc *desc, const u8 *data, (sctx->count[0] % SHA512_BLOCK_SIZE) + len < SHA512_BLOCK_SIZE) return crypto_sha512_update(desc, data, len); - /* make sure casting to sha512_block_fn() is safe */ + /* + * Make sure struct sha512_state begins directly with the SHA512 + * 512-bit internal state, as this is what the asm functions expect. + */ BUILD_BUG_ON(offsetof(struct sha512_state, state) != 0); kernel_fpu_begin(); - sha512_base_do_update(desc, data, len, - (sha512_block_fn *)sha512_xform); + sha512_base_do_update(desc, data, len, sha512_xform); kernel_fpu_end(); return 0; } static int sha512_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out, sha512_transform_fn *sha512_xform) + unsigned int len, u8 *out, sha512_block_fn *sha512_xform) { if (!irq_fpu_usable()) return crypto_sha512_finup(desc, data, len, out); kernel_fpu_begin(); if (len) - sha512_base_do_update(desc, data, len, - (sha512_block_fn *)sha512_xform); - sha512_base_do_finalize(desc, (sha512_block_fn *)sha512_xform); + sha512_base_do_update(desc, data, len, sha512_xform); + sha512_base_do_finalize(desc, sha512_xform); kernel_fpu_end(); return sha512_base_finish(desc, out); @@ -146,8 +145,8 @@ static void unregister_sha512_ssse3(void) } #ifdef CONFIG_AS_AVX -asmlinkage void sha512_transform_avx(u64 *digest, const char *data, - u64 rounds); +asmlinkage void sha512_transform_avx(struct sha512_state *state, + const u8 *data, int blocks); static bool avx_usable(void) { if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) { @@ -229,8 +228,8 @@ static inline void unregister_sha512_avx(void) { } #endif #if defined(CONFIG_AS_AVX2) && defined(CONFIG_AS_AVX) -asmlinkage void sha512_transform_rorx(u64 *digest, const char *data, - u64 rounds); +asmlinkage void sha512_transform_rorx(struct sha512_state *state, + const u8 *data, int blocks); static int sha512_avx2_update(struct shash_desc *desc, const u8 *data, unsigned int len) diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 389800344f6975f7381d4edc737c8aff09336ae8..ba5698dca9698592023a7baf429f5a8e5f4e46af 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -271,7 +271,7 @@ __visible inline void syscall_return_slowpath(struct pt_regs *regs) } #ifdef CONFIG_X86_64 -__visible void do_syscall_64(struct pt_regs *regs) +__nocfi __visible void do_syscall_64(struct pt_regs *regs) { struct thread_info *ti = current_thread_info(); unsigned long nr = regs->orig_ax; @@ -305,7 +305,7 @@ __visible void do_syscall_64(struct pt_regs *regs) * extremely hot in workloads that use it, and it's usually called from * do_fast_syscall_32, so forcibly inline it to improve performance. */ -static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) +static __nocfi __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) { struct thread_info *ti = current_thread_info(); unsigned int nr = (unsigned int)regs->orig_ax; diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 49adabd94f883faf7f9c93b9cbd1121e4c1243d4..c19974a493784e1cc40f75452a96179f1010625a 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -1057,6 +1057,7 @@ ENTRY(int3) END(int3) ENTRY(general_protection) + ASM_CLAC pushl $do_general_protection jmp common_exception END(general_protection) diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index ab7f730cf7f22172ab99cda4219c1e598245121f..d64dd8cbee3b845e8d98fc79cc3e3f4eaec6fe00 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -3,7 +3,6 @@ # Building vDSO images for x86. # -KBUILD_CFLAGS += $(DISABLE_LTO) KASAN_SANITIZE := n UBSAN_SANITIZE := n OBJECT_FILES_NON_STANDARD := y @@ -72,7 +71,7 @@ $(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso%.so $(obj)/vdso2c FORCE CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \ -fno-omit-frame-pointer -foptimize-sibling-calls \ - -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO + -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO $(DISABLE_LTO) ifdef CONFIG_RETPOLINE ifneq ($(RETPOLINE_VDSO_CFLAGS),) @@ -150,6 +149,8 @@ KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS_32)) +KBUILD_CFLAGS_32 := $(filter-out $(LTO_CFLAGS),$(KBUILD_CFLAGS_32)) +KBUILD_CFLAGS_32 := $(filter-out $(CFI_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector) KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) diff --git a/arch/x86/entry/vdso/vdso32-setup.c b/arch/x86/entry/vdso/vdso32-setup.c index 42d4c89f990ed1d752b24c641329671587313ba0..ddff0ca6f50981bfc53cfae86d81e9d2200a92a0 100644 --- a/arch/x86/entry/vdso/vdso32-setup.c +++ b/arch/x86/entry/vdso/vdso32-setup.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index defb536aebce2144db706672e62d3e5ee82fdbe3..c3ec535fd36b84d4e92c1ccea8d6d3ce64073ce9 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -245,6 +245,7 @@ static const u64 amd_f17h_perfmon_event_map[PERF_COUNT_HW_MAX] = [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, [PERF_COUNT_HW_CACHE_REFERENCES] = 0xff60, + [PERF_COUNT_HW_CACHE_MISSES] = 0x0964, [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x0287, diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c index baa7e36073f907b19a983459aa15e66a682b9f95..604a8558752d1d46dea98b9cf3238e82c8ecaeb6 100644 --- a/arch/x86/events/amd/uncore.c +++ b/arch/x86/events/amd/uncore.c @@ -193,20 +193,18 @@ static int amd_uncore_event_init(struct perf_event *event) /* * NB and Last level cache counters (MSRs) are shared across all cores - * that share the same NB / Last level cache. Interrupts can be directed - * to a single target core, however, event counts generated by processes - * running on other cores cannot be masked out. So we do not support - * sampling and per-thread events. + * that share the same NB / Last level cache. On family 16h and below, + * Interrupts can be directed to a single target core, however, event + * counts generated by processes running on other cores cannot be masked + * out. So we do not support sampling and per-thread events via + * CAP_NO_INTERRUPT, and we do not enable counter overflow interrupts: */ - if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) - return -EINVAL; /* NB and Last level cache counters do not have usr/os/guest/host bits */ if (event->attr.exclude_user || event->attr.exclude_kernel || event->attr.exclude_host || event->attr.exclude_guest) return -EINVAL; - /* and we do not enable counter overflow interrupts */ hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB; hwc->idx = -1; @@ -314,6 +312,7 @@ static struct pmu amd_nb_pmu = { .start = amd_uncore_start, .stop = amd_uncore_stop, .read = amd_uncore_read, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT, }; static struct pmu amd_llc_pmu = { @@ -324,6 +323,7 @@ static struct pmu amd_llc_pmu = { .start = amd_uncore_start, .stop = amd_uncore_stop, .read = amd_uncore_read, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT, }; static struct amd_uncore *amd_uncore_alloc(unsigned int cpu) diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 3310f9f6c3e14f5aa6193a4568103a553e9f62c1..550b7814ef92b12b26a7f3e86ee8a4179285abda 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -1368,6 +1368,8 @@ intel_pmu_save_and_restart_reload(struct perf_event *event, int count) old = ((s64)(prev_raw_count << shift) >> shift); local64_add(new - old + count * period, &event->count); + local64_set(&hwc->period_left, -new); + perf_event_update_userpage(event); return 0; diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index b4bef819d5d5365039d0039506d34503bee774ff..157cfaf1064c9e874185a0ee154f2e975c5835b3 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -205,7 +205,7 @@ #define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ - +#define X86_FEATURE_CDP_L2 ( 7*32+15) /* Code and Data Prioritization L2 */ #define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */ #define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */ #define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d0e17813a9b0a558b36c3cac76fdded9924b6601..9529fe69e1d927bb43199d0e8d1a57b4c2617f89 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1006,7 +1006,7 @@ struct kvm_x86_ops { void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu); void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa); - void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector); + int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector); int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); int (*get_tdp_level)(struct kvm_vcpu *vcpu); @@ -1032,7 +1032,7 @@ struct kvm_x86_ops { bool (*mpx_supported)(void); bool (*xsaves_supported)(void); - int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr); + int (*check_nested_events)(struct kvm_vcpu *vcpu); void (*sched_in)(struct kvm_vcpu *kvm, int cpu); diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index 209492849566cefc56305cd8e976fbf4a25d7527..5c524d4f71cd7b2a99b7037f7962e334f227a94c 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -41,7 +41,7 @@ struct microcode_amd { unsigned int mpb[0]; }; -#define PATCH_MAX_SIZE PAGE_SIZE +#define PATCH_MAX_SIZE (3 * PAGE_SIZE) #ifdef CONFIG_MICROCODE_AMD extern void __init load_ucode_amd_bsp(unsigned int family); diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 6a4b1a54ff479cf2ff018470351de45890625582..98a337e3835d68758297115cc6d9cbba8e5b657a 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -588,12 +588,15 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) return __pmd(val); } -/* mprotect needs to preserve PAT bits when updating vm_page_prot */ +/* + * mprotect needs to preserve PAT and encryption bits when updating + * vm_page_prot + */ #define pgprot_modify pgprot_modify static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) { pgprotval_t preservebits = pgprot_val(oldprot) & _PAGE_CHG_MASK; - pgprotval_t addbits = pgprot_val(newprot); + pgprotval_t addbits = pgprot_val(newprot) & ~_PAGE_CHG_MASK; return __pgprot(preservebits | addbits); } diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 85f8279c885ac36290b3ec57ebeb11848e3be596..e6c870c240657ed6e53c41f408699d47381c9760 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -124,7 +124,7 @@ */ #define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \ - _PAGE_SOFT_DIRTY | _PAGE_DEVMAP) + _PAGE_SOFT_DIRTY | _PAGE_DEVMAP | _PAGE_ENC) #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE) /* diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h index 5c019d23d06b1168da0ea965d7c35bebd4d02307..4c85f6db1e3df634adad2033e98899f9cb8bbb6b 100644 --- a/arch/x86/include/asm/sections.h +++ b/arch/x86/include/asm/sections.h @@ -6,7 +6,7 @@ #include extern char __brk_base[], __brk_limit[]; -extern struct exception_table_entry __stop___ex_table[]; +extern char __cfi_jt_start[], __cfi_jt_end[]; #if defined(CONFIG_X86_64) extern char __end_rodata_hpage_align[]; diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 6dda3595acf8571b750fb58236e889a5e991396f..40d7072be70984fae28a7881ff1f9fd397e9848a 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1738,7 +1738,7 @@ int __acpi_acquire_global_lock(unsigned int *lock) new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); val = cmpxchg(lock, old, new); } while (unlikely (val != old)); - return (new < 3) ? -1 : 0; + return ((new & 0x3) < 3) ? -1 : 0; } int __acpi_release_global_lock(unsigned int *lock) diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index dde437f5d14ff828dccff19275033ff2330acc60..596e7640d895a084c5b961503b8e3325f31cdca8 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c @@ -133,7 +133,8 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, /* Make sure we are running on right CPU */ - retval = work_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx); + retval = call_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx, + false); if (retval == 0) { /* Use the hint in CST */ percpu_entry->states[cx->index].eax = cx->address; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 3d805e8b373965c048ef4e52c2ec523e26d6e149..7b4141889919083c9d4800c7d08b97708339f2d1 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -360,7 +360,7 @@ static __always_inline void setup_pku(struct cpuinfo_x86 *c) * cpuid bit to be set. We need to ensure that we * update that bit in this CPU's "cpu_info". */ - get_cpu_cap(c); + set_cpu_cap(c, X86_FEATURE_OSPKE); } #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c index 3f731d7f04bf65f2726bd7b0349a12c3b995d88c..07742b69d914cd27aa2d0e5396a796fe8f6009fa 100644 --- a/arch/x86/kernel/cpu/intel_rdt.c +++ b/arch/x86/kernel/cpu/intel_rdt.c @@ -135,6 +135,40 @@ struct rdt_resource rdt_resources_all[] = { .format_str = "%d=%0*x", .fflags = RFTYPE_RES_CACHE, }, + [RDT_RESOURCE_L2DATA] = + { + .rid = RDT_RESOURCE_L2DATA, + .name = "L2DATA", + .domains = domain_init(RDT_RESOURCE_L2DATA), + .msr_base = IA32_L2_CBM_BASE, + .msr_update = cat_wrmsr, + .cache_level = 2, + .cache = { + .min_cbm_bits = 1, + .cbm_idx_mult = 2, + .cbm_idx_offset = 0, + }, + .parse_ctrlval = parse_cbm, + .format_str = "%d=%0*x", + .fflags = RFTYPE_RES_CACHE, + }, + [RDT_RESOURCE_L2CODE] = + { + .rid = RDT_RESOURCE_L2CODE, + .name = "L2CODE", + .domains = domain_init(RDT_RESOURCE_L2CODE), + .msr_base = IA32_L2_CBM_BASE, + .msr_update = cat_wrmsr, + .cache_level = 2, + .cache = { + .min_cbm_bits = 1, + .cbm_idx_mult = 2, + .cbm_idx_offset = 1, + }, + .parse_ctrlval = parse_cbm, + .format_str = "%d=%0*x", + .fflags = RFTYPE_RES_CACHE, + }, [RDT_RESOURCE_MBA] = { .rid = RDT_RESOURCE_MBA, @@ -259,15 +293,15 @@ static void rdt_get_cache_alloc_cfg(int idx, struct rdt_resource *r) r->alloc_enabled = true; } -static void rdt_get_cdp_l3_config(int type) +static void rdt_get_cdp_config(int level, int type) { - struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3]; + struct rdt_resource *r_l = &rdt_resources_all[level]; struct rdt_resource *r = &rdt_resources_all[type]; - r->num_closid = r_l3->num_closid / 2; - r->cache.cbm_len = r_l3->cache.cbm_len; - r->default_ctrl = r_l3->default_ctrl; - r->cache.shareable_bits = r_l3->cache.shareable_bits; + r->num_closid = r_l->num_closid / 2; + r->cache.cbm_len = r_l->cache.cbm_len; + r->default_ctrl = r_l->default_ctrl; + r->cache.shareable_bits = r_l->cache.shareable_bits; r->data_width = (r->cache.cbm_len + 3) / 4; r->alloc_capable = true; /* @@ -277,6 +311,18 @@ static void rdt_get_cdp_l3_config(int type) r->alloc_enabled = false; } +static void rdt_get_cdp_l3_config(void) +{ + rdt_get_cdp_config(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA); + rdt_get_cdp_config(RDT_RESOURCE_L3, RDT_RESOURCE_L3CODE); +} + +static void rdt_get_cdp_l2_config(void) +{ + rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA); + rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2CODE); +} + static int get_cache_id(int cpu, int level) { struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu); @@ -486,6 +532,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r) d->id = id; cpumask_set_cpu(cpu, &d->cpu_mask); + rdt_domain_reconfigure_cdp(r); + if (r->alloc_capable && domain_setup_ctrlval(r, d)) { kfree(d); return; @@ -729,15 +777,15 @@ static __init bool get_rdt_alloc_resources(void) if (rdt_cpu_has(X86_FEATURE_CAT_L3)) { rdt_get_cache_alloc_cfg(1, &rdt_resources_all[RDT_RESOURCE_L3]); - if (rdt_cpu_has(X86_FEATURE_CDP_L3)) { - rdt_get_cdp_l3_config(RDT_RESOURCE_L3DATA); - rdt_get_cdp_l3_config(RDT_RESOURCE_L3CODE); - } + if (rdt_cpu_has(X86_FEATURE_CDP_L3)) + rdt_get_cdp_l3_config(); ret = true; } if (rdt_cpu_has(X86_FEATURE_CAT_L2)) { /* CPUID 0x10.2 fields are same format at 0x10.1 */ rdt_get_cache_alloc_cfg(2, &rdt_resources_all[RDT_RESOURCE_L2]); + if (rdt_cpu_has(X86_FEATURE_CDP_L2)) + rdt_get_cdp_l2_config(); ret = true; } diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h index a43a72d8e88e45ef76a2dee5e5a4abbd0ecab308..b43a786ec15f24e1111980ae9d204fdbad9c4e6e 100644 --- a/arch/x86/kernel/cpu/intel_rdt.h +++ b/arch/x86/kernel/cpu/intel_rdt.h @@ -7,12 +7,15 @@ #include #define IA32_L3_QOS_CFG 0xc81 +#define IA32_L2_QOS_CFG 0xc82 #define IA32_L3_CBM_BASE 0xc90 #define IA32_L2_CBM_BASE 0xd10 #define IA32_MBA_THRTL_BASE 0xd50 #define L3_QOS_CDP_ENABLE 0x01ULL +#define L2_QOS_CDP_ENABLE 0x01ULL + /* * Event IDs are used to program IA32_QM_EVTSEL before reading event * counter from IA32_QM_CTR @@ -354,6 +357,8 @@ enum { RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3CODE, RDT_RESOURCE_L2, + RDT_RESOURCE_L2DATA, + RDT_RESOURCE_L2CODE, RDT_RESOURCE_MBA, /* Must be the last */ @@ -437,5 +442,6 @@ void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms); void cqm_handle_limbo(struct work_struct *work); bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d); void __check_limbo(struct rdt_domain *d, bool force_free); +void rdt_domain_reconfigure_cdp(struct rdt_resource *r); #endif /* _ASM_X86_INTEL_RDT_H */ diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 0ec30b2384c052c8299d3d72acf395618f2706f8..60c63b23e3baa8351b933c21fde99dd6ad15d450 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -922,6 +922,7 @@ mongroup_create_dir(struct kernfs_node *parent_kn, struct rdtgroup *prgrp, kernfs_remove(kn); return ret; } + static void l3_qos_cfg_update(void *arg) { bool *enable = arg; @@ -929,8 +930,17 @@ static void l3_qos_cfg_update(void *arg) wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL); } -static int set_l3_qos_cfg(struct rdt_resource *r, bool enable) +static void l2_qos_cfg_update(void *arg) +{ + bool *enable = arg; + + wrmsrl(IA32_L2_QOS_CFG, *enable ? L2_QOS_CDP_ENABLE : 0ULL); +} + +static int set_cache_qos_cfg(int level, bool enable) { + void (*update)(void *arg); + struct rdt_resource *r_l; cpumask_var_t cpu_mask; struct rdt_domain *d; int cpu; @@ -938,16 +948,24 @@ static int set_l3_qos_cfg(struct rdt_resource *r, bool enable) if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL)) return -ENOMEM; - list_for_each_entry(d, &r->domains, list) { + if (level == RDT_RESOURCE_L3) + update = l3_qos_cfg_update; + else if (level == RDT_RESOURCE_L2) + update = l2_qos_cfg_update; + else + return -EINVAL; + + r_l = &rdt_resources_all[level]; + list_for_each_entry(d, &r_l->domains, list) { /* Pick one CPU from each domain instance to update MSR */ cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask); } cpu = get_cpu(); /* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */ if (cpumask_test_cpu(cpu, cpu_mask)) - l3_qos_cfg_update(&enable); + update(&enable); /* Update QOS_CFG MSR on all other cpus in cpu_mask. */ - smp_call_function_many(cpu_mask, l3_qos_cfg_update, &enable, 1); + smp_call_function_many(cpu_mask, update, &enable, 1); put_cpu(); free_cpumask_var(cpu_mask); @@ -955,52 +973,99 @@ static int set_l3_qos_cfg(struct rdt_resource *r, bool enable) return 0; } -static int cdp_enable(void) +static int cdp_enable(int level, int data_type, int code_type) { - struct rdt_resource *r_l3data = &rdt_resources_all[RDT_RESOURCE_L3DATA]; - struct rdt_resource *r_l3code = &rdt_resources_all[RDT_RESOURCE_L3CODE]; - struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3]; + struct rdt_resource *r_ldata = &rdt_resources_all[data_type]; + struct rdt_resource *r_lcode = &rdt_resources_all[code_type]; + struct rdt_resource *r_l = &rdt_resources_all[level]; int ret; - if (!r_l3->alloc_capable || !r_l3data->alloc_capable || - !r_l3code->alloc_capable) + if (!r_l->alloc_capable || !r_ldata->alloc_capable || + !r_lcode->alloc_capable) return -EINVAL; - ret = set_l3_qos_cfg(r_l3, true); + ret = set_cache_qos_cfg(level, true); if (!ret) { - r_l3->alloc_enabled = false; - r_l3data->alloc_enabled = true; - r_l3code->alloc_enabled = true; + r_l->alloc_enabled = false; + r_ldata->alloc_enabled = true; + r_lcode->alloc_enabled = true; } return ret; } -static void cdp_disable(void) +static int cdpl3_enable(void) { - struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3]; + return cdp_enable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, + RDT_RESOURCE_L3CODE); +} + +static int cdpl2_enable(void) +{ + return cdp_enable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA, + RDT_RESOURCE_L2CODE); +} + +static void cdp_disable(int level, int data_type, int code_type) +{ + struct rdt_resource *r = &rdt_resources_all[level]; r->alloc_enabled = r->alloc_capable; - if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled) { - rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled = false; - rdt_resources_all[RDT_RESOURCE_L3CODE].alloc_enabled = false; - set_l3_qos_cfg(r, false); + if (rdt_resources_all[data_type].alloc_enabled) { + rdt_resources_all[data_type].alloc_enabled = false; + rdt_resources_all[code_type].alloc_enabled = false; + set_cache_qos_cfg(level, false); } } +static void cdpl3_disable(void) +{ + cdp_disable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3CODE); +} + +static void cdpl2_disable(void) +{ + cdp_disable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA, RDT_RESOURCE_L2CODE); +} + +static void cdp_disable_all(void) +{ + if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled) + cdpl3_disable(); + if (rdt_resources_all[RDT_RESOURCE_L2DATA].alloc_enabled) + cdpl2_disable(); +} + static int parse_rdtgroupfs_options(char *data) { char *token, *o = data; int ret = 0; while ((token = strsep(&o, ",")) != NULL) { - if (!*token) - return -EINVAL; + if (!*token) { + ret = -EINVAL; + goto out; + } - if (!strcmp(token, "cdp")) - ret = cdp_enable(); + if (!strcmp(token, "cdp")) { + ret = cdpl3_enable(); + if (ret) + goto out; + } else if (!strcmp(token, "cdpl2")) { + ret = cdpl2_enable(); + if (ret) + goto out; + } else { + ret = -EINVAL; + goto out; + } } + return 0; + +out: + pr_err("Invalid mount option \"%s\"\n", token); + return ret; } @@ -1155,7 +1220,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, out_info: kernfs_remove(kn_info); out_cdp: - cdp_disable(); + cdp_disable_all(); out: mutex_unlock(&rdtgroup_mutex); cpus_read_unlock(); @@ -1322,7 +1387,7 @@ static void rdt_kill_sb(struct super_block *sb) /*Put everything back to default values. */ for_each_alloc_enabled_rdt_resource(r) reset_all_ctrls(r); - cdp_disable(); + cdp_disable_all(); rmdir_all_sub(); static_branch_disable_cpuslocked(&rdt_alloc_enable_key); static_branch_disable_cpuslocked(&rdt_mon_enable_key); @@ -1692,6 +1757,19 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, return ret; } +/* Restore the qos cfg state when a domain comes online */ +void rdt_domain_reconfigure_cdp(struct rdt_resource *r) +{ + if (!r->alloc_capable) + return; + + if (r == &rdt_resources_all[RDT_RESOURCE_L2DATA]) + l2_qos_cfg_update(&r->alloc_enabled); + + if (r == &rdt_resources_all[RDT_RESOURCE_L3DATA]) + l3_qos_cfg_update(&r->alloc_enabled); +} + /* * We allow creating mon groups only with in a directory called "mon_groups" * which is present in every ctrl_mon group. Check if this is a valid @@ -1840,7 +1918,8 @@ static int rdtgroup_rmdir(struct kernfs_node *kn) * If the rdtgroup is a mon group and parent directory * is a valid "mon_groups" directory, remove the mon group. */ - if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn) + if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn && + rdtgrp != &rdtgroup_default) ret = rdtgroup_rmdir_ctrl(kn, rdtgrp, tmpmask); else if (rdtgrp->type == RDTMON_GROUP && is_mon_groups(parent_kn, kn->name)) diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c index f12141ba9a76d59963d2f87e6a0177e86742237c..e57b59762f9f5f7b33126cea9de96c4dfd8eaf02 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-inject.c +++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c @@ -46,8 +46,6 @@ static struct mce i_mce; static struct dentry *dfs_inj; -static u8 n_banks; - #define MAX_FLAG_OPT_SIZE 4 #define NBCFG 0x44 @@ -570,9 +568,15 @@ static void do_inject(void) static int inj_bank_set(void *data, u64 val) { struct mce *m = (struct mce *)data; + u8 n_banks; + u64 cap; + + /* Get bank count on target CPU so we can handle non-uniform values. */ + rdmsrl_on_cpu(m->extcpu, MSR_IA32_MCG_CAP, &cap); + n_banks = cap & MCG_BANKCNT_MASK; if (val >= n_banks) { - pr_err("Non-existent MCE bank: %llu\n", val); + pr_err("MCA bank %llu non-existent on CPU%d\n", val, m->extcpu); return -EINVAL; } @@ -665,10 +669,6 @@ static struct dfs_node { static int __init debugfs_init(void) { unsigned int i; - u64 cap; - - rdmsrl(MSR_IA32_MCG_CAP, cap); - n_banks = cap & MCG_BANKCNT_MASK; dfs_inj = debugfs_create_dir("mce-inject", NULL); if (!dfs_inj) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 0b0e44f853931a86b4fa6ad7e0d4f264e945f68b..95c09db1bba214680433eac27543e1a955ad48a1 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1499,13 +1499,12 @@ EXPORT_SYMBOL_GPL(mce_notify_irq); static int __mcheck_cpu_mce_banks_init(void) { int i; - u8 num_banks = mca_cfg.banks; - mce_banks = kzalloc(num_banks * sizeof(struct mce_bank), GFP_KERNEL); + mce_banks = kcalloc(MAX_NR_BANKS, sizeof(struct mce_bank), GFP_KERNEL); if (!mce_banks) return -ENOMEM; - for (i = 0; i < num_banks; i++) { + for (i = 0; i < MAX_NR_BANKS; i++) { struct mce_bank *b = &mce_banks[i]; b->ctl = -1ULL; @@ -1519,28 +1518,19 @@ static int __mcheck_cpu_mce_banks_init(void) */ static int __mcheck_cpu_cap_init(void) { - unsigned b; u64 cap; + u8 b; rdmsrl(MSR_IA32_MCG_CAP, cap); b = cap & MCG_BANKCNT_MASK; - if (!mca_cfg.banks) - pr_info("CPU supports %d MCE banks\n", b); - - if (b > MAX_NR_BANKS) { - pr_warn("Using only %u machine check banks out of %u\n", - MAX_NR_BANKS, b); + if (WARN_ON_ONCE(b > MAX_NR_BANKS)) b = MAX_NR_BANKS; - } - /* Don't support asymmetric configurations today */ - WARN_ON(mca_cfg.banks != 0 && b != mca_cfg.banks); - mca_cfg.banks = b; + mca_cfg.banks = max(mca_cfg.banks, b); if (!mce_banks) { int err = __mcheck_cpu_mce_banks_init(); - if (err) return err; } @@ -2470,6 +2460,8 @@ EXPORT_SYMBOL_GPL(mcsafe_key); static int __init mcheck_late_init(void) { + pr_info("Using %d MCE banks\n", mca_cfg.banks); + if (mca_cfg.recovery) static_branch_inc(&mcsafe_key); diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index a8f47697276b60b676a6ca969cf607b509568abd..bbe94b682119ebb5913ab2ee5296dc9eb5337007 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -1116,9 +1116,12 @@ static const struct sysfs_ops threshold_ops = { .store = store, }; +static void threshold_block_release(struct kobject *kobj); + static struct kobj_type threshold_ktype = { .sysfs_ops = &threshold_ops, .default_attrs = default_attrs, + .release = threshold_block_release, }; static const char *get_name(unsigned int bank, struct threshold_block *b) @@ -1151,8 +1154,9 @@ static const char *get_name(unsigned int bank, struct threshold_block *b) return buf_mcatype; } -static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, - unsigned int block, u32 address) +static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb, + unsigned int bank, unsigned int block, + u32 address) { struct threshold_block *b = NULL; u32 low, high; @@ -1196,16 +1200,12 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, INIT_LIST_HEAD(&b->miscj); - if (per_cpu(threshold_banks, cpu)[bank]->blocks) { - list_add(&b->miscj, - &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj); - } else { - per_cpu(threshold_banks, cpu)[bank]->blocks = b; - } + if (tb->blocks) + list_add(&b->miscj, &tb->blocks->miscj); + else + tb->blocks = b; - err = kobject_init_and_add(&b->kobj, &threshold_ktype, - per_cpu(threshold_banks, cpu)[bank]->kobj, - get_name(bank, b)); + err = kobject_init_and_add(&b->kobj, &threshold_ktype, tb->kobj, get_name(bank, b)); if (err) goto out_free; recurse: @@ -1213,7 +1213,7 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, if (!address) return 0; - err = allocate_threshold_blocks(cpu, bank, block, address); + err = allocate_threshold_blocks(cpu, tb, bank, block, address); if (err) goto out_free; @@ -1298,8 +1298,6 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) goto out_free; } - per_cpu(threshold_banks, cpu)[bank] = b; - if (is_shared_bank(bank)) { refcount_set(&b->cpus, 1); @@ -1310,9 +1308,13 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) } } - err = allocate_threshold_blocks(cpu, bank, 0, msr_ops.misc(bank)); - if (!err) - goto out; + err = allocate_threshold_blocks(cpu, b, bank, 0, msr_ops.misc(bank)); + if (err) + goto out_free; + + per_cpu(threshold_banks, cpu)[bank] = b; + + return 0; out_free: kfree(b); @@ -1321,8 +1323,12 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) return err; } -static void deallocate_threshold_block(unsigned int cpu, - unsigned int bank) +static void threshold_block_release(struct kobject *kobj) +{ + kfree(to_block(kobj)); +} + +static void deallocate_threshold_block(unsigned int cpu, unsigned int bank) { struct threshold_block *pos = NULL; struct threshold_block *tmp = NULL; @@ -1332,13 +1338,11 @@ static void deallocate_threshold_block(unsigned int cpu, return; list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) { - kobject_put(&pos->kobj); list_del(&pos->miscj); - kfree(pos); + kobject_put(&pos->kobj); } - kfree(per_cpu(threshold_banks, cpu)[bank]->blocks); - per_cpu(threshold_banks, cpu)[bank]->blocks = NULL; + kobject_put(&head->blocks->kobj); } static void __threshold_remove_blocks(struct threshold_bank *b) diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c index d05be307d081a67c12eef433b5c832fcfcffa1a7..1d87b85150dbd5bb527a92c396823ecab7cbf61d 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -489,17 +489,18 @@ static void intel_ppin_init(struct cpuinfo_x86 *c) return; if ((val & 3UL) == 1UL) { - /* PPIN available but disabled: */ + /* PPIN locked in disabled mode */ return; } - /* If PPIN is disabled, but not locked, try to enable: */ - if (!(val & 3UL)) { + /* If PPIN is disabled, try to enable */ + if (!(val & 2UL)) { wrmsrl_safe(MSR_PPIN_CTL, val | 2UL); rdmsrl_safe(MSR_PPIN_CTL, &val); } - if ((val & 3UL) == 2UL) + /* Is the enable bit set? */ + if (val & 2UL) set_cpu_cap(c, X86_FEATURE_INTEL_PPIN); } } diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index c0201b11e9e2a36439853975318c77521f680082..a6b323a3a63047cb54643052b92f33fbb0f17979 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -178,8 +178,8 @@ static void __init ms_hyperv_init_platform(void) ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES); ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); - pr_info("Hyper-V: features 0x%x, hints 0x%x\n", - ms_hyperv.features, ms_hyperv.hints); + pr_info("Hyper-V: features 0x%x, hints 0x%x, misc 0x%x\n", + ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features); ms_hyperv.max_vp_index = cpuid_eax(HVCPUID_IMPLEMENTATION_LIMITS); ms_hyperv.max_lp_index = cpuid_ebx(HVCPUID_IMPLEMENTATION_LIMITS); diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index ed7ce5184a772d2cddb5124ed6f005e445983b08..0b9c7150cb23f00ac777232e226e7a299672e9b9 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -28,6 +28,7 @@ static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 }, { X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 }, { X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 }, + { X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 }, { X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 }, { X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, diff --git a/arch/x86/kernel/cpu/tsx.c b/arch/x86/kernel/cpu/tsx.c index 3e20d322bc98b636cde2747394d26fcec8783a0c..032509adf9de9f664e808083955de464a35f9d34 100644 --- a/arch/x86/kernel/cpu/tsx.c +++ b/arch/x86/kernel/cpu/tsx.c @@ -115,11 +115,12 @@ void __init tsx_init(void) tsx_disable(); /* - * tsx_disable() will change the state of the - * RTM CPUID bit. Clear it here since it is now - * expected to be not set. + * tsx_disable() will change the state of the RTM and HLE CPUID + * bits. Clear them here since they are now expected to be not + * set. */ setup_clear_cpu_cap(X86_FEATURE_RTM); + setup_clear_cpu_cap(X86_FEATURE_HLE); } else if (tsx_ctrl_state == TSX_CTRL_ENABLE) { /* @@ -131,10 +132,10 @@ void __init tsx_init(void) tsx_enable(); /* - * tsx_enable() will change the state of the - * RTM CPUID bit. Force it here since it is now - * expected to be set. + * tsx_enable() will change the state of the RTM and HLE CPUID + * bits. Force them here since they are now expected to be set. */ setup_force_cpu_cap(X86_FEATURE_RTM); + setup_force_cpu_cap(X86_FEATURE_HLE); } } diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index d805202c63cdccfeaa303f5a5e14cd38ee6341d7..917840ed5fe47c585d13ab7081a2093cf381b28c 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -45,7 +45,7 @@ #define VMWARE_PORT_CMD_VCPU_RESERVED 31 #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ - __asm__("inl (%%dx)" : \ + __asm__("inl (%%dx), %%eax" : \ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ "0"(VMWARE_HYPERVISOR_MAGIC), \ "1"(VMWARE_PORT_CMD_##cmd), \ diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index ccc2b9d2956aa4a80e3a0cb3f82346b84df190b4..387340b1f6dbf9ecc8b26c4ef329e5eb30a3d196 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -36,6 +36,7 @@ #ifdef CONFIG_DYNAMIC_FTRACE int ftrace_arch_code_modify_prepare(void) + __acquires(&text_mutex) { mutex_lock(&text_mutex); set_kernel_text_rw(); @@ -44,6 +45,7 @@ int ftrace_arch_code_modify_prepare(void) } int ftrace_arch_code_modify_post_process(void) + __releases(&text_mutex) { set_all_modules_text_ro(); set_kernel_text_ro(); diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index f58336af095c9d3050e85c5dea79a164b275e420..fcd4d7b7d33020357d975284289d108a6802db4e 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -201,6 +201,10 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, goto overflow; #endif break; + case R_X86_64_8: + if (!strncmp(strtab + sym->st_name, "__typeid__", 10)) + break; + /* fallthrough */ default: pr_err("%s: Unknown rela relocation: %llu\n", me->name, ELF64_R_TYPE(rel[i].r_info)); diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c index 85195d447a922785857db0caacc73d6bc9b9490c..f3215346e47fd8d822191d9ff879896e1f5e7a4f 100644 --- a/arch/x86/kernel/sysfb_simplefb.c +++ b/arch/x86/kernel/sysfb_simplefb.c @@ -94,11 +94,11 @@ __init int create_simplefb(const struct screen_info *si, if (si->orig_video_isVGA == VIDEO_TYPE_VLFB) size <<= 16; length = mode->height * mode->stride; - length = PAGE_ALIGN(length); if (length > size) { printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n"); return -EINVAL; } + length = PAGE_ALIGN(length); /* setup IORESOURCE_MEM as framebuffer memory */ memset(&res, 0, sizeof(res)); diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 2384a2ae5ec3e9db7e660d80b45dfc4287cb9139..2e994fff9164b6fc9d2dbc5cb93ca1d1fe0bf6ea 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -132,15 +132,20 @@ SECTIONS __indirect_thunk_end = .; #endif - /* End of text section */ - _etext = .; +#ifdef CONFIG_CFI_CLANG + . = ALIGN(PAGE_SIZE); + __cfi_jt_start = .; + *(.text..L.cfi.jumptable .text..L.cfi.jumptable.*) + __cfi_jt_end = .; +#endif } :text = 0x9090 NOTES :text :note EXCEPTION_TABLE(16) :text = 0x9090 - /* .text should occupy whole number of pages */ + /* End of text section, which should occupy whole number of pages */ + _etext = .; . = ALIGN(PAGE_SIZE); X64_ALIGN_RODATA_BEGIN RO_DATA(PAGE_SIZE) @@ -352,7 +357,7 @@ SECTIONS .bss : AT(ADDR(.bss) - LOAD_OFFSET) { __bss_start = .; *(.bss..page_aligned) - *(.bss) + *(BSS_MAIN) . = ALIGN(PAGE_SIZE); __bss_stop = .; } @@ -414,3 +419,7 @@ INIT_PER_CPU(irq_stack_union); "kexec control code size is too big"); #endif +#ifdef CONFIG_CFI_CLANG +. = ASSERT((__cfi_jt_end - __cfi_jt_start > 0), + "CFI jump table is empty"); +#endif diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 38959b173a4232d61bdfeff5621b588a69919166..6ec1cfd0addd89c0b2919a20153744c4ebabc2d3 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -291,13 +291,18 @@ static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry, { switch (func) { case 0: - entry->eax = 1; /* only one leaf currently */ + entry->eax = 7; ++*nent; break; case 1: entry->ecx = F(MOVBE); ++*nent; break; + case 7: + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + if (index == 0) + entry->ecx = F(RDPID); + ++*nent; default: break; } @@ -489,7 +494,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->edx |= F(SPEC_CTRL); if (boot_cpu_has(X86_FEATURE_STIBP)) entry->edx |= F(INTEL_STIBP); - if (boot_cpu_has(X86_FEATURE_SSBD)) + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) || + boot_cpu_has(X86_FEATURE_AMD_SSBD)) entry->edx |= F(SPEC_CTRL_SSBD); /* * We emulate ARCH_CAPABILITIES in software even diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index eb8b843325f4cd0bf8cd64880731a206f7bae539..4cc8a4a6f1d00946ed2379f3363fcd8ca6fb5316 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -3539,6 +3539,16 @@ static int em_cwd(struct x86_emulate_ctxt *ctxt) return X86EMUL_CONTINUE; } +static int em_rdpid(struct x86_emulate_ctxt *ctxt) +{ + u64 tsc_aux = 0; + + if (ctxt->ops->get_msr(ctxt, MSR_TSC_AUX, &tsc_aux)) + return emulate_gp(ctxt, 0); + ctxt->dst.val = tsc_aux; + return X86EMUL_CONTINUE; +} + static int em_rdtsc(struct x86_emulate_ctxt *ctxt) { u64 tsc = 0; @@ -4431,10 +4441,20 @@ static const struct opcode group8[] = { F(DstMem | SrcImmByte | Lock | PageTable, em_btc), }; +/* + * The "memory" destination is actually always a register, since we come + * from the register case of group9. + */ +static const struct gprefix pfx_0f_c7_7 = { + N, N, N, II(DstMem | ModRM | Op3264 | EmulateOnUD, em_rdpid, rdtscp), +}; + + static const struct group_dual group9 = { { N, I(DstMem64 | Lock | PageTable, em_cmpxchg8b), N, N, N, N, N, N, }, { - N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, + GP(0, &pfx_0f_c7_7), } }; static const struct opcode group11[] = { @@ -5042,6 +5062,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) ctxt->fetch.ptr = ctxt->fetch.data; ctxt->fetch.end = ctxt->fetch.data + insn_len; ctxt->opcode_len = 1; + ctxt->intercept = x86_intercept_none; if (insn_len > 0) memcpy(ctxt->fetch.data, insn, insn_len); else { @@ -5094,16 +5115,28 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) ctxt->ad_bytes = def_ad_bytes ^ 6; break; case 0x26: /* ES override */ + has_seg_override = true; + ctxt->seg_override = VCPU_SREG_ES; + break; case 0x2e: /* CS override */ + has_seg_override = true; + ctxt->seg_override = VCPU_SREG_CS; + break; case 0x36: /* SS override */ + has_seg_override = true; + ctxt->seg_override = VCPU_SREG_SS; + break; case 0x3e: /* DS override */ has_seg_override = true; - ctxt->seg_override = (ctxt->b >> 3) & 3; + ctxt->seg_override = VCPU_SREG_DS; break; case 0x64: /* FS override */ + has_seg_override = true; + ctxt->seg_override = VCPU_SREG_FS; + break; case 0x65: /* GS override */ has_seg_override = true; - ctxt->seg_override = ctxt->b & 7; + ctxt->seg_override = VCPU_SREG_GS; break; case 0x40 ... 0x4f: /* REX */ if (mode != X86EMUL_MODE_PROT64) @@ -5187,10 +5220,15 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) } break; case Escape: - if (ctxt->modrm > 0xbf) - opcode = opcode.u.esc->high[ctxt->modrm - 0xc0]; - else + if (ctxt->modrm > 0xbf) { + size_t size = ARRAY_SIZE(opcode.u.esc->high); + u32 index = array_index_nospec( + ctxt->modrm - 0xc0, size); + + opcode = opcode.u.esc->high[index]; + } else { opcode = opcode.u.esc->op[(ctxt->modrm >> 3) & 7]; + } break; case InstrDual: if ((ctxt->modrm >> 6) == 3) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 5d13abecb384514029d6991dc60efdc983a00d27..2fba82b06c2d5d0448705098bb3806b938b84035 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -747,11 +747,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu, u32 index, u64 *pdata) { struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; + size_t size = ARRAY_SIZE(hv->hv_crash_param); - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param))) + if (WARN_ON_ONCE(index >= size)) return -EINVAL; - *pdata = hv->hv_crash_param[index]; + *pdata = hv->hv_crash_param[array_index_nospec(index, size)]; return 0; } @@ -790,11 +791,12 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, u32 index, u64 data) { struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; + size_t size = ARRAY_SIZE(hv->hv_crash_param); - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param))) + if (WARN_ON_ONCE(index >= size)) return -EINVAL; - hv->hv_crash_param[index] = data; + hv->hv_crash_param[array_index_nospec(index, size)] = data; return 0; } diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index bdcd4139eca9233bbd9e82615a1ed3c45c2ad060..38a36a1cc87fe14746a40055b1a5c998abd315a4 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -460,10 +460,14 @@ static int picdev_write(struct kvm_pic *s, switch (addr) { case 0x20: case 0x21: + pic_lock(s); + pic_ioport_write(&s->pics[0], addr, data); + pic_unlock(s); + break; case 0xa0: case 0xa1: pic_lock(s); - pic_ioport_write(&s->pics[addr >> 7], addr, data); + pic_ioport_write(&s->pics[1], addr, data); pic_unlock(s); break; case 0x4d0: diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 9d270ba9643ca85291a62498687d6cbc1c70e667..dab6940ea99cb3b1bc2384839d9528337a526d52 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -73,13 +74,14 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, default: { u32 redir_index = (ioapic->ioregsel - 0x10) >> 1; - u64 redir_content; + u64 redir_content = ~0ULL; - if (redir_index < IOAPIC_NUM_PINS) - redir_content = - ioapic->redirtbl[redir_index].bits; - else - redir_content = ~0ULL; + if (redir_index < IOAPIC_NUM_PINS) { + u32 index = array_index_nospec( + redir_index, IOAPIC_NUM_PINS); + + redir_content = ioapic->redirtbl[index].bits; + } result = (ioapic->ioregsel & 0x1) ? (redir_content >> 32) & 0xffffffff : @@ -297,6 +299,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) ioapic_debug("change redir index %x val %x\n", index, val); if (index >= IOAPIC_NUM_PINS) return; + index = array_index_nospec(index, IOAPIC_NUM_PINS); e = &ioapic->redirtbl[index]; mask_before = e->fields.mask; /* Preserve read-only fields */ diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 3cc3b2d130a0c277e6b4cb6f59aa2a391d2253f6..4d000aea05e09bd0d511796f757f4a485194d05e 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -427,7 +427,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, kvm_set_msi_irq(vcpu->kvm, entry, &irq); - if (irq.level && kvm_apic_match_dest(vcpu, NULL, 0, + if (irq.trig_mode && kvm_apic_match_dest(vcpu, NULL, 0, irq.dest_id, irq.dest_mode)) __set_bit(irq.vector, ioapic_handled_vectors); } diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 2307f63efd2066d74a1f6b3748152667b1cfb625..537c36b55b5d73e115ec392857a7d25d6db81a7d 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -566,9 +566,11 @@ static inline bool pv_eoi_enabled(struct kvm_vcpu *vcpu) static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu) { u8 val; - if (pv_eoi_get_user(vcpu, &val) < 0) + if (pv_eoi_get_user(vcpu, &val) < 0) { apic_debug("Can't read EOI MSR value: 0x%llx\n", (unsigned long long)vcpu->arch.pv_eoi.msr_val); + return false; + } return val & 0x1; } @@ -993,11 +995,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, apic_clear_vector(vector, apic->regs + APIC_TMR); } - if (vcpu->arch.apicv_active) - kvm_x86_ops->deliver_posted_interrupt(vcpu, vector); - else { + if (kvm_x86_ops->deliver_posted_interrupt(vcpu, vector)) { kvm_lapic_set_irr(vector, apic); - kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); } @@ -1754,15 +1753,20 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_LVTTHMR: case APIC_LVTPC: case APIC_LVT1: - case APIC_LVTERR: + case APIC_LVTERR: { /* TODO: Check vector */ + size_t size; + u32 index; + if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; - - val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4]; + size = ARRAY_SIZE(apic_lvt_mask); + index = array_index_nospec( + (reg - APIC_LVTT) >> 4, size); + val &= apic_lvt_mask[index]; kvm_lapic_set_reg(apic, reg, val); - break; + } case APIC_LVTT: if (!kvm_apic_sw_enabled(apic)) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index c0b0135ef07f0e982a85888fd28d8d8b51d95c11..e5af08b581320ca617909d3748f9896b050f130e 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1165,12 +1165,12 @@ static bool mmu_gfn_lpage_is_disallowed(struct kvm_vcpu *vcpu, gfn_t gfn, return __mmu_gfn_lpage_is_disallowed(gfn, level, slot); } -static int host_mapping_level(struct kvm *kvm, gfn_t gfn) +static int host_mapping_level(struct kvm_vcpu *vcpu, gfn_t gfn) { unsigned long page_size; int i, ret = 0; - page_size = kvm_host_page_size(kvm, gfn); + page_size = kvm_host_page_size(vcpu, gfn); for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) { if (page_size >= KVM_HPAGE_SIZE(i)) @@ -1220,7 +1220,7 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn, if (unlikely(*force_pt_level)) return PT_PAGE_TABLE_LEVEL; - host_level = host_mapping_level(vcpu->kvm, large_gfn); + host_level = host_mapping_level(vcpu, large_gfn); if (host_level == PT_PAGE_TABLE_LEVEL) return host_level; diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c index e9ea2d45ae66baa65a2e3818e7120189bcd61e57..1209447d6014da7279d2aefff94f6e12b992def5 100644 --- a/arch/x86/kvm/mtrr.c +++ b/arch/x86/kvm/mtrr.c @@ -202,11 +202,15 @@ static bool fixed_msr_to_seg_unit(u32 msr, int *seg, int *unit) break; case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000: *seg = 1; - *unit = msr - MSR_MTRRfix16K_80000; + *unit = array_index_nospec( + msr - MSR_MTRRfix16K_80000, + MSR_MTRRfix16K_A0000 - MSR_MTRRfix16K_80000 + 1); break; case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000: *seg = 2; - *unit = msr - MSR_MTRRfix4K_C0000; + *unit = array_index_nospec( + msr - MSR_MTRRfix4K_C0000, + MSR_MTRRfix4K_F8000 - MSR_MTRRfix4K_C0000 + 1); break; default: return false; diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index a9a62b9a73e25c3594fb1a537db7c498213cdfcd..c67a636b268ff162e42a0cbca393d680d0fe318d 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -2,6 +2,8 @@ #ifndef __KVM_X86_PMU_H #define __KVM_X86_PMU_H +#include + #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu) @@ -81,8 +83,12 @@ static inline bool pmc_is_enabled(struct kvm_pmc *pmc) static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr, u32 base) { - if (msr >= base && msr < base + pmu->nr_arch_gp_counters) - return &pmu->gp_counters[msr - base]; + if (msr >= base && msr < base + pmu->nr_arch_gp_counters) { + u32 index = array_index_nospec(msr - base, + pmu->nr_arch_gp_counters); + + return &pmu->gp_counters[index]; + } return NULL; } @@ -92,8 +98,12 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr) { int base = MSR_CORE_PERF_FIXED_CTR0; - if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) - return &pmu->fixed_counters[msr - base]; + if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) { + u32 index = array_index_nospec(msr - base, + pmu->nr_arch_fixed_counters); + + return &pmu->fixed_counters[index]; + } return NULL; } diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c index 2729131fe9bfc6d68160100a65e587cd53127622..84ae4dd261caff611a6dff9bd3aae3360a0f37c3 100644 --- a/arch/x86/kvm/pmu_intel.c +++ b/arch/x86/kvm/pmu_intel.c @@ -87,10 +87,14 @@ static unsigned intel_find_arch_event(struct kvm_pmu *pmu, static unsigned intel_find_fixed_event(int idx) { - if (idx >= ARRAY_SIZE(fixed_pmc_events)) + u32 event; + size_t size = ARRAY_SIZE(fixed_pmc_events); + + if (idx >= size) return PERF_COUNT_HW_MAX; - return intel_arch_events[fixed_pmc_events[idx]].event_type; + event = fixed_pmc_events[array_index_nospec(idx, size)]; + return intel_arch_events[event].event_type; } /* check if a PMC is enabled by comparing it with globl_ctrl bits. */ @@ -131,15 +135,19 @@ static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu, struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); bool fixed = idx & (1u << 30); struct kvm_pmc *counters; + unsigned int num_counters; idx &= ~(3u << 30); - if (!fixed && idx >= pmu->nr_arch_gp_counters) - return NULL; - if (fixed && idx >= pmu->nr_arch_fixed_counters) + if (fixed) { + counters = pmu->fixed_counters; + num_counters = pmu->nr_arch_fixed_counters; + } else { + counters = pmu->gp_counters; + num_counters = pmu->nr_arch_gp_counters; + } + if (idx >= num_counters) return NULL; - counters = fixed ? pmu->fixed_counters : pmu->gp_counters; - - return &counters[idx]; + return &counters[array_index_nospec(idx, num_counters)]; } static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 52edb8cf1c400565556c325e55c5b2bdc7d73ac0..d636213864185958833505112e8157f79b144c27 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1088,6 +1088,47 @@ static int avic_ga_log_notifier(u32 ga_tag) return 0; } +/* + * The default MMIO mask is a single bit (excluding the present bit), + * which could conflict with the memory encryption bit. Check for + * memory encryption support and override the default MMIO mask if + * memory encryption is enabled. + */ +static __init void svm_adjust_mmio_mask(void) +{ + unsigned int enc_bit, mask_bit; + u64 msr, mask; + + /* If there is no memory encryption support, use existing mask */ + if (cpuid_eax(0x80000000) < 0x8000001f) + return; + + /* If memory encryption is not enabled, use existing mask */ + rdmsrl(MSR_K8_SYSCFG, msr); + if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT)) + return; + + enc_bit = cpuid_ebx(0x8000001f) & 0x3f; + mask_bit = boot_cpu_data.x86_phys_bits; + + /* Increment the mask bit if it is the same as the encryption bit */ + if (enc_bit == mask_bit) + mask_bit++; + + /* + * If the mask bit location is below 52, then some bits above the + * physical addressing limit will always be reserved, so use the + * rsvd_bits() function to generate the mask. This mask, along with + * the present bit, will be used to generate a page fault with + * PFER.RSV = 1. + * + * If the mask bit location is 52 (or above), then clear the mask. + */ + mask = (mask_bit < 52) ? rsvd_bits(mask_bit, 51) | PT_PRESENT_MASK : 0; + + kvm_mmu_set_mmio_spte_mask(mask, mask); +} + static __init int svm_hardware_setup(void) { int cpu; @@ -1123,6 +1164,8 @@ static __init int svm_hardware_setup(void) kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); } + svm_adjust_mmio_mask(); + for_each_possible_cpu(cpu) { r = svm_cpu_init(cpu); if (r) @@ -4631,8 +4674,11 @@ static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) return; } -static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec) +static int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec) { + if (!vcpu->arch.apicv_active) + return -1; + kvm_lapic_set_irr(vec, vcpu->arch.apic); smp_mb__after_atomic(); @@ -4641,6 +4687,8 @@ static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec) kvm_cpu_get_apicid(vcpu->cpu)); else kvm_vcpu_wake_up(vcpu); + + return 0; } static bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c579cda1721e18d6703384be5063e859ec9fcc41..c139dedec12bc028ec34adbab6097cd79c51b37f 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1674,43 +1674,15 @@ static void vmcs_load(struct vmcs *vmcs) } #ifdef CONFIG_KEXEC_CORE -/* - * This bitmap is used to indicate whether the vmclear - * operation is enabled on all cpus. All disabled by - * default. - */ -static cpumask_t crash_vmclear_enabled_bitmap = CPU_MASK_NONE; - -static inline void crash_enable_local_vmclear(int cpu) -{ - cpumask_set_cpu(cpu, &crash_vmclear_enabled_bitmap); -} - -static inline void crash_disable_local_vmclear(int cpu) -{ - cpumask_clear_cpu(cpu, &crash_vmclear_enabled_bitmap); -} - -static inline int crash_local_vmclear_enabled(int cpu) -{ - return cpumask_test_cpu(cpu, &crash_vmclear_enabled_bitmap); -} - static void crash_vmclear_local_loaded_vmcss(void) { int cpu = raw_smp_processor_id(); struct loaded_vmcs *v; - if (!crash_local_vmclear_enabled(cpu)) - return; - list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu), loaded_vmcss_on_cpu_link) vmcs_clear(v->vmcs); } -#else -static inline void crash_enable_local_vmclear(int cpu) { } -static inline void crash_disable_local_vmclear(int cpu) { } #endif /* CONFIG_KEXEC_CORE */ static void __loaded_vmcs_clear(void *arg) @@ -1722,19 +1694,24 @@ static void __loaded_vmcs_clear(void *arg) return; /* vcpu migration can race with cpu offline */ if (per_cpu(current_vmcs, cpu) == loaded_vmcs->vmcs) per_cpu(current_vmcs, cpu) = NULL; - crash_disable_local_vmclear(cpu); + + vmcs_clear(loaded_vmcs->vmcs); + if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched) + vmcs_clear(loaded_vmcs->shadow_vmcs); + list_del(&loaded_vmcs->loaded_vmcss_on_cpu_link); /* - * we should ensure updating loaded_vmcs->loaded_vmcss_on_cpu_link - * is before setting loaded_vmcs->vcpu to -1 which is done in - * loaded_vmcs_init. Otherwise, other cpu can see vcpu = -1 fist - * then adds the vmcs into percpu list before it is deleted. + * Ensure all writes to loaded_vmcs, including deleting it from its + * current percpu list, complete before setting loaded_vmcs->vcpu to + * -1, otherwise a different cpu can see vcpu == -1 first and add + * loaded_vmcs to its percpu list before it's deleted from this cpu's + * list. Pairs with the smp_rmb() in vmx_vcpu_load_vmcs(). */ smp_wmb(); - loaded_vmcs_init(loaded_vmcs); - crash_enable_local_vmclear(cpu); + loaded_vmcs->cpu = -1; + loaded_vmcs->launched = 0; } static void loaded_vmcs_clear(struct loaded_vmcs *loaded_vmcs) @@ -2497,18 +2474,17 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (!already_loaded) { loaded_vmcs_clear(vmx->loaded_vmcs); local_irq_disable(); - crash_disable_local_vmclear(cpu); /* - * Read loaded_vmcs->cpu should be before fetching - * loaded_vmcs->loaded_vmcss_on_cpu_link. - * See the comments in __loaded_vmcs_clear(). + * Ensure loaded_vmcs->cpu is read before adding loaded_vmcs to + * this cpu's percpu list, otherwise it may not yet be deleted + * from its previous cpu's percpu list. Pairs with the + * smb_wmb() in __loaded_vmcs_clear(). */ smp_rmb(); list_add(&vmx->loaded_vmcs->loaded_vmcss_on_cpu_link, &per_cpu(loaded_vmcss_on_cpu, cpu)); - crash_enable_local_vmclear(cpu); local_irq_enable(); } @@ -3800,21 +3776,6 @@ static int hardware_enable(void) if (cr4_read_shadow() & X86_CR4_VMXE) return -EBUSY; - INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu)); - INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu)); - spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu)); - - /* - * Now we can enable the vmclear operation in kdump - * since the loaded_vmcss_on_cpu list on this cpu - * has been initialized. - * - * Though the cpu is not in VMX operation now, there - * is no problem to enable the vmclear operation - * for the loaded_vmcss_on_cpu list is empty! - */ - crash_enable_local_vmclear(cpu); - rdmsrl(MSR_IA32_FEATURE_CONTROL, old); test_bits = FEATURE_CONTROL_LOCKED; @@ -4597,6 +4558,9 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) static int get_ept_level(struct kvm_vcpu *vcpu) { + /* Nested EPT currently only supports 4-level walks. */ + if (is_guest_mode(vcpu) && nested_cpu_has_ept(get_vmcs12(vcpu))) + return 4; if (cpu_has_vmx_ept_5levels() && (cpuid_maxphyaddr(vcpu) > 48)) return 5; return 4; @@ -4988,6 +4952,26 @@ static bool cs_ss_rpl_check(struct kvm_vcpu *vcpu) (ss.selector & SEGMENT_RPL_MASK)); } +static bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, + unsigned int port, int size); +static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu, + struct vmcs12 *vmcs12) +{ + unsigned long exit_qualification; + unsigned short port; + int size; + + if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS)) + return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING); + + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); + + port = exit_qualification >> 16; + size = (exit_qualification & 7) + 1; + + return nested_vmx_check_io_bitmaps(vcpu, port, size); +} + /* * Check if guest state is valid. Returns true if valid, false if * not. @@ -5518,24 +5502,29 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu, * 2. If target vcpu isn't running(root mode), kick it to pick up the * interrupt from PIR in next vmentry. */ -static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector) +static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector) { struct vcpu_vmx *vmx = to_vmx(vcpu); int r; r = vmx_deliver_nested_posted_interrupt(vcpu, vector); if (!r) - return; + return 0; + + if (!vcpu->arch.apicv_active) + return -1; if (pi_test_and_set_pir(vector, &vmx->pi_desc)) - return; + return 0; /* If a previous notification has sent the IPI, nothing to do. */ if (pi_test_and_set_on(&vmx->pi_desc)) - return; + return 0; if (!kvm_vcpu_trigger_posted_interrupt(vcpu, false)) kvm_vcpu_kick(vcpu); + + return 0; } /* @@ -6170,8 +6159,13 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) { - return (!to_vmx(vcpu)->nested.nested_run_pending && - vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + if (to_vmx(vcpu)->nested.nested_run_pending) + return false; + + if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) + return true; + + return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); } @@ -6256,7 +6250,7 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu, */ static void kvm_machine_check(void) { -#if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_64) +#if defined(CONFIG_X86_MCE) struct pt_regs regs = { .cs = 3, /* Fake ring 3 no matter what the guest ran on */ .flags = X86_EFLAGS_IF, @@ -8014,8 +8008,10 @@ static int handle_vmread(struct kvm_vcpu *vcpu) /* _system ok, nested_vmx_check_permission has verified cpl=0 */ if (kvm_write_guest_virt_system(vcpu, gva, &field_value, (is_long_mode(vcpu) ? 8 : 4), - &e)) + &e)) { kvm_inject_page_fault(vcpu, &e); + return 1; + } } nested_vmx_succeed(vcpu); @@ -8516,23 +8512,17 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { static const int kvm_vmx_max_exit_handlers = ARRAY_SIZE(kvm_vmx_exit_handlers); -static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) +/* + * Return true if an IO instruction with the specified port and size should cause + * a VM-exit into L1. + */ +bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port, + int size) { - unsigned long exit_qualification; + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); gpa_t bitmap, last_bitmap; - unsigned int port; - int size; u8 b; - if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS)) - return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING); - - exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - - port = exit_qualification >> 16; - size = (exit_qualification & 7) + 1; - last_bitmap = (gpa_t)-1; b = -1; @@ -11635,7 +11625,7 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu, } } -static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr) +static int vmx_check_nested_events(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long exit_qual; @@ -11673,8 +11663,7 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr) return 0; } - if ((kvm_cpu_has_interrupt(vcpu) || external_intr) && - nested_exit_on_intr(vcpu)) { + if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(vcpu)) { if (block_nested_events) return -EBUSY; nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0); @@ -12230,17 +12219,8 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; if (likely(!vmx->fail)) { - /* - * TODO: SDM says that with acknowledge interrupt on - * exit, bit 31 of the VM-exit interrupt information - * (valid interrupt) is always set to 1 on - * EXIT_REASON_EXTERNAL_INTERRUPT, so we shouldn't - * need kvm_cpu_has_interrupt(). See the commit - * message for details. - */ - if (nested_exit_intr_ack_set(vcpu) && - exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT && - kvm_cpu_has_interrupt(vcpu)) { + if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT && + nested_exit_intr_ack_set(vcpu)) { int irq = kvm_cpu_get_interrupt(vcpu); WARN_ON(irq < 0); vmcs12->vm_exit_intr_info = irq | @@ -12316,11 +12296,86 @@ static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, to_vmx(vcpu)->nested.sync_shadow_vmcs = true; } +static int vmx_check_intercept_io(struct kvm_vcpu *vcpu, + struct x86_instruction_info *info) +{ + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + unsigned short port; + bool intercept; + int size; + + if (info->intercept == x86_intercept_in || + info->intercept == x86_intercept_ins) { + port = info->src_val; + size = info->dst_bytes; + } else { + port = info->dst_val; + size = info->src_bytes; + } + + /* + * If the 'use IO bitmaps' VM-execution control is 0, IO instruction + * VM-exits depend on the 'unconditional IO exiting' VM-execution + * control. + * + * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps. + */ + if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS)) + intercept = nested_cpu_has(vmcs12, + CPU_BASED_UNCOND_IO_EXITING); + else + intercept = nested_vmx_check_io_bitmaps(vcpu, port, size); + + /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED. */ + return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; +} + static int vmx_check_intercept(struct kvm_vcpu *vcpu, struct x86_instruction_info *info, enum x86_intercept_stage stage) { - return X86EMUL_CONTINUE; + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; + + switch (info->intercept) { + /* + * RDPID causes #UD if disabled through secondary execution controls. + * Because it is marked as EmulateOnUD, we need to intercept it here. + */ + case x86_intercept_rdtscp: + if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) { + ctxt->exception.vector = UD_VECTOR; + ctxt->exception.error_code_valid = false; + return X86EMUL_PROPAGATE_FAULT; + } + break; + + case x86_intercept_in: + case x86_intercept_ins: + case x86_intercept_out: + case x86_intercept_outs: + return vmx_check_intercept_io(vcpu, info); + + case x86_intercept_lgdt: + case x86_intercept_lidt: + case x86_intercept_lldt: + case x86_intercept_ltr: + case x86_intercept_sgdt: + case x86_intercept_sidt: + case x86_intercept_sldt: + case x86_intercept_str: + if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC)) + return X86EMUL_CONTINUE; + + /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED. */ + break; + + /* TODO: check more intercepts... */ + default: + break; + } + + return X86EMUL_UNHANDLEABLE; } #ifdef CONFIG_X86_64 @@ -12841,7 +12896,7 @@ module_exit(vmx_exit) static int __init vmx_init(void) { - int r; + int r, cpu; r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), __alignof__(struct vcpu_vmx), THIS_MODULE); @@ -12863,6 +12918,12 @@ static int __init vmx_init(void) } } + for_each_possible_cpu(cpu) { + INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu)); + INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu)); + spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu)); + } + #ifdef CONFIG_KEXEC_CORE rcu_assign_pointer(crash_vmclear_loaded_vmcss, crash_vmclear_local_loaded_vmcss); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8a51442247c5b36f4a8785f2930c74eb2c5422fa..5f44827e496207d8a778b91f442f21bb5f5a907b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -924,9 +924,11 @@ static u64 kvm_dr6_fixed(struct kvm_vcpu *vcpu) static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val) { + size_t size = ARRAY_SIZE(vcpu->arch.db); + switch (dr) { case 0 ... 3: - vcpu->arch.db[dr] = val; + vcpu->arch.db[array_index_nospec(dr, size)] = val; if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) vcpu->arch.eff_db[dr] = val; break; @@ -963,9 +965,11 @@ EXPORT_SYMBOL_GPL(kvm_set_dr); int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val) { + size_t size = ARRAY_SIZE(vcpu->arch.db); + switch (dr) { case 0 ... 3: - *val = vcpu->arch.db[dr]; + *val = vcpu->arch.db[array_index_nospec(dr, size)]; break; case 4: /* fall through */ @@ -2161,7 +2165,10 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 data) default: if (msr >= MSR_IA32_MC0_CTL && msr < MSR_IA32_MCx_CTL(bank_num)) { - u32 offset = msr - MSR_IA32_MC0_CTL; + u32 offset = array_index_nospec( + msr - MSR_IA32_MC0_CTL, + MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL); + /* only 0 or all 1s can be written to IA32_MCi_CTL * some Linux kernels though clear bit 10 in bank 4 to * workaround a BIOS/GART TBL issue on AMD K8s, ignore @@ -2545,7 +2552,10 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) default: if (msr >= MSR_IA32_MC0_CTL && msr < MSR_IA32_MCx_CTL(bank_num)) { - u32 offset = msr - MSR_IA32_MC0_CTL; + u32 offset = array_index_nospec( + msr - MSR_IA32_MC0_CTL, + MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL); + data = vcpu->arch.mce_banks[offset]; break; } @@ -6304,7 +6314,7 @@ static void kvm_set_mmio_spte_mask(void) * If reserved bit is not supported, clear the present bit to disable * mmio page fault. */ - if (IS_ENABLED(CONFIG_X86_64) && maxphyaddr == 52) + if (maxphyaddr == 52) mask &= ~1ull; kvm_mmu_set_mmio_spte_mask(mask, mask); @@ -6628,7 +6638,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr); } -static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win) +static int inject_pending_event(struct kvm_vcpu *vcpu) { int r; @@ -6655,7 +6665,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win) } if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) { - r = kvm_x86_ops->check_nested_events(vcpu, req_int_win); + r = kvm_x86_ops->check_nested_events(vcpu); if (r != 0) return r; } @@ -6696,7 +6706,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win) * KVM_REQ_EVENT only on certain events and not unconditionally? */ if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) { - r = kvm_x86_ops->check_nested_events(vcpu, req_int_win); + r = kvm_x86_ops->check_nested_events(vcpu); if (r != 0) return r; } @@ -7142,7 +7152,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto out; } - if (inject_pending_event(vcpu, req_int_win) != 0) + if (inject_pending_event(vcpu) != 0) req_immediate_exit = true; else { /* Enable NMI/IRQ window open exits if needed. @@ -7350,7 +7360,7 @@ static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu) static inline bool kvm_vcpu_running(struct kvm_vcpu *vcpu) { if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) - kvm_x86_ops->check_nested_events(vcpu, false); + kvm_x86_ops->check_nested_events(vcpu); return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && !vcpu->arch.apf.halted); @@ -7667,6 +7677,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { + if (kvm_mpx_supported()) + kvm_load_guest_fpu(vcpu); + kvm_apic_accept_events(vcpu); if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED && vcpu->arch.pv.pv_unhalted) @@ -7674,6 +7687,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, else mp_state->mp_state = vcpu->arch.mp_state; + if (kvm_mpx_supported()) + kvm_put_guest_fpu(vcpu); return 0; } @@ -8053,7 +8068,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvm_mmu_unload(vcpu); vcpu_put(vcpu); - kvm_x86_ops->vcpu_free(vcpu); + kvm_arch_vcpu_free(vcpu); } void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) @@ -8569,6 +8584,13 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, { int i; + /* + * Clear out the previous array pointers for the KVM_MR_MOVE case. The + * old arrays will be freed by __kvm_set_memory_region() if installing + * the new memslot is successful. + */ + memset(&slot->arch, 0, sizeof(slot->arch)); + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { struct kvm_lpage_info *linfo; unsigned long ugfn; @@ -8642,6 +8664,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_userspace_memory_region *mem, enum kvm_mr_change change) { + if (change == KVM_MR_MOVE) + return kvm_arch_create_memslot(kvm, memslot, + mem->memory_size >> PAGE_SHIFT); + return 0; } diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 0a0e9112f2842e5b40e4e2284b2c061c4d98370a..5cb9f009f2be3f32c2bd8316d0e5f9805f6b4ea5 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -909,7 +909,7 @@ EndTable GrpTable: Grp3_2 0: TEST Ev,Iz -1: +1: TEST Ev,Iz 2: NOT Ev 3: NEG Ev 4: MUL rAX,Ev diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 9fe656c42aa5b16560e139cebba247ca52756c80..2b0450a3c8ab2c05b54596cb9c5fd2197422af07 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -170,6 +170,7 @@ bool ex_has_fault_handler(unsigned long ip) return handler == ex_handler_fault; } +__nocfi int fixup_exception(struct pt_regs *regs, int trapnr) { const struct exception_table_entry *e; diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 03370c29510533c55a4211690c9594bd01b53c31..d3df6fa5dc639309fd5b66148652ea02fb63ee74 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -272,7 +272,7 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) return pmd_k; } -void vmalloc_sync_all(void) +static void vmalloc_sync(void) { unsigned long address; @@ -299,6 +299,16 @@ void vmalloc_sync_all(void) } } +void vmalloc_sync_mappings(void) +{ + vmalloc_sync(); +} + +void vmalloc_sync_unmappings(void) +{ + vmalloc_sync(); +} + /* * 32-bit: * @@ -401,11 +411,23 @@ static void dump_pagetable(unsigned long address) #else /* CONFIG_X86_64: */ -void vmalloc_sync_all(void) +void vmalloc_sync_mappings(void) { + /* + * 64-bit mappings might allocate new p4d/pud pages + * that need to be propagated to all tasks' PGDs. + */ sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END); } +void vmalloc_sync_unmappings(void) +{ + /* + * Unmappings never allocate or free p4d/pud pages. + * No work is required here. + */ +} + /* * 64-bit: * diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 624edfbff02de4d794dea06041e4d3a1cb669cbb..4937d6f7c256bffdfb1f320ce61a8564f7c1ed04 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1184,7 +1184,7 @@ int kernel_set_to_readonly; void set_kernel_text_rw(void) { unsigned long start = PFN_ALIGN(_text); - unsigned long end = PFN_ALIGN(__stop___ex_table); + unsigned long end = PFN_ALIGN(_etext); if (!kernel_set_to_readonly) return; @@ -1203,7 +1203,7 @@ void set_kernel_text_rw(void) void set_kernel_text_ro(void) { unsigned long start = PFN_ALIGN(_text); - unsigned long end = PFN_ALIGN(__stop___ex_table); + unsigned long end = PFN_ALIGN(_etext); if (!kernel_set_to_readonly) return; @@ -1222,7 +1222,7 @@ void mark_rodata_ro(void) unsigned long start = PFN_ALIGN(_text); unsigned long rodata_start = PFN_ALIGN(__start_rodata); unsigned long end = (unsigned long) &__end_rodata_hpage_align; - unsigned long text_end = PFN_ALIGN(&__stop___ex_table); + unsigned long text_end = PFN_ALIGN(&_etext); unsigned long rodata_end = PFN_ALIGN(&__end_rodata); unsigned long all_end; diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 835620ab435fdb55101c783c26461c6a4d47b2c0..eaee1a7ed0b5061a60aa2c2fb27a661682ba7208 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -2077,19 +2077,13 @@ int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, .pgd = pgd, .numpages = numpages, .mask_set = __pgprot(0), - .mask_clr = __pgprot(0), + .mask_clr = __pgprot(~page_flags & (_PAGE_NX|_PAGE_RW)), .flags = 0, }; if (!(__supported_pte_mask & _PAGE_NX)) goto out; - if (!(page_flags & _PAGE_NX)) - cpa.mask_clr = __pgprot(_PAGE_NX); - - if (!(page_flags & _PAGE_RW)) - cpa.mask_clr = __pgprot(_PAGE_RW); - if (!(page_flags & _PAGE_ENC)) cpa.mask_clr = pgprot_encrypted(cpa.mask_clr); diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 33c6ee9aebbd0f802deee90bc38039fdecb4379b..639f56dc626a151040d1dc66780d17bb5d749cf9 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -367,6 +367,15 @@ static void __init pti_clone_entry_text(void) pti_clone_pmds((unsigned long) __entry_text_start, (unsigned long) __irqentry_text_end, _PAGE_RW | _PAGE_GLOBAL); + + /* + * If CFI is enabled, also map jump tables, so the entry code can + * make indirect calls. + */ + if (IS_ENABLED(CONFIG_CFI_CLANG)) + pti_clone_pmds((unsigned long) __cfi_jt_start, + (unsigned long) __cfi_jt_end, + _PAGE_RW | _PAGE_GLOBAL); } /* diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index cdb386fa710134712bf01147bc60c94fe87bdd0b..0415c0cd4a1915f396e7e3b3769fc93fe8e372ed 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -153,6 +153,19 @@ static bool is_ereg(u32 reg) BIT(BPF_REG_AX)); } +/* + * is_ereg_8l() == true if BPF register 'reg' is mapped to access x86-64 + * lower 8-bit registers dil,sil,bpl,spl,r8b..r15b, which need extra byte + * of encoding. al,cl,dl,bl have simpler encoding. + */ +static bool is_ereg_8l(u32 reg) +{ + return is_ereg(reg) || + (1 << reg) & (BIT(BPF_REG_1) | + BIT(BPF_REG_2) | + BIT(BPF_REG_FP)); +} + /* add modifiers if 'reg' maps to x64 registers r8..r15 */ static u8 add_1mod(u8 byte, u32 reg) { @@ -770,9 +783,8 @@ st: if (is_imm8(insn->off)) /* STX: *(u8*)(dst_reg + off) = src_reg */ case BPF_STX | BPF_MEM | BPF_B: /* emit 'mov byte ptr [rax + off], al' */ - if (is_ereg(dst_reg) || is_ereg(src_reg) || - /* have to add extra byte for x86 SIL, DIL regs */ - src_reg == BPF_REG_1 || src_reg == BPF_REG_2) + if (is_ereg(dst_reg) || is_ereg_8l(src_reg)) + /* Add extra byte for eregs or SIL,DIL,BPL in src_reg */ EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88); else EMIT1(0x88); diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 335a62e74a2e9ad8d1751bd1aef1bc556d2ce172..e7f19dec16b9704927681dab9c74715f32b75faa 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -480,7 +480,6 @@ void __init efi_init(void) efi_char16_t *c16; char vendor[100] = "unknown"; int i = 0; - void *tmp; #ifdef CONFIG_X86_32 if (boot_params.efi_info.efi_systab_hi || @@ -505,14 +504,16 @@ void __init efi_init(void) /* * Show what we know for posterity */ - c16 = tmp = early_memremap(efi.systab->fw_vendor, 2); + c16 = early_memremap_ro(efi.systab->fw_vendor, + sizeof(vendor) * sizeof(efi_char16_t)); if (c16) { - for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i) - vendor[i] = *c16++; + for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i) + vendor[i] = c16[i]; vendor[i] = '\0'; - } else + early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t)); + } else { pr_err("Could not map the firmware vendor!\n"); - early_memunmap(tmp, 2); + } pr_info("EFI v%u.%.02u by %s\n", efi.systab->hdr.revision >> 16, @@ -929,16 +930,14 @@ static void __init __efi_enter_virtual_mode(void) if (efi_alloc_page_tables()) { pr_err("Failed to allocate EFI page tables\n"); - clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); - return; + goto err; } efi_merge_regions(); new_memmap = efi_map_regions(&count, &pg_shift); if (!new_memmap) { pr_err("Error reallocating memory, EFI runtime non-functional!\n"); - clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); - return; + goto err; } pa = __pa(new_memmap); @@ -952,8 +951,7 @@ static void __init __efi_enter_virtual_mode(void) if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) { pr_err("Failed to remap late EFI memory map\n"); - clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); - return; + goto err; } if (efi_enabled(EFI_DBG)) { @@ -961,12 +959,11 @@ static void __init __efi_enter_virtual_mode(void) efi_print_memmap(); } - BUG_ON(!efi.systab); + if (WARN_ON(!efi.systab)) + goto err; - if (efi_setup_page_tables(pa, 1 << pg_shift)) { - clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); - return; - } + if (efi_setup_page_tables(pa, 1 << pg_shift)) + goto err; efi_sync_low_kernel_mappings(); @@ -986,9 +983,9 @@ static void __init __efi_enter_virtual_mode(void) } if (status != EFI_SUCCESS) { - pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n", - status); - panic("EFI call to SetVirtualAddressMap() failed!"); + pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n", + status); + goto err; } /* @@ -1015,6 +1012,10 @@ static void __init __efi_enter_virtual_mode(void) /* clean DUMMY object */ efi_delete_dummy_variable(); + return; + +err: + clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); } void __init efi_enter_virtual_mode(void) diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index ae369c2bbc3ebbf508e7c64bd32a8a9e77950848..0ebb7f94fd518c3cff6f94ea2494ade4a098ab7b 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -390,11 +390,12 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) return 0; page = alloc_page(GFP_KERNEL|__GFP_DMA32); - if (!page) - panic("Unable to allocate EFI runtime stack < 4GB\n"); + if (!page) { + pr_err("Unable to allocate EFI runtime stack < 4GB\n"); + return 1; + } - efi_scratch.phys_stack = virt_to_phys(page_address(page)); - efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */ + efi_scratch.phys_stack = page_to_phys(page + 1); /* stack grows down */ npages = (_etext - _text) >> PAGE_SHIFT; text = __pa(_text); diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 220e97841e494c41e21b242a053b9ffcefeb2b4a..4334dfb24ed66e8fe1e9afa77e501c0496b7cad9 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -46,6 +46,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { "^(xen_irq_disable_direct_reloc$|" "xen_save_fl_direct_reloc$|" "VDSO|" + "__typeid__|" "__crc_)", /* @@ -781,6 +782,12 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, add_reloc(&relocs32neg, offset); break; + case R_X86_64_8: + if (!shn_abs || !is_reloc(S_ABS, symname)) + die("Non-whitelisted %s relocation: %s\n", + rel_type(r_type), symname); + break; + case R_X86_64_32: case R_X86_64_32S: case R_X86_64_64: diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index f79a0cdc6b4e7ba23100a40447d981a89c929a02..1f8175bf2a5e300df11571dc585467e6ed1ba783 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -909,14 +909,15 @@ static u64 xen_read_msr_safe(unsigned int msr, int *err) static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int ret; +#ifdef CONFIG_X86_64 + unsigned int which; + u64 base; +#endif ret = 0; switch (msr) { #ifdef CONFIG_X86_64 - unsigned which; - u64 base; - case MSR_FS_BASE: which = SEGBASE_FS; goto set; case MSR_KERNEL_GS_BASE: which = SEGBASE_GS_USER; goto set; case MSR_GS_BASE: which = SEGBASE_GS_KERNEL; goto set; diff --git a/block/Kconfig b/block/Kconfig index 28ec55752b68e89bd1babc0b0c6eb4b3e4576014..4d9bcb951d831afa1ef2752568230faa0882d025 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -184,6 +184,23 @@ config BLK_SED_OPAL Enabling this option enables users to setup/unlock/lock Locking ranges for SED devices using the Opal protocol. +config BLK_INLINE_ENCRYPTION + bool "Enable inline encryption support in block layer" + help + Build the blk-crypto subsystem. Enabling this lets the + block layer handle encryption, so users can take + advantage of inline encryption hardware if present. + +config BLK_INLINE_ENCRYPTION_FALLBACK + bool "Enable crypto API fallback for blk-crypto" + depends on BLK_INLINE_ENCRYPTION + select CRYPTO + select CRYPTO_BLKCIPHER + help + Enabling this lets the block layer handle inline encryption + by falling back to the kernel crypto API when inline + encryption hardware is not present. + menu "Partition Types" source "block/partitions/Kconfig" diff --git a/block/Makefile b/block/Makefile index 6a56303b992529a08e0d719d08a54a9702950c79..ab14055d8222e74b31f9f48463e6754f624520e4 100644 --- a/block/Makefile +++ b/block/Makefile @@ -35,3 +35,6 @@ obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o obj-$(CONFIG_BLK_WBT) += blk-wbt.o obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o +obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += keyslot-manager.o bio-crypt-ctx.o \ + blk-crypto.o +obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o \ No newline at end of file diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index afbbe5750a1f85b635e7cd9a903314c0729c26d4..7d7aee024ece28b8fc121f89ddad7f06a6d41887 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -499,12 +499,13 @@ struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd, */ entity = &bfqg->entity; for_each_entity(entity) { - bfqg = container_of(entity, struct bfq_group, entity); - if (bfqg != bfqd->root_group) { - parent = bfqg_parent(bfqg); + struct bfq_group *curr_bfqg = container_of(entity, + struct bfq_group, entity); + if (curr_bfqg != bfqd->root_group) { + parent = bfqg_parent(curr_bfqg); if (!parent) parent = bfqd->root_group; - bfq_group_set_parent(bfqg, parent); + bfq_group_set_parent(curr_bfqg, parent); } } diff --git a/block/bio-crypt-ctx.c b/block/bio-crypt-ctx.c new file mode 100644 index 0000000000000000000000000000000000000000..75008b2afea21dc87c466d4e840156a730a0f8dd --- /dev/null +++ b/block/bio-crypt-ctx.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include +#include +#include +#include +#include + +#include "blk-crypto-internal.h" + +static int num_prealloc_crypt_ctxs = 128; + +module_param(num_prealloc_crypt_ctxs, int, 0444); +MODULE_PARM_DESC(num_prealloc_crypt_ctxs, + "Number of bio crypto contexts to preallocate"); + +static struct kmem_cache *bio_crypt_ctx_cache; +static mempool_t *bio_crypt_ctx_pool; + +int __init bio_crypt_ctx_init(void) +{ + size_t i; + + bio_crypt_ctx_cache = KMEM_CACHE(bio_crypt_ctx, 0); + if (!bio_crypt_ctx_cache) + return -ENOMEM; + + bio_crypt_ctx_pool = mempool_create_slab_pool(num_prealloc_crypt_ctxs, + bio_crypt_ctx_cache); + if (!bio_crypt_ctx_pool) + return -ENOMEM; + + /* This is assumed in various places. */ + BUILD_BUG_ON(BLK_ENCRYPTION_MODE_INVALID != 0); + + /* Sanity check that no algorithm exceeds the defined limits. */ + for (i = 0; i < BLK_ENCRYPTION_MODE_MAX; i++) { + BUG_ON(blk_crypto_modes[i].keysize > BLK_CRYPTO_MAX_KEY_SIZE); + BUG_ON(blk_crypto_modes[i].ivsize > BLK_CRYPTO_MAX_IV_SIZE); + } + + return 0; +} + +struct bio_crypt_ctx *bio_crypt_alloc_ctx(gfp_t gfp_mask) +{ + return mempool_alloc(bio_crypt_ctx_pool, gfp_mask); +} +EXPORT_SYMBOL_GPL(bio_crypt_alloc_ctx); + +void bio_crypt_free_ctx(struct bio *bio) +{ + mempool_free(bio->bi_crypt_context, bio_crypt_ctx_pool); + bio->bi_crypt_context = NULL; +} + +void bio_crypt_clone(struct bio *dst, struct bio *src, gfp_t gfp_mask) +{ + const struct bio_crypt_ctx *src_bc = src->bi_crypt_context; + + bio_clone_skip_dm_default_key(dst, src); + + /* + * If a bio is fallback_crypted, then it will be decrypted when + * bio_endio is called. As we only want the data to be decrypted once, + * copies of the bio must not have have a crypt context. + */ + if (!src_bc || bio_crypt_fallback_crypted(src_bc)) + return; + + dst->bi_crypt_context = bio_crypt_alloc_ctx(gfp_mask); + *dst->bi_crypt_context = *src_bc; + + if (src_bc->bc_keyslot >= 0) + keyslot_manager_get_slot(src_bc->bc_ksm, src_bc->bc_keyslot); +} +EXPORT_SYMBOL_GPL(bio_crypt_clone); + +bool bio_crypt_should_process(struct request *rq) +{ + struct bio *bio = rq->bio; + + if (!bio || !bio->bi_crypt_context) + return false; + + return rq->q->ksm == bio->bi_crypt_context->bc_ksm; +} +EXPORT_SYMBOL_GPL(bio_crypt_should_process); + +/* + * Checks that two bio crypt contexts are compatible - i.e. that + * they are mergeable except for data_unit_num continuity. + */ +bool bio_crypt_ctx_compatible(struct bio *b_1, struct bio *b_2) +{ + struct bio_crypt_ctx *bc1 = b_1->bi_crypt_context; + struct bio_crypt_ctx *bc2 = b_2->bi_crypt_context; + + if (!bc1) + return !bc2; + return bc2 && bc1->bc_key == bc2->bc_key; +} + +/* + * Checks that two bio crypt contexts are compatible, and also + * that their data_unit_nums are continuous (and can hence be merged) + * in the order b_1 followed by b_2. + */ +bool bio_crypt_ctx_mergeable(struct bio *b_1, unsigned int b1_bytes, + struct bio *b_2) +{ + struct bio_crypt_ctx *bc1 = b_1->bi_crypt_context; + struct bio_crypt_ctx *bc2 = b_2->bi_crypt_context; + + if (!bio_crypt_ctx_compatible(b_1, b_2)) + return false; + + return !bc1 || bio_crypt_dun_is_contiguous(bc1, b1_bytes, bc2->bc_dun); +} + +void bio_crypt_ctx_release_keyslot(struct bio_crypt_ctx *bc) +{ + keyslot_manager_put_slot(bc->bc_ksm, bc->bc_keyslot); + bc->bc_ksm = NULL; + bc->bc_keyslot = -1; +} + +int bio_crypt_ctx_acquire_keyslot(struct bio_crypt_ctx *bc, + struct keyslot_manager *ksm) +{ + int slot = keyslot_manager_get_slot_for_key(ksm, bc->bc_key); + + if (slot < 0) + return slot; + + bc->bc_keyslot = slot; + bc->bc_ksm = ksm; + return 0; +} diff --git a/block/bio.c b/block/bio.c index ce70677b9b5e9d04ad2384de3420ba4632fc9f98..6ef2e22d2bf3726057e5ab152324fb5693c4ebb6 100644 --- a/block/bio.c +++ b/block/bio.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "blk.h" @@ -243,6 +244,8 @@ struct bio_vec *bvec_alloc(gfp_t gfp_mask, int nr, unsigned long *idx, void bio_uninit(struct bio *bio) { bio_disassociate_task(bio); + + bio_crypt_free_ctx(bio); } EXPORT_SYMBOL(bio_uninit); @@ -577,18 +580,6 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio) } EXPORT_SYMBOL(bio_phys_segments); -static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src) -{ -#ifdef CONFIG_PFK - dst->bi_iter.bi_dun = src->bi_iter.bi_dun; -#ifdef CONFIG_DM_DEFAULT_KEY - dst->bi_crypt_key = src->bi_crypt_key; - dst->bi_crypt_skip = src->bi_crypt_skip; -#endif - dst->bi_dio_inode = src->bi_dio_inode; -#endif -} - /** * __bio_clone_fast - clone a bio that shares the original bio's biovec * @bio: destination bio @@ -617,7 +608,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_write_hint = bio_src->bi_write_hint; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; - bio_clone_crypt_key(bio, bio_src); + bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); @@ -640,15 +631,12 @@ struct bio *bio_clone_fast(struct bio *bio, gfp_t gfp_mask, struct bio_set *bs) __bio_clone_fast(b, bio); - if (bio_integrity(bio)) { - int ret; - - ret = bio_integrity_clone(b, bio, gfp_mask); + bio_crypt_clone(b, bio, gfp_mask); - if (ret < 0) { - bio_put(b); - return NULL; - } + if (bio_integrity(bio) && + bio_integrity_clone(b, bio, gfp_mask) < 0) { + bio_put(b); + return NULL; } return b; @@ -716,6 +704,8 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, break; } + bio_crypt_clone(bio, bio_src, gfp_mask); + if (bio_integrity(bio_src)) { int ret; @@ -726,7 +716,6 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, } } - bio_clone_crypt_key(bio, bio_src); bio_clone_blkcg_association(bio, bio_src); return bio; @@ -1048,6 +1037,7 @@ void bio_advance(struct bio *bio, unsigned bytes) if (bio_integrity(bio)) bio_integrity_advance(bio, bytes); + bio_crypt_advance(bio, bytes); bio_advance_iter(bio, &bio->bi_iter, bytes); } EXPORT_SYMBOL(bio_advance); @@ -1905,6 +1895,10 @@ void bio_endio(struct bio *bio) again: if (!bio_remaining_done(bio)) return; + + if (!blk_crypto_endio(bio)) + return; + if (!bio_integrity_endio(bio)) return; diff --git a/block/blk-core.c b/block/blk-core.c index 7ce048c9861c42735a34629077bdb8641d5f091a..e90d2e3644c0700361ce6caf65605feecf0fe5bd 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -35,6 +35,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -1462,9 +1463,6 @@ static struct request *blk_old_get_request(struct request_queue *q, /* q->queue_lock is unlocked at this point */ rq->__data_len = 0; rq->__sector = (sector_t) -1; -#ifdef CONFIG_PFK - rq->__dun = 0; -#endif rq->bio = rq->biotail = NULL; return rq; } @@ -1688,9 +1686,6 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req, bio->bi_next = req->bio; req->bio = bio; -#ifdef CONFIG_PFK - req->__dun = bio->bi_iter.bi_dun; -#endif req->__sector = bio->bi_iter.bi_sector; req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); @@ -1840,9 +1835,6 @@ void blk_init_request_from_bio(struct request *req, struct bio *bio) else req->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0); req->write_hint = bio->bi_write_hint; -#ifdef CONFIG_PFK - req->__dun = bio->bi_iter.bi_dun; -#endif blk_rq_bio_prep(req->q, req, bio); } EXPORT_SYMBOL_GPL(blk_init_request_from_bio); @@ -2293,7 +2285,9 @@ blk_qc_t generic_make_request(struct bio *bio) /* Create a fresh bio_list for all subordinate requests */ bio_list_on_stack[1] = bio_list_on_stack[0]; bio_list_init(&bio_list_on_stack[0]); - ret = q->make_request_fn(q, bio); + + if (!blk_crypto_submit_bio(&bio)) + ret = q->make_request_fn(q, bio); /* sort new bios into those for a lower level * and those for the same level @@ -2876,13 +2870,8 @@ bool blk_update_request(struct request *req, blk_status_t error, req->__data_len -= total_bytes; /* update sector only for requests with clear definition of sector */ - if (!blk_rq_is_passthrough(req)) { + if (!blk_rq_is_passthrough(req)) req->__sector += total_bytes >> 9; -#ifdef CONFIG_PFK - if (req->__dun) - req->__dun += total_bytes >> 12; -#endif - } /* mixed attributes always follow the first bio */ if (req->rq_flags & RQF_MIXED_MERGE) { @@ -3245,9 +3234,6 @@ static void __blk_rq_prep_clone(struct request *dst, struct request *src) { dst->cpu = src->cpu; dst->__sector = blk_rq_pos(src); -#ifdef CONFIG_PFK - dst->__dun = blk_rq_dun(src); -#endif dst->__data_len = blk_rq_bytes(src); if (src->rq_flags & RQF_SPECIAL_PAYLOAD) { dst->rq_flags |= RQF_SPECIAL_PAYLOAD; @@ -3745,6 +3731,12 @@ int __init blk_dev_init(void) blk_debugfs_root = debugfs_create_dir("block", NULL); #endif + if (bio_crypt_ctx_init() < 0) + panic("Failed to allocate mem for bio crypt ctxs\n"); + + if (blk_crypto_fallback_init() < 0) + panic("Failed to init blk-crypto-fallback\n"); + return 0; } diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c new file mode 100644 index 0000000000000000000000000000000000000000..18b6851d8301e8e6fb17035f0db30789cf1e2978 --- /dev/null +++ b/block/blk-crypto-fallback.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +/* + * Refer to Documentation/block/inline-encryption.rst for detailed explanation. + */ + +#define pr_fmt(fmt) "blk-crypto-fallback: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "blk-crypto-internal.h" + +static unsigned int num_prealloc_bounce_pg = 32; +module_param(num_prealloc_bounce_pg, uint, 0); +MODULE_PARM_DESC(num_prealloc_bounce_pg, + "Number of preallocated bounce pages for the blk-crypto crypto API fallback"); + +static unsigned int blk_crypto_num_keyslots = 100; +module_param_named(num_keyslots, blk_crypto_num_keyslots, uint, 0); +MODULE_PARM_DESC(num_keyslots, + "Number of keyslots for the blk-crypto crypto API fallback"); + +static unsigned int num_prealloc_fallback_crypt_ctxs = 128; +module_param(num_prealloc_fallback_crypt_ctxs, uint, 0); +MODULE_PARM_DESC(num_prealloc_crypt_fallback_ctxs, + "Number of preallocated bio fallback crypto contexts for blk-crypto to use during crypto API fallback"); + +struct bio_fallback_crypt_ctx { + struct bio_crypt_ctx crypt_ctx; + /* + * Copy of the bvec_iter when this bio was submitted. + * We only want to en/decrypt the part of the bio as described by the + * bvec_iter upon submission because bio might be split before being + * resubmitted + */ + struct bvec_iter crypt_iter; + u64 fallback_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; +}; + +/* The following few vars are only used during the crypto API fallback */ +static struct kmem_cache *bio_fallback_crypt_ctx_cache; +static mempool_t *bio_fallback_crypt_ctx_pool; + +/* + * Allocating a crypto tfm during I/O can deadlock, so we have to preallocate + * all of a mode's tfms when that mode starts being used. Since each mode may + * need all the keyslots at some point, each mode needs its own tfm for each + * keyslot; thus, a keyslot may contain tfms for multiple modes. However, to + * match the behavior of real inline encryption hardware (which only supports a + * single encryption context per keyslot), we only allow one tfm per keyslot to + * be used at a time - the rest of the unused tfms have their keys cleared. + */ +static DEFINE_MUTEX(tfms_init_lock); +static bool tfms_inited[BLK_ENCRYPTION_MODE_MAX]; + +struct blk_crypto_decrypt_work { + struct work_struct work; + struct bio *bio; +}; + +static struct blk_crypto_keyslot { + struct crypto_skcipher *tfm; + enum blk_crypto_mode_num crypto_mode; + struct crypto_skcipher *tfms[BLK_ENCRYPTION_MODE_MAX]; +} *blk_crypto_keyslots; + +/* The following few vars are only used during the crypto API fallback */ +static struct keyslot_manager *blk_crypto_ksm; +static struct workqueue_struct *blk_crypto_wq; +static mempool_t *blk_crypto_bounce_page_pool; +static struct kmem_cache *blk_crypto_decrypt_work_cache; + +bool bio_crypt_fallback_crypted(const struct bio_crypt_ctx *bc) +{ + return bc && bc->bc_ksm == blk_crypto_ksm; +} + +/* + * This is the key we set when evicting a keyslot. This *should* be the all 0's + * key, but AES-XTS rejects that key, so we use some random bytes instead. + */ +static u8 blank_key[BLK_CRYPTO_MAX_KEY_SIZE]; + +static void blk_crypto_evict_keyslot(unsigned int slot) +{ + struct blk_crypto_keyslot *slotp = &blk_crypto_keyslots[slot]; + enum blk_crypto_mode_num crypto_mode = slotp->crypto_mode; + int err; + + WARN_ON(slotp->crypto_mode == BLK_ENCRYPTION_MODE_INVALID); + + /* Clear the key in the skcipher */ + err = crypto_skcipher_setkey(slotp->tfms[crypto_mode], blank_key, + blk_crypto_modes[crypto_mode].keysize); + WARN_ON(err); + slotp->crypto_mode = BLK_ENCRYPTION_MODE_INVALID; +} + +static int blk_crypto_keyslot_program(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct blk_crypto_keyslot *slotp = &blk_crypto_keyslots[slot]; + const enum blk_crypto_mode_num crypto_mode = key->crypto_mode; + int err; + + if (crypto_mode != slotp->crypto_mode && + slotp->crypto_mode != BLK_ENCRYPTION_MODE_INVALID) { + blk_crypto_evict_keyslot(slot); + } + + if (!slotp->tfms[crypto_mode]) + return -ENOMEM; + slotp->crypto_mode = crypto_mode; + err = crypto_skcipher_setkey(slotp->tfms[crypto_mode], key->raw, + key->size); + if (err) { + blk_crypto_evict_keyslot(slot); + return err; + } + return 0; +} + +static int blk_crypto_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + blk_crypto_evict_keyslot(slot); + return 0; +} + +/* + * The crypto API fallback KSM ops - only used for a bio when it specifies a + * blk_crypto_mode for which we failed to get a keyslot in the device's inline + * encryption hardware (which probably means the device doesn't have inline + * encryption hardware that supports that crypto mode). + */ +static const struct keyslot_mgmt_ll_ops blk_crypto_ksm_ll_ops = { + .keyslot_program = blk_crypto_keyslot_program, + .keyslot_evict = blk_crypto_keyslot_evict, +}; + +static void blk_crypto_encrypt_endio(struct bio *enc_bio) +{ + struct bio *src_bio = enc_bio->bi_private; + int i; + + for (i = 0; i < enc_bio->bi_vcnt; i++) + mempool_free(enc_bio->bi_io_vec[i].bv_page, + blk_crypto_bounce_page_pool); + + src_bio->bi_status = enc_bio->bi_status; + + bio_put(enc_bio); + bio_endio(src_bio); +} + +static struct bio *blk_crypto_clone_bio(struct bio *bio_src) +{ + struct bvec_iter iter; + struct bio_vec bv; + struct bio *bio; + + bio = bio_alloc_bioset(GFP_NOIO, bio_segments(bio_src), NULL); + if (!bio) + return NULL; + bio->bi_disk = bio_src->bi_disk; + bio->bi_opf = bio_src->bi_opf; + bio->bi_ioprio = bio_src->bi_ioprio; + bio->bi_write_hint = bio_src->bi_write_hint; + bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; + bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; + + bio_for_each_segment(bv, bio_src, iter) + bio->bi_io_vec[bio->bi_vcnt++] = bv; + + if (bio_integrity(bio_src) && + bio_integrity_clone(bio, bio_src, GFP_NOIO) < 0) { + bio_put(bio); + return NULL; + } + + bio_clone_blkcg_association(bio, bio_src); + + bio_clone_skip_dm_default_key(bio, bio_src); + + return bio; +} + +static int blk_crypto_alloc_cipher_req(struct bio *src_bio, + struct skcipher_request **ciph_req_ret, + struct crypto_wait *wait) +{ + struct skcipher_request *ciph_req; + const struct blk_crypto_keyslot *slotp; + + slotp = &blk_crypto_keyslots[src_bio->bi_crypt_context->bc_keyslot]; + ciph_req = skcipher_request_alloc(slotp->tfms[slotp->crypto_mode], + GFP_NOIO); + if (!ciph_req) { + src_bio->bi_status = BLK_STS_RESOURCE; + return -ENOMEM; + } + + skcipher_request_set_callback(ciph_req, + CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, wait); + *ciph_req_ret = ciph_req; + return 0; +} + +static int blk_crypto_split_bio_if_needed(struct bio **bio_ptr) +{ + struct bio *bio = *bio_ptr; + unsigned int i = 0; + unsigned int num_sectors = 0; + struct bio_vec bv; + struct bvec_iter iter; + + bio_for_each_segment(bv, bio, iter) { + num_sectors += bv.bv_len >> SECTOR_SHIFT; + if (++i == BIO_MAX_PAGES) + break; + } + if (num_sectors < bio_sectors(bio)) { + struct bio *split_bio; + + split_bio = bio_split(bio, num_sectors, GFP_NOIO, NULL); + if (!split_bio) { + bio->bi_status = BLK_STS_RESOURCE; + return -ENOMEM; + } + bio_chain(split_bio, bio); + generic_make_request(bio); + *bio_ptr = split_bio; + } + return 0; +} + +union blk_crypto_iv { + __le64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + u8 bytes[BLK_CRYPTO_MAX_IV_SIZE]; +}; + +static void blk_crypto_dun_to_iv(const u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE], + union blk_crypto_iv *iv) +{ + int i; + + for (i = 0; i < BLK_CRYPTO_DUN_ARRAY_SIZE; i++) + iv->dun[i] = cpu_to_le64(dun[i]); +} + +/* + * The crypto API fallback's encryption routine. + * Allocate a bounce bio for encryption, encrypt the input bio using crypto API, + * and replace *bio_ptr with the bounce bio. May split input bio if it's too + * large. + */ +static int blk_crypto_encrypt_bio(struct bio **bio_ptr) +{ + struct bio *src_bio; + struct skcipher_request *ciph_req = NULL; + DECLARE_CRYPTO_WAIT(wait); + u64 curr_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + union blk_crypto_iv iv; + struct scatterlist src, dst; + struct bio *enc_bio; + unsigned int i, j; + int data_unit_size; + struct bio_crypt_ctx *bc; + int err = 0; + + /* Split the bio if it's too big for single page bvec */ + err = blk_crypto_split_bio_if_needed(bio_ptr); + if (err) + return err; + + src_bio = *bio_ptr; + bc = src_bio->bi_crypt_context; + data_unit_size = bc->bc_key->data_unit_size; + + /* Allocate bounce bio for encryption */ + enc_bio = blk_crypto_clone_bio(src_bio); + if (!enc_bio) { + src_bio->bi_status = BLK_STS_RESOURCE; + return -ENOMEM; + } + + /* + * Use the crypto API fallback keyslot manager to get a crypto_skcipher + * for the algorithm and key specified for this bio. + */ + err = bio_crypt_ctx_acquire_keyslot(bc, blk_crypto_ksm); + if (err) { + src_bio->bi_status = BLK_STS_IOERR; + goto out_put_enc_bio; + } + + /* and then allocate an skcipher_request for it */ + err = blk_crypto_alloc_cipher_req(src_bio, &ciph_req, &wait); + if (err) + goto out_release_keyslot; + + memcpy(curr_dun, bc->bc_dun, sizeof(curr_dun)); + sg_init_table(&src, 1); + sg_init_table(&dst, 1); + + skcipher_request_set_crypt(ciph_req, &src, &dst, data_unit_size, + iv.bytes); + + /* Encrypt each page in the bounce bio */ + for (i = 0; i < enc_bio->bi_vcnt; i++) { + struct bio_vec *enc_bvec = &enc_bio->bi_io_vec[i]; + struct page *plaintext_page = enc_bvec->bv_page; + struct page *ciphertext_page = + mempool_alloc(blk_crypto_bounce_page_pool, GFP_NOIO); + + enc_bvec->bv_page = ciphertext_page; + + if (!ciphertext_page) { + src_bio->bi_status = BLK_STS_RESOURCE; + err = -ENOMEM; + goto out_free_bounce_pages; + } + + sg_set_page(&src, plaintext_page, data_unit_size, + enc_bvec->bv_offset); + sg_set_page(&dst, ciphertext_page, data_unit_size, + enc_bvec->bv_offset); + + /* Encrypt each data unit in this page */ + for (j = 0; j < enc_bvec->bv_len; j += data_unit_size) { + blk_crypto_dun_to_iv(curr_dun, &iv); + err = crypto_wait_req(crypto_skcipher_encrypt(ciph_req), + &wait); + if (err) { + i++; + src_bio->bi_status = BLK_STS_RESOURCE; + goto out_free_bounce_pages; + } + bio_crypt_dun_increment(curr_dun, 1); + src.offset += data_unit_size; + dst.offset += data_unit_size; + } + } + + enc_bio->bi_private = src_bio; + enc_bio->bi_end_io = blk_crypto_encrypt_endio; + *bio_ptr = enc_bio; + + enc_bio = NULL; + err = 0; + goto out_free_ciph_req; + +out_free_bounce_pages: + while (i > 0) + mempool_free(enc_bio->bi_io_vec[--i].bv_page, + blk_crypto_bounce_page_pool); +out_free_ciph_req: + skcipher_request_free(ciph_req); +out_release_keyslot: + bio_crypt_ctx_release_keyslot(bc); +out_put_enc_bio: + if (enc_bio) + bio_put(enc_bio); + + return err; +} + +static void blk_crypto_free_fallback_crypt_ctx(struct bio *bio) +{ + mempool_free(container_of(bio->bi_crypt_context, + struct bio_fallback_crypt_ctx, + crypt_ctx), + bio_fallback_crypt_ctx_pool); + bio->bi_crypt_context = NULL; +} + +/* + * The crypto API fallback's main decryption routine. + * Decrypts input bio in place. + */ +static void blk_crypto_decrypt_bio(struct work_struct *work) +{ + struct blk_crypto_decrypt_work *decrypt_work = + container_of(work, struct blk_crypto_decrypt_work, work); + struct bio *bio = decrypt_work->bio; + struct skcipher_request *ciph_req = NULL; + DECLARE_CRYPTO_WAIT(wait); + struct bio_vec bv; + struct bvec_iter iter; + u64 curr_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + union blk_crypto_iv iv; + struct scatterlist sg; + struct bio_crypt_ctx *bc = bio->bi_crypt_context; + struct bio_fallback_crypt_ctx *f_ctx = + container_of(bc, struct bio_fallback_crypt_ctx, crypt_ctx); + const int data_unit_size = bc->bc_key->data_unit_size; + unsigned int i; + int err; + + /* + * Use the crypto API fallback keyslot manager to get a crypto_skcipher + * for the algorithm and key specified for this bio. + */ + if (bio_crypt_ctx_acquire_keyslot(bc, blk_crypto_ksm)) { + bio->bi_status = BLK_STS_RESOURCE; + goto out_no_keyslot; + } + + /* and then allocate an skcipher_request for it */ + err = blk_crypto_alloc_cipher_req(bio, &ciph_req, &wait); + if (err) + goto out; + + memcpy(curr_dun, f_ctx->fallback_dun, sizeof(curr_dun)); + sg_init_table(&sg, 1); + skcipher_request_set_crypt(ciph_req, &sg, &sg, data_unit_size, + iv.bytes); + + /* Decrypt each segment in the bio */ + __bio_for_each_segment(bv, bio, iter, f_ctx->crypt_iter) { + struct page *page = bv.bv_page; + + sg_set_page(&sg, page, data_unit_size, bv.bv_offset); + + /* Decrypt each data unit in the segment */ + for (i = 0; i < bv.bv_len; i += data_unit_size) { + blk_crypto_dun_to_iv(curr_dun, &iv); + if (crypto_wait_req(crypto_skcipher_decrypt(ciph_req), + &wait)) { + bio->bi_status = BLK_STS_IOERR; + goto out; + } + bio_crypt_dun_increment(curr_dun, 1); + sg.offset += data_unit_size; + } + } + +out: + skcipher_request_free(ciph_req); + bio_crypt_ctx_release_keyslot(bc); +out_no_keyslot: + kmem_cache_free(blk_crypto_decrypt_work_cache, decrypt_work); + blk_crypto_free_fallback_crypt_ctx(bio); + bio_endio(bio); +} + +/* + * Queue bio for decryption. + * Returns true iff bio was queued for decryption. + */ +bool blk_crypto_queue_decrypt_bio(struct bio *bio) +{ + struct blk_crypto_decrypt_work *decrypt_work; + + /* If there was an IO error, don't queue for decrypt. */ + if (bio->bi_status) + goto out; + + decrypt_work = kmem_cache_zalloc(blk_crypto_decrypt_work_cache, + GFP_ATOMIC); + if (!decrypt_work) { + bio->bi_status = BLK_STS_RESOURCE; + goto out; + } + + INIT_WORK(&decrypt_work->work, blk_crypto_decrypt_bio); + decrypt_work->bio = bio; + queue_work(blk_crypto_wq, &decrypt_work->work); + + return true; +out: + blk_crypto_free_fallback_crypt_ctx(bio); + return false; +} + +/* + * Prepare blk-crypto-fallback for the specified crypto mode. + * Returns -ENOPKG if the needed crypto API support is missing. + */ +int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num) +{ + const char *cipher_str = blk_crypto_modes[mode_num].cipher_str; + struct blk_crypto_keyslot *slotp; + unsigned int i; + int err = 0; + + /* + * Fast path + * Ensure that updates to blk_crypto_keyslots[i].tfms[mode_num] + * for each i are visible before we try to access them. + */ + if (likely(smp_load_acquire(&tfms_inited[mode_num]))) + return 0; + + mutex_lock(&tfms_init_lock); + if (likely(tfms_inited[mode_num])) + goto out; + + for (i = 0; i < blk_crypto_num_keyslots; i++) { + slotp = &blk_crypto_keyslots[i]; + slotp->tfms[mode_num] = crypto_alloc_skcipher(cipher_str, 0, 0); + if (IS_ERR(slotp->tfms[mode_num])) { + err = PTR_ERR(slotp->tfms[mode_num]); + if (err == -ENOENT) { + pr_warn_once("Missing crypto API support for \"%s\"\n", + cipher_str); + err = -ENOPKG; + } + slotp->tfms[mode_num] = NULL; + goto out_free_tfms; + } + + crypto_skcipher_set_flags(slotp->tfms[mode_num], + CRYPTO_TFM_REQ_WEAK_KEY); + } + + /* + * Ensure that updates to blk_crypto_keyslots[i].tfms[mode_num] + * for each i are visible before we set tfms_inited[mode_num]. + */ + smp_store_release(&tfms_inited[mode_num], true); + goto out; + +out_free_tfms: + for (i = 0; i < blk_crypto_num_keyslots; i++) { + slotp = &blk_crypto_keyslots[i]; + crypto_free_skcipher(slotp->tfms[mode_num]); + slotp->tfms[mode_num] = NULL; + } +out: + mutex_unlock(&tfms_init_lock); + return err; +} + +int blk_crypto_fallback_evict_key(const struct blk_crypto_key *key) +{ + return keyslot_manager_evict_key(blk_crypto_ksm, key); +} + +int blk_crypto_fallback_submit_bio(struct bio **bio_ptr) +{ + struct bio *bio = *bio_ptr; + struct bio_crypt_ctx *bc = bio->bi_crypt_context; + struct bio_fallback_crypt_ctx *f_ctx; + + if (bc->bc_key->is_hw_wrapped) { + pr_warn_once("HW wrapped key cannot be used with fallback.\n"); + bio->bi_status = BLK_STS_NOTSUPP; + return -EOPNOTSUPP; + } + + if (!tfms_inited[bc->bc_key->crypto_mode]) { + bio->bi_status = BLK_STS_IOERR; + return -EIO; + } + + if (bio_data_dir(bio) == WRITE) + return blk_crypto_encrypt_bio(bio_ptr); + + /* + * Mark bio as fallback crypted and replace the bio_crypt_ctx with + * another one contained in a bio_fallback_crypt_ctx, so that the + * fallback has space to store the info it needs for decryption. + */ + bc->bc_ksm = blk_crypto_ksm; + f_ctx = mempool_alloc(bio_fallback_crypt_ctx_pool, GFP_NOIO); + f_ctx->crypt_ctx = *bc; + memcpy(f_ctx->fallback_dun, bc->bc_dun, sizeof(f_ctx->fallback_dun)); + f_ctx->crypt_iter = bio->bi_iter; + + bio_crypt_free_ctx(bio); + bio->bi_crypt_context = &f_ctx->crypt_ctx; + + return 0; +} + +int __init blk_crypto_fallback_init(void) +{ + int i; + unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX]; + + prandom_bytes(blank_key, BLK_CRYPTO_MAX_KEY_SIZE); + + /* All blk-crypto modes have a crypto API fallback. */ + for (i = 0; i < BLK_ENCRYPTION_MODE_MAX; i++) + crypto_mode_supported[i] = 0xFFFFFFFF; + crypto_mode_supported[BLK_ENCRYPTION_MODE_INVALID] = 0; + + blk_crypto_ksm = keyslot_manager_create(blk_crypto_num_keyslots, + &blk_crypto_ksm_ll_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS, + crypto_mode_supported, NULL); + if (!blk_crypto_ksm) + return -ENOMEM; + + blk_crypto_wq = alloc_workqueue("blk_crypto_wq", + WQ_UNBOUND | WQ_HIGHPRI | + WQ_MEM_RECLAIM, num_online_cpus()); + if (!blk_crypto_wq) + return -ENOMEM; + + blk_crypto_keyslots = kcalloc(blk_crypto_num_keyslots, + sizeof(blk_crypto_keyslots[0]), + GFP_KERNEL); + if (!blk_crypto_keyslots) + return -ENOMEM; + + blk_crypto_bounce_page_pool = + mempool_create_page_pool(num_prealloc_bounce_pg, 0); + if (!blk_crypto_bounce_page_pool) + return -ENOMEM; + + blk_crypto_decrypt_work_cache = KMEM_CACHE(blk_crypto_decrypt_work, + SLAB_RECLAIM_ACCOUNT); + if (!blk_crypto_decrypt_work_cache) + return -ENOMEM; + + bio_fallback_crypt_ctx_cache = KMEM_CACHE(bio_fallback_crypt_ctx, 0); + if (!bio_fallback_crypt_ctx_cache) + return -ENOMEM; + + bio_fallback_crypt_ctx_pool = + mempool_create_slab_pool(num_prealloc_fallback_crypt_ctxs, + bio_fallback_crypt_ctx_cache); + if (!bio_fallback_crypt_ctx_pool) + return -ENOMEM; + + return 0; +} diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h new file mode 100644 index 0000000000000000000000000000000000000000..4da998c803f284fae262d029d76faab5a69d815b --- /dev/null +++ b/block/blk-crypto-internal.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __LINUX_BLK_CRYPTO_INTERNAL_H +#define __LINUX_BLK_CRYPTO_INTERNAL_H + +#include + +/* Represents a crypto mode supported by blk-crypto */ +struct blk_crypto_mode { + const char *cipher_str; /* crypto API name (for fallback case) */ + unsigned int keysize; /* key size in bytes */ + unsigned int ivsize; /* iv size in bytes */ +}; + +extern const struct blk_crypto_mode blk_crypto_modes[]; + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK + +int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num); + +int blk_crypto_fallback_submit_bio(struct bio **bio_ptr); + +bool blk_crypto_queue_decrypt_bio(struct bio *bio); + +int blk_crypto_fallback_evict_key(const struct blk_crypto_key *key); + +bool bio_crypt_fallback_crypted(const struct bio_crypt_ctx *bc); + +#else /* CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK */ + +static inline int +blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num) +{ + pr_warn_once("crypto API fallback is disabled\n"); + return -ENOPKG; +} + +static inline bool bio_crypt_fallback_crypted(const struct bio_crypt_ctx *bc) +{ + return false; +} + +static inline int blk_crypto_fallback_submit_bio(struct bio **bio_ptr) +{ + pr_warn_once("crypto API fallback disabled; failing request\n"); + (*bio_ptr)->bi_status = BLK_STS_NOTSUPP; + return -EIO; +} + +static inline bool blk_crypto_queue_decrypt_bio(struct bio *bio) +{ + WARN_ON(1); + return false; +} + +static inline int +blk_crypto_fallback_evict_key(const struct blk_crypto_key *key) +{ + return 0; +} + +#endif /* CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK */ + +#endif /* __LINUX_BLK_CRYPTO_INTERNAL_H */ diff --git a/block/blk-crypto.c b/block/blk-crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..e07a37cf8b5fbe2ec696e1027c17788fdfa7d0a0 --- /dev/null +++ b/block/blk-crypto.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +/* + * Refer to Documentation/block/inline-encryption.rst for detailed explanation. + */ + +#define pr_fmt(fmt) "blk-crypto: " fmt + +#include +#include +#include +#include +#include + +#include "blk-crypto-internal.h" + +const struct blk_crypto_mode blk_crypto_modes[] = { + [BLK_ENCRYPTION_MODE_AES_256_XTS] = { + .cipher_str = "xts(aes)", + .keysize = 64, + .ivsize = 16, + }, + [BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV] = { + .cipher_str = "essiv(cbc(aes),sha256)", + .keysize = 16, + .ivsize = 16, + }, + [BLK_ENCRYPTION_MODE_ADIANTUM] = { + .cipher_str = "adiantum(xchacha12,aes)", + .keysize = 32, + .ivsize = 32, + }, +}; + +/* Check that all I/O segments are data unit aligned */ +static int bio_crypt_check_alignment(struct bio *bio) +{ + const unsigned int data_unit_size = + bio->bi_crypt_context->bc_key->data_unit_size; + struct bvec_iter iter; + struct bio_vec bv; + + bio_for_each_segment(bv, bio, iter) { + if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size)) + return -EIO; + } + return 0; +} + +/** + * blk_crypto_submit_bio - handle submitting bio for inline encryption + * + * @bio_ptr: pointer to original bio pointer + * + * If the bio doesn't have inline encryption enabled or the submitter already + * specified a keyslot for the target device, do nothing. Else, a raw key must + * have been provided, so acquire a device keyslot for it if supported. Else, + * use the crypto API fallback. + * + * When the crypto API fallback is used for encryption, blk-crypto may choose to + * split the bio into 2 - the first one that will continue to be processed and + * the second one that will be resubmitted via generic_make_request. + * A bounce bio will be allocated to encrypt the contents of the aforementioned + * "first one", and *bio_ptr will be updated to this bounce bio. + * + * Return: 0 if bio submission should continue; nonzero if bio_endio() was + * already called so bio submission should abort. + */ +int blk_crypto_submit_bio(struct bio **bio_ptr) +{ + struct bio *bio = *bio_ptr; + struct request_queue *q; + struct bio_crypt_ctx *bc = bio->bi_crypt_context; + int err; + + if (!bc || !bio_has_data(bio)) + return 0; + + /* + * When a read bio is marked for fallback decryption, its bi_iter is + * saved so that when we decrypt the bio later, we know what part of it + * was marked for fallback decryption (when the bio is passed down after + * blk_crypto_submit bio, it may be split or advanced so we cannot rely + * on the bi_iter while decrypting in blk_crypto_endio) + */ + if (bio_crypt_fallback_crypted(bc)) + return 0; + + err = bio_crypt_check_alignment(bio); + if (err) { + bio->bi_status = BLK_STS_IOERR; + goto out; + } + + q = bio->bi_disk->queue; + + if (bc->bc_ksm) { + /* Key already programmed into device? */ + if (q->ksm == bc->bc_ksm) + return 0; + + /* Nope, release the existing keyslot. */ + bio_crypt_ctx_release_keyslot(bc); + } + + /* Get device keyslot if supported */ + if (keyslot_manager_crypto_mode_supported(q->ksm, + bc->bc_key->crypto_mode, + blk_crypto_key_dun_bytes(bc->bc_key), + bc->bc_key->data_unit_size, + bc->bc_key->is_hw_wrapped)) { + err = bio_crypt_ctx_acquire_keyslot(bc, q->ksm); + if (!err) + return 0; + + pr_warn_once("Failed to acquire keyslot for %s (err=%d). Falling back to crypto API.\n", + bio->bi_disk->disk_name, err); + } + + /* Fallback to crypto API */ + err = blk_crypto_fallback_submit_bio(bio_ptr); + if (err) + goto out; + + return 0; +out: + bio_endio(*bio_ptr); + return err; +} + +/** + * blk_crypto_endio - clean up bio w.r.t inline encryption during bio_endio + * + * @bio: the bio to clean up + * + * If blk_crypto_submit_bio decided to fallback to crypto API for this bio, + * we queue the bio for decryption into a workqueue and return false, + * and call bio_endio(bio) at a later time (after the bio has been decrypted). + * + * If the bio is not to be decrypted by the crypto API, this function releases + * the reference to the keyslot that blk_crypto_submit_bio got. + * + * Return: true if bio_endio should continue; false otherwise (bio_endio will + * be called again when bio has been decrypted). + */ +bool blk_crypto_endio(struct bio *bio) +{ + struct bio_crypt_ctx *bc = bio->bi_crypt_context; + + if (!bc) + return true; + + if (bio_crypt_fallback_crypted(bc)) { + /* + * The only bios who's crypto is handled by the blk-crypto + * fallback when they reach here are those with + * bio_data_dir(bio) == READ, since WRITE bios that are + * encrypted by the crypto API fallback are handled by + * blk_crypto_encrypt_endio(). + */ + return !blk_crypto_queue_decrypt_bio(bio); + } + + if (bc->bc_keyslot >= 0) + bio_crypt_ctx_release_keyslot(bc); + + return true; +} + +/** + * blk_crypto_init_key() - Prepare a key for use with blk-crypto + * @blk_key: Pointer to the blk_crypto_key to initialize. + * @raw_key: Pointer to the raw key. + * @raw_key_size: Size of raw key. Must be at least the required size for the + * chosen @crypto_mode; see blk_crypto_modes[]. (It's allowed + * to be longer than the mode's actual key size, in order to + * support inline encryption hardware that accepts wrapped keys. + * @is_hw_wrapped has to be set for such keys) + * @is_hw_wrapped: Denotes @raw_key is wrapped. + * @crypto_mode: identifier for the encryption algorithm to use + * @dun_bytes: number of bytes that will be used to specify the DUN when this + * key is used + * @data_unit_size: the data unit size to use for en/decryption + * + * Return: The blk_crypto_key that was prepared, or an ERR_PTR() on error. When + * done using the key, it must be freed with blk_crypto_free_key(). + */ +int blk_crypto_init_key(struct blk_crypto_key *blk_key, + const u8 *raw_key, unsigned int raw_key_size, + bool is_hw_wrapped, + enum blk_crypto_mode_num crypto_mode, + unsigned int dun_bytes, + unsigned int data_unit_size) +{ + const struct blk_crypto_mode *mode; + static siphash_key_t hash_key; + u32 hash; + + memset(blk_key, 0, sizeof(*blk_key)); + + if (crypto_mode >= ARRAY_SIZE(blk_crypto_modes)) + return -EINVAL; + + BUILD_BUG_ON(BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE < BLK_CRYPTO_MAX_KEY_SIZE); + + mode = &blk_crypto_modes[crypto_mode]; + if (is_hw_wrapped) { + if (raw_key_size < mode->keysize || + raw_key_size > BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE) + return -EINVAL; + } else { + if (raw_key_size != mode->keysize) + return -EINVAL; + } + + if (dun_bytes <= 0 || dun_bytes > BLK_CRYPTO_MAX_IV_SIZE) + return -EINVAL; + + if (!is_power_of_2(data_unit_size)) + return -EINVAL; + + blk_key->crypto_mode = crypto_mode; + blk_key->data_unit_size = data_unit_size; + blk_key->data_unit_size_bits = ilog2(data_unit_size); + blk_key->size = raw_key_size; + blk_key->is_hw_wrapped = is_hw_wrapped; + memcpy(blk_key->raw, raw_key, raw_key_size); + + /* + * The keyslot manager uses the SipHash of the key to implement O(1) key + * lookups while avoiding leaking information about the keys. It's + * precomputed here so that it only needs to be computed once per key. + */ + get_random_once(&hash_key, sizeof(hash_key)); + hash = (u32)siphash(raw_key, raw_key_size, &hash_key); + blk_crypto_key_set_hash_and_dun_bytes(blk_key, hash, dun_bytes); + + return 0; +} +EXPORT_SYMBOL_GPL(blk_crypto_init_key); + +/** + * blk_crypto_start_using_mode() - Start using blk-crypto on a device + * @crypto_mode: the crypto mode that will be used + * @dun_bytes: number of bytes that will be used to specify the DUN + * @data_unit_size: the data unit size that will be used + * @is_hw_wrapped_key: whether the key will be hardware-wrapped + * @q: the request queue for the device + * + * Upper layers must call this function to ensure that either the hardware + * supports the needed crypto settings, or the crypto API fallback has + * transforms for the needed mode allocated and ready to go. + * + * Return: 0 on success; -ENOPKG if the hardware doesn't support the crypto + * settings and blk-crypto-fallback is either disabled or the needed + * algorithm is disabled in the crypto API; or another -errno code. + */ +int blk_crypto_start_using_mode(enum blk_crypto_mode_num crypto_mode, + unsigned int dun_bytes, + unsigned int data_unit_size, + bool is_hw_wrapped_key, + struct request_queue *q) +{ + if (keyslot_manager_crypto_mode_supported(q->ksm, crypto_mode, + dun_bytes, data_unit_size, + is_hw_wrapped_key)) + return 0; + if (is_hw_wrapped_key) { + pr_warn_once("hardware doesn't support wrapped keys\n"); + return -EOPNOTSUPP; + } + return blk_crypto_fallback_start_using_mode(crypto_mode); +} +EXPORT_SYMBOL_GPL(blk_crypto_start_using_mode); + +/** + * blk_crypto_evict_key() - Evict a key from any inline encryption hardware + * it may have been programmed into + * @q: The request queue who's keyslot manager this key might have been + * programmed into + * @key: The key to evict + * + * Upper layers (filesystems) should call this function to ensure that a key + * is evicted from hardware that it might have been programmed into. This + * will call keyslot_manager_evict_key on the queue's keyslot manager, if one + * exists, and supports the crypto algorithm with the specified data unit size. + * Otherwise, it will evict the key from the blk-crypto-fallback's ksm. + * + * Return: 0 on success, -err on error. + */ +int blk_crypto_evict_key(struct request_queue *q, + const struct blk_crypto_key *key) +{ + if (q->ksm && + keyslot_manager_crypto_mode_supported(q->ksm, key->crypto_mode, + blk_crypto_key_dun_bytes(key), + key->data_unit_size, + key->is_hw_wrapped)) + return keyslot_manager_evict_key(q->ksm, key); + + return blk_crypto_fallback_evict_key(key); +} +EXPORT_SYMBOL_GPL(blk_crypto_evict_key); diff --git a/block/blk-ioc.c b/block/blk-ioc.c index f23311e4b201fe60a6cf460a5c194cf43fd8f65b..e56a480b6f929b296d25609b54920268ad38db71 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -87,6 +87,7 @@ static void ioc_destroy_icq(struct io_cq *icq) * making it impossible to determine icq_cache. Record it in @icq. */ icq->__rcu_icq_cache = et->icq_cache; + icq->flags |= ICQ_DESTROYED; call_rcu(&icq->__rcu_head, icq_free_icq_rcu); } @@ -230,15 +231,21 @@ static void __ioc_clear_queue(struct list_head *icq_list) { unsigned long flags; + rcu_read_lock(); while (!list_empty(icq_list)) { struct io_cq *icq = list_entry(icq_list->next, struct io_cq, q_node); struct io_context *ioc = icq->ioc; spin_lock_irqsave(&ioc->lock, flags); + if (icq->flags & ICQ_DESTROYED) { + spin_unlock_irqrestore(&ioc->lock, flags); + continue; + } ioc_destroy_icq(icq); spin_unlock_irqrestore(&ioc->lock, flags); } + rcu_read_unlock(); } /** diff --git a/block/blk-merge.c b/block/blk-merge.c index 82dc0c1df283646a8a4e949267938677672aac24..9e322d62d9f4ec8e4b213e38bc6f41c4ca838d3a 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -9,7 +9,7 @@ #include #include -#include + #include "blk.h" static struct bio *blk_bio_discard_split(struct request_queue *q, @@ -509,13 +509,13 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req, if (blk_integrity_rq(req) && integrity_req_gap_back_merge(req, bio)) return 0; - if (blk_try_merge(req, bio) != ELEVATOR_BACK_MERGE) - return 0; if (blk_rq_sectors(req) + bio_sectors(bio) > blk_rq_get_max_sectors(req, blk_rq_pos(req))) { req_set_nomerge(q, req); return 0; } + if (!bio_crypt_ctx_mergeable(req->bio, blk_rq_bytes(req), bio)) + return 0; if (!bio_flagged(req->biotail, BIO_SEG_VALID)) blk_recount_segments(q, req->biotail); if (!bio_flagged(bio, BIO_SEG_VALID)) @@ -533,13 +533,13 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req, if (blk_integrity_rq(req) && integrity_req_gap_front_merge(req, bio)) return 0; - if (blk_try_merge(req, bio) != ELEVATOR_FRONT_MERGE) - return 0; if (blk_rq_sectors(req) + bio_sectors(bio) > blk_rq_get_max_sectors(req, bio->bi_iter.bi_sector)) { req_set_nomerge(q, req); return 0; } + if (!bio_crypt_ctx_mergeable(bio, bio->bi_iter.bi_size, req->bio)) + return 0; if (!bio_flagged(bio, BIO_SEG_VALID)) blk_recount_segments(q, bio); if (!bio_flagged(req->bio, BIO_SEG_VALID)) @@ -616,6 +616,9 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, if (blk_integrity_merge_rq(q, req, next) == false) return 0; + if (!bio_crypt_ctx_mergeable(req->bio, blk_rq_bytes(req), next->bio)) + return 0; + /* Merge is OK... */ req->nr_phys_segments = total_phys_segments; return 1; @@ -668,11 +671,6 @@ static void blk_account_io_merge(struct request *req) } } -static bool crypto_not_mergeable(const struct bio *bio, const struct bio *nxt) -{ - return (!pfk_allow_merge_bio(bio, nxt)); -} - /* * For non-mq, this has to be called with the request spinlock acquired. * For mq with scheduling, the appropriate queue wide lock should be held. @@ -711,9 +709,6 @@ static struct request *attempt_merge(struct request_queue *q, if (req->write_hint != next->write_hint) return NULL; - if (crypto_not_mergeable(req->bio, next->bio)) - return 0; - /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn @@ -845,24 +840,21 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (rq->write_hint != bio->bi_write_hint) return false; + /* Only merge if the crypt contexts are compatible */ + if (!bio_crypt_ctx_compatible(bio, rq->bio)) + return false; + return true; } enum elv_merge blk_try_merge(struct request *rq, struct bio *bio) { if (req_op(rq) == REQ_OP_DISCARD && - queue_max_discard_segments(rq->q) > 1) { + queue_max_discard_segments(rq->q) > 1) return ELEVATOR_DISCARD_MERGE; - } else if (blk_rq_pos(rq) + blk_rq_sectors(rq) == - bio->bi_iter.bi_sector) { - if (crypto_not_mergeable(rq->bio, bio)) - return ELEVATOR_NO_MERGE; + else if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector) return ELEVATOR_BACK_MERGE; - } else if (blk_rq_pos(rq) - bio_sectors(bio) == - bio->bi_iter.bi_sector) { - if (crypto_not_mergeable(bio, rq->bio)) - return ELEVATOR_NO_MERGE; + else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector) return ELEVATOR_FRONT_MERGE; - } return ELEVATOR_NO_MERGE; } diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 3d2ab65d2dd15a012d3ff1efb71ad5b5aca6ddd5..e4b3eeaffc821aa61a03c1a9fad2782ea7ce6eb9 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -334,6 +334,13 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn, struct blk_mq_hw_ctx *hctx; int i; + /* + * __blk_mq_update_nr_hw_queues will update the nr_hw_queues and + * queue_hw_ctx after freeze the queue, so we use q_usage_counter + * to avoid race with it. + */ + if (!percpu_ref_tryget(&q->q_usage_counter)) + return; queue_for_each_hw_ctx(q, hctx, i) { struct blk_mq_tags *tags = hctx->tags; @@ -349,7 +356,7 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn, bt_for_each(hctx, &tags->breserved_tags, fn, priv, true); bt_for_each(hctx, &tags->bitmap_tags, fn, priv, false); } - + blk_queue_exit(q); } static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth, diff --git a/block/blk-mq.c b/block/blk-mq.c index eac4448047366bb60db76788833f6e5b977dd467..9d53f476c5179713a41b5e9e672d9152626519cd 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2748,6 +2748,10 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, list_for_each_entry(q, &set->tag_list, tag_set_list) blk_mq_unfreeze_queue(q); + /* + * Sync with blk_mq_queue_tag_busy_iter. + */ + synchronize_rcu(); } void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues) diff --git a/block/blk-settings.c b/block/blk-settings.c index 6c2faaa38cc1e47f41cb81f2e223df82f6db4c4b..e0a744921ed3d349a5a43711364781b2f4d702e6 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -717,6 +717,9 @@ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n", top, bottom); } + + t->backing_dev_info->io_pages = + t->limits.max_sectors >> (PAGE_SHIFT - 9); } EXPORT_SYMBOL(disk_stack_limits); diff --git a/block/elevator.c b/block/elevator.c index 2346c5b53b9337fc2ac860671bfa9a1bd8493e1a..8320d97240bec6096a7cf75e221bf63d3ffc7ea3 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -443,7 +443,7 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, { struct elevator_queue *e = q->elevator; struct request *__rq; - enum elv_merge ret; + /* * Levels of merges: * nomerges: No merges at all attempted @@ -456,11 +456,9 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, /* * First try one-hit cache. */ - if (q->last_merge) { - if (!elv_bio_merge_ok(q->last_merge, bio)) - return ELEVATOR_NO_MERGE; + if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { + enum elv_merge ret = blk_try_merge(q->last_merge, bio); - ret = blk_try_merge(q->last_merge, bio); if (ret != ELEVATOR_NO_MERGE) { *req = q->last_merge; return ret; diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c new file mode 100644 index 0000000000000000000000000000000000000000..13d34b85762514bfd9de83c7a617e17409b12676 --- /dev/null +++ b/block/keyslot-manager.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +/** + * DOC: The Keyslot Manager + * + * Many devices with inline encryption support have a limited number of "slots" + * into which encryption contexts may be programmed, and requests can be tagged + * with a slot number to specify the key to use for en/decryption. + * + * As the number of slots are limited, and programming keys is expensive on + * many inline encryption hardware, we don't want to program the same key into + * multiple slots - if multiple requests are using the same key, we want to + * program just one slot with that key and use that slot for all requests. + * + * The keyslot manager manages these keyslots appropriately, and also acts as + * an abstraction between the inline encryption hardware and the upper layers. + * + * Lower layer devices will set up a keyslot manager in their request queue + * and tell it how to perform device specific operations like programming/ + * evicting keys from keyslots. + * + * Upper layers will call keyslot_manager_get_slot_for_key() to program a + * key into some slot in the inline encryption hardware. + */ +#include +#include +#include +#include +#include +#include +#include + +struct keyslot { + atomic_t slot_refs; + struct list_head idle_slot_node; + struct hlist_node hash_node; + struct blk_crypto_key key; +}; + +struct keyslot_manager { + unsigned int num_slots; + struct keyslot_mgmt_ll_ops ksm_ll_ops; + unsigned int features; + unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX]; + unsigned int max_dun_bytes_supported; + void *ll_priv_data; + + /* Protects programming and evicting keys from the device */ + struct rw_semaphore lock; + + /* List of idle slots, with least recently used slot at front */ + wait_queue_head_t idle_slots_wait_queue; + struct list_head idle_slots; + spinlock_t idle_slots_lock; + + /* + * Hash table which maps key hashes to keyslots, so that we can find a + * key's keyslot in O(1) time rather than O(num_slots). Protected by + * 'lock'. A cryptographic hash function is used so that timing attacks + * can't leak information about the raw keys. + */ + struct hlist_head *slot_hashtable; + unsigned int slot_hashtable_size; + + /* Per-keyslot data */ + struct keyslot slots[]; +}; + +static inline bool keyslot_manager_is_passthrough(struct keyslot_manager *ksm) +{ + return ksm->num_slots == 0; +} + +/** + * keyslot_manager_create() - Create a keyslot manager + * @num_slots: The number of key slots to manage. + * @ksm_ll_ops: The struct keyslot_mgmt_ll_ops for the device that this keyslot + * manager will use to perform operations like programming and + * evicting keys. + * @features: The supported features as a bitmask of BLK_CRYPTO_FEATURE_* flags. + * Most drivers should set BLK_CRYPTO_FEATURE_STANDARD_KEYS here. + * @crypto_mode_supported: Array of size BLK_ENCRYPTION_MODE_MAX of + * bitmasks that represents whether a crypto mode + * and data unit size are supported. The i'th bit + * of crypto_mode_supported[crypto_mode] is set iff + * a data unit size of (1 << i) is supported. We + * only support data unit sizes that are powers of + * 2. + * @ll_priv_data: Private data passed as is to the functions in ksm_ll_ops. + * + * Allocate memory for and initialize a keyslot manager. Called by e.g. + * storage drivers to set up a keyslot manager in their request_queue. + * + * Context: May sleep + * Return: Pointer to constructed keyslot manager or NULL on error. + */ +struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, + const struct keyslot_mgmt_ll_ops *ksm_ll_ops, + unsigned int features, + const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], + void *ll_priv_data) +{ + struct keyslot_manager *ksm; + unsigned int slot; + unsigned int i; + + if (num_slots == 0) + return NULL; + + /* Check that all ops are specified */ + if (ksm_ll_ops->keyslot_program == NULL || + ksm_ll_ops->keyslot_evict == NULL) + return NULL; + + ksm = kvzalloc(struct_size(ksm, slots, num_slots), GFP_KERNEL); + if (!ksm) + return NULL; + + ksm->num_slots = num_slots; + ksm->ksm_ll_ops = *ksm_ll_ops; + ksm->features = features; + memcpy(ksm->crypto_mode_supported, crypto_mode_supported, + sizeof(ksm->crypto_mode_supported)); + ksm->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE; + ksm->ll_priv_data = ll_priv_data; + + init_rwsem(&ksm->lock); + + init_waitqueue_head(&ksm->idle_slots_wait_queue); + INIT_LIST_HEAD(&ksm->idle_slots); + + for (slot = 0; slot < num_slots; slot++) { + list_add_tail(&ksm->slots[slot].idle_slot_node, + &ksm->idle_slots); + } + + spin_lock_init(&ksm->idle_slots_lock); + + ksm->slot_hashtable_size = roundup_pow_of_two(num_slots); + ksm->slot_hashtable = kvmalloc_array(ksm->slot_hashtable_size, + sizeof(ksm->slot_hashtable[0]), + GFP_KERNEL); + if (!ksm->slot_hashtable) + goto err_free_ksm; + for (i = 0; i < ksm->slot_hashtable_size; i++) + INIT_HLIST_HEAD(&ksm->slot_hashtable[i]); + + return ksm; + +err_free_ksm: + keyslot_manager_destroy(ksm); + return NULL; +} +EXPORT_SYMBOL_GPL(keyslot_manager_create); + +void keyslot_manager_set_max_dun_bytes(struct keyslot_manager *ksm, + unsigned int max_dun_bytes) +{ + ksm->max_dun_bytes_supported = max_dun_bytes; +} +EXPORT_SYMBOL_GPL(keyslot_manager_set_max_dun_bytes); + +static inline struct hlist_head * +hash_bucket_for_key(struct keyslot_manager *ksm, + const struct blk_crypto_key *key) +{ + return &ksm->slot_hashtable[blk_crypto_key_hash(key) & + (ksm->slot_hashtable_size - 1)]; +} + +static void remove_slot_from_lru_list(struct keyslot_manager *ksm, int slot) +{ + unsigned long flags; + + spin_lock_irqsave(&ksm->idle_slots_lock, flags); + list_del(&ksm->slots[slot].idle_slot_node); + spin_unlock_irqrestore(&ksm->idle_slots_lock, flags); +} + +static int find_keyslot(struct keyslot_manager *ksm, + const struct blk_crypto_key *key) +{ + const struct hlist_head *head = hash_bucket_for_key(ksm, key); + const struct keyslot *slotp; + + hlist_for_each_entry(slotp, head, hash_node) { + if (slotp->key.hash == key->hash && + slotp->key.crypto_mode == key->crypto_mode && + slotp->key.size == key->size && + slotp->key.data_unit_size == key->data_unit_size && + !crypto_memneq(slotp->key.raw, key->raw, key->size)) + return slotp - ksm->slots; + } + return -ENOKEY; +} + +static int find_and_grab_keyslot(struct keyslot_manager *ksm, + const struct blk_crypto_key *key) +{ + int slot; + + slot = find_keyslot(ksm, key); + if (slot < 0) + return slot; + if (atomic_inc_return(&ksm->slots[slot].slot_refs) == 1) { + /* Took first reference to this slot; remove it from LRU list */ + remove_slot_from_lru_list(ksm, slot); + } + return slot; +} + +/** + * keyslot_manager_get_slot_for_key() - Program a key into a keyslot. + * @ksm: The keyslot manager to program the key into. + * @key: Pointer to the key object to program, including the raw key, crypto + * mode, and data unit size. + * + * Get a keyslot that's been programmed with the specified key. If one already + * exists, return it with incremented refcount. Otherwise, wait for a keyslot + * to become idle and program it. + * + * Context: Process context. Takes and releases ksm->lock. + * Return: The keyslot on success, else a -errno value. + */ +int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm, + const struct blk_crypto_key *key) +{ + int slot; + int err; + struct keyslot *idle_slot; + + if (keyslot_manager_is_passthrough(ksm)) + return 0; + + down_read(&ksm->lock); + slot = find_and_grab_keyslot(ksm, key); + up_read(&ksm->lock); + if (slot != -ENOKEY) + return slot; + + for (;;) { + down_write(&ksm->lock); + slot = find_and_grab_keyslot(ksm, key); + if (slot != -ENOKEY) { + up_write(&ksm->lock); + return slot; + } + + /* + * If we're here, that means there wasn't a slot that was + * already programmed with the key. So try to program it. + */ + if (!list_empty(&ksm->idle_slots)) + break; + + up_write(&ksm->lock); + wait_event(ksm->idle_slots_wait_queue, + !list_empty(&ksm->idle_slots)); + } + + idle_slot = list_first_entry(&ksm->idle_slots, struct keyslot, + idle_slot_node); + slot = idle_slot - ksm->slots; + + err = ksm->ksm_ll_ops.keyslot_program(ksm, key, slot); + if (err) { + wake_up(&ksm->idle_slots_wait_queue); + up_write(&ksm->lock); + return err; + } + + /* Move this slot to the hash list for the new key. */ + if (idle_slot->key.crypto_mode != BLK_ENCRYPTION_MODE_INVALID) + hlist_del(&idle_slot->hash_node); + hlist_add_head(&idle_slot->hash_node, hash_bucket_for_key(ksm, key)); + + atomic_set(&idle_slot->slot_refs, 1); + idle_slot->key = *key; + + remove_slot_from_lru_list(ksm, slot); + + up_write(&ksm->lock); + return slot; +} + +/** + * keyslot_manager_get_slot() - Increment the refcount on the specified slot. + * @ksm: The keyslot manager that we want to modify. + * @slot: The slot to increment the refcount of. + * + * This function assumes that there is already an active reference to that slot + * and simply increments the refcount. This is useful when cloning a bio that + * already has a reference to a keyslot, and we want the cloned bio to also have + * its own reference. + * + * Context: Any context. + */ +void keyslot_manager_get_slot(struct keyslot_manager *ksm, unsigned int slot) +{ + if (keyslot_manager_is_passthrough(ksm)) + return; + + if (WARN_ON(slot >= ksm->num_slots)) + return; + + WARN_ON(atomic_inc_return(&ksm->slots[slot].slot_refs) < 2); +} + +/** + * keyslot_manager_put_slot() - Release a reference to a slot + * @ksm: The keyslot manager to release the reference from. + * @slot: The slot to release the reference from. + * + * Context: Any context. + */ +void keyslot_manager_put_slot(struct keyslot_manager *ksm, unsigned int slot) +{ + unsigned long flags; + + if (keyslot_manager_is_passthrough(ksm)) + return; + + if (WARN_ON(slot >= ksm->num_slots)) + return; + + if (atomic_dec_and_lock_irqsave(&ksm->slots[slot].slot_refs, + &ksm->idle_slots_lock, flags)) { + list_add_tail(&ksm->slots[slot].idle_slot_node, + &ksm->idle_slots); + spin_unlock_irqrestore(&ksm->idle_slots_lock, flags); + wake_up(&ksm->idle_slots_wait_queue); + } +} + +/** + * keyslot_manager_crypto_mode_supported() - Find out if a crypto_mode / + * data unit size / is_hw_wrapped_key + * combination is supported by a ksm. + * @ksm: The keyslot manager to check + * @crypto_mode: The crypto mode to check for. + * @dun_bytes: The number of bytes that will be used to specify the DUN + * @data_unit_size: The data_unit_size for the mode. + * @is_hw_wrapped_key: Whether a hardware-wrapped key will be used. + * + * Calls and returns the result of the crypto_mode_supported function specified + * by the ksm. + * + * Context: Process context. + * Return: Whether or not this ksm supports the specified crypto settings. + */ +bool keyslot_manager_crypto_mode_supported(struct keyslot_manager *ksm, + enum blk_crypto_mode_num crypto_mode, + unsigned int dun_bytes, + unsigned int data_unit_size, + bool is_hw_wrapped_key) +{ + if (!ksm) + return false; + if (WARN_ON(crypto_mode >= BLK_ENCRYPTION_MODE_MAX)) + return false; + if (WARN_ON(!is_power_of_2(data_unit_size))) + return false; + if (is_hw_wrapped_key) { + if (!(ksm->features & BLK_CRYPTO_FEATURE_WRAPPED_KEYS)) + return false; + } else { + if (!(ksm->features & BLK_CRYPTO_FEATURE_STANDARD_KEYS)) + return false; + } + if (!(ksm->crypto_mode_supported[crypto_mode] & data_unit_size)) + return false; + + return ksm->max_dun_bytes_supported >= dun_bytes; +} + +/** + * keyslot_manager_evict_key() - Evict a key from the lower layer device. + * @ksm: The keyslot manager to evict from + * @key: The key to evict + * + * Find the keyslot that the specified key was programmed into, and evict that + * slot from the lower layer device if that slot is not currently in use. + * + * Context: Process context. Takes and releases ksm->lock. + * Return: 0 on success, -EBUSY if the key is still in use, or another + * -errno value on other error. + */ +int keyslot_manager_evict_key(struct keyslot_manager *ksm, + const struct blk_crypto_key *key) +{ + int slot; + int err; + struct keyslot *slotp; + + if (keyslot_manager_is_passthrough(ksm)) { + if (ksm->ksm_ll_ops.keyslot_evict) { + down_write(&ksm->lock); + err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, -1); + up_write(&ksm->lock); + return err; + } + return 0; + } + + down_write(&ksm->lock); + slot = find_keyslot(ksm, key); + if (slot < 0) { + err = slot; + goto out_unlock; + } + slotp = &ksm->slots[slot]; + + if (atomic_read(&slotp->slot_refs) != 0) { + err = -EBUSY; + goto out_unlock; + } + err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, slot); + if (err) + goto out_unlock; + + hlist_del(&slotp->hash_node); + memzero_explicit(&slotp->key, sizeof(slotp->key)); + err = 0; +out_unlock: + up_write(&ksm->lock); + return err; +} + +/** + * keyslot_manager_reprogram_all_keys() - Re-program all keyslots. + * @ksm: The keyslot manager + * + * Re-program all keyslots that are supposed to have a key programmed. This is + * intended only for use by drivers for hardware that loses its keys on reset. + * + * Context: Process context. Takes and releases ksm->lock. + */ +void keyslot_manager_reprogram_all_keys(struct keyslot_manager *ksm) +{ + unsigned int slot; + + if (WARN_ON(keyslot_manager_is_passthrough(ksm))) + return; + + down_write(&ksm->lock); + for (slot = 0; slot < ksm->num_slots; slot++) { + const struct keyslot *slotp = &ksm->slots[slot]; + int err; + + if (slotp->key.crypto_mode == BLK_ENCRYPTION_MODE_INVALID) + continue; + + err = ksm->ksm_ll_ops.keyslot_program(ksm, &slotp->key, slot); + WARN_ON(err); + } + up_write(&ksm->lock); +} +EXPORT_SYMBOL_GPL(keyslot_manager_reprogram_all_keys); + +/** + * keyslot_manager_private() - return the private data stored with ksm + * @ksm: The keyslot manager + * + * Returns the private data passed to the ksm when it was created. + */ +void *keyslot_manager_private(struct keyslot_manager *ksm) +{ + return ksm->ll_priv_data; +} +EXPORT_SYMBOL_GPL(keyslot_manager_private); + +void keyslot_manager_destroy(struct keyslot_manager *ksm) +{ + if (ksm) { + kvfree(ksm->slot_hashtable); + memzero_explicit(ksm, struct_size(ksm, slots, ksm->num_slots)); + kvfree(ksm); + } +} +EXPORT_SYMBOL_GPL(keyslot_manager_destroy); + +/** + * keyslot_manager_create_passthrough() - Create a passthrough keyslot manager + * @ksm_ll_ops: The struct keyslot_mgmt_ll_ops + * @features: Bitmask of BLK_CRYPTO_FEATURE_* flags + * @crypto_mode_supported: Bitmasks for supported encryption modes + * @ll_priv_data: Private data passed as is to the functions in ksm_ll_ops. + * + * Allocate memory for and initialize a passthrough keyslot manager. + * Called by e.g. storage drivers to set up a keyslot manager in their + * request_queue, when the storage driver wants to manage its keys by itself. + * This is useful for inline encryption hardware that don't have a small fixed + * number of keyslots, and for layered devices. + * + * See keyslot_manager_create() for more details about the parameters. + * + * Context: This function may sleep + * Return: Pointer to constructed keyslot manager or NULL on error. + */ +struct keyslot_manager *keyslot_manager_create_passthrough( + const struct keyslot_mgmt_ll_ops *ksm_ll_ops, + unsigned int features, + const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], + void *ll_priv_data) +{ + struct keyslot_manager *ksm; + + ksm = kzalloc(sizeof(*ksm), GFP_KERNEL); + if (!ksm) + return NULL; + + ksm->ksm_ll_ops = *ksm_ll_ops; + ksm->features = features; + memcpy(ksm->crypto_mode_supported, crypto_mode_supported, + sizeof(ksm->crypto_mode_supported)); + ksm->max_dun_bytes_supported = BLK_CRYPTO_MAX_IV_SIZE; + ksm->ll_priv_data = ll_priv_data; + + init_rwsem(&ksm->lock); + + return ksm; +} +EXPORT_SYMBOL_GPL(keyslot_manager_create_passthrough); + +/** + * keyslot_manager_intersect_modes() - restrict supported modes by child device + * @parent: The keyslot manager for parent device + * @child: The keyslot manager for child device, or NULL + * + * Clear any crypto mode support bits in @parent that aren't set in @child. + * If @child is NULL, then all parent bits are cleared. + * + * Only use this when setting up the keyslot manager for a layered device, + * before it's been exposed yet. + */ +void keyslot_manager_intersect_modes(struct keyslot_manager *parent, + const struct keyslot_manager *child) +{ + if (child) { + unsigned int i; + + parent->features &= child->features; + parent->max_dun_bytes_supported = + min(parent->max_dun_bytes_supported, + child->max_dun_bytes_supported); + for (i = 0; i < ARRAY_SIZE(child->crypto_mode_supported); i++) { + parent->crypto_mode_supported[i] &= + child->crypto_mode_supported[i]; + } + } else { + parent->features = 0; + parent->max_dun_bytes_supported = 0; + memset(parent->crypto_mode_supported, 0, + sizeof(parent->crypto_mode_supported)); + } +} +EXPORT_SYMBOL_GPL(keyslot_manager_intersect_modes); + +/** + * keyslot_manager_derive_raw_secret() - Derive software secret from wrapped key + * @ksm: The keyslot manager + * @wrapped_key: The wrapped key + * @wrapped_key_size: Size of the wrapped key in bytes + * @secret: (output) the software secret + * @secret_size: (output) the number of secret bytes to derive + * + * Given a hardware-wrapped key, ask the hardware to derive a secret which + * software can use for cryptographic tasks other than inline encryption. The + * derived secret is guaranteed to be cryptographically isolated from the key + * with which any inline encryption with this wrapped key would actually be + * done. I.e., both will be derived from the unwrapped key. + * + * Return: 0 on success, -EOPNOTSUPP if hardware-wrapped keys are unsupported, + * or another -errno code. + */ +int keyslot_manager_derive_raw_secret(struct keyslot_manager *ksm, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, unsigned int secret_size) +{ + int err; + + down_write(&ksm->lock); + if (ksm->ksm_ll_ops.derive_raw_secret) { + err = ksm->ksm_ll_ops.derive_raw_secret(ksm, wrapped_key, + wrapped_key_size, + secret, secret_size); + } else { + err = -EOPNOTSUPP; + } + up_write(&ksm->lock); + + return err; +} +EXPORT_SYMBOL_GPL(keyslot_manager_derive_raw_secret); diff --git a/build.config.common b/build.config.common index d4754486cd821612b3bf4ee18de1708eba2af2fe..6176b14b9b88c4043d4be7901b282ca4f6fd42a4 100644 --- a/build.config.common +++ b/build.config.common @@ -3,7 +3,7 @@ KERNEL_DIR=common CC=clang LD=ld.lld -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r370808/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r377782c/bin BUILDTOOLS_PREBUILT_BIN=build/build-tools/path/linux-x86 EXTRA_CMDS='' diff --git a/crypto/algapi.c b/crypto/algapi.c index 50eb828db767e8256082f7c4b42d0935b8b5606c..603d2d6372091d199b6f45af7e1417936a7eef76 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -652,11 +652,9 @@ EXPORT_SYMBOL_GPL(crypto_grab_spawn); void crypto_drop_spawn(struct crypto_spawn *spawn) { - if (!spawn->alg) - return; - down_write(&crypto_alg_sem); - list_del(&spawn->list); + if (spawn->alg) + list_del(&spawn->list); up_write(&crypto_alg_sem); } EXPORT_SYMBOL_GPL(crypto_drop_spawn); @@ -664,22 +662,16 @@ EXPORT_SYMBOL_GPL(crypto_drop_spawn); static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn) { struct crypto_alg *alg; - struct crypto_alg *alg2; down_read(&crypto_alg_sem); alg = spawn->alg; - alg2 = alg; - if (alg2) - alg2 = crypto_mod_get(alg2); - up_read(&crypto_alg_sem); - - if (!alg2) { - if (alg) - crypto_shoot_alg(alg); - return ERR_PTR(-EAGAIN); + if (alg && !crypto_mod_get(alg)) { + alg->cra_flags |= CRYPTO_ALG_DYING; + alg = NULL; } + up_read(&crypto_alg_sem); - return alg; + return alg ?: ERR_PTR(-EAGAIN); } struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, diff --git a/crypto/api.c b/crypto/api.c index ff7a7852bb17acc90535be965727f42a2a9ef7e4..6832b599ec4c70a8ebfcbcac9245574eca07b346 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -340,13 +340,12 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) return len; } -void crypto_shoot_alg(struct crypto_alg *alg) +static void crypto_shoot_alg(struct crypto_alg *alg) { down_write(&crypto_alg_sem); alg->cra_flags |= CRYPTO_ALG_DYING; up_write(&crypto_alg_sem); } -EXPORT_SYMBOL_GPL(crypto_shoot_alg); struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, u32 mask) diff --git a/crypto/internal.h b/crypto/internal.h index f07320423191ac3171d29f2a7fb7aa9a13b74ce7..6262ec0435b49ff4caba850439805e9dbb921dfa 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -84,7 +84,6 @@ void crypto_alg_tested(const char *name, int err); void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, struct crypto_alg *nalg); void crypto_remove_final(struct list_head *list); -void crypto_shoot_alg(struct crypto_alg *alg); struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, u32 mask); void *crypto_create_tfm(struct crypto_alg *alg, diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index 1348541da463a0cfe57a20e2fa9ddef432194d96..85082574c515402581c072e238fefb6b62bc1de8 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -130,7 +130,6 @@ static void pcrypt_aead_done(struct crypto_async_request *areq, int err) struct padata_priv *padata = pcrypt_request_padata(preq); padata->info = err; - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; padata_do_serial(padata); } diff --git a/disable_dbgfs.sh b/disable_dbgfs.sh new file mode 100755 index 0000000000000000000000000000000000000000..fe23680972a5db4bbf0d37854efb846ec4ca5aad --- /dev/null +++ b/disable_dbgfs.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# disable debugfs for user builds +export MAKE_ARGS=$@ + +if [ ${DISABLE_DEBUGFS} == "true" ]; then + echo "build variant ${TARGET_BUILD_VARIANT}" + if [ ${TARGET_BUILD_VARIANT} == "user" ] && \ + [ ${ARCH} == "arm64" ]; then + echo "combining fragments for user build" + (cd $KERNEL_DIR && \ + ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE}\ + ./scripts/kconfig/merge_config.sh \ + ./arch/${ARCH}/configs/$DEFCONFIG \ + ./arch/${ARCH}/configs/vendor/debugfs.config + make ${MAKE_ARGS} ARCH=${ARCH} \ + CROSS_COMPILE=${CROSS_COMPILE} savedefconfig + mv defconfig ./arch/${ARCH}/configs/$DEFCONFIG + rm .config) + else + if [[ ${DEFCONFIG} == *"perf_defconfig" ]] && \ + [ ${ARCH} == "arm64" ]; then + echo "resetting perf defconfig" + (cd ${KERNEL_DIR} && \ + git checkout arch/$ARCH/configs/$DEFCONFIG) + fi + fi +fi diff --git a/drivers/Kconfig b/drivers/Kconfig index 83e7ecb8600b22bc6a31212b52f09aa07fff906d..43377a3acb970b42badd910de16be6035869d945 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -201,6 +201,8 @@ source "drivers/thunderbolt/Kconfig" source "drivers/android/Kconfig" +source "drivers/gpu/trace/Kconfig" + source "drivers/nvdimm/Kconfig" source "drivers/dax/Kconfig" diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index 95600309ce420a21d32f50f6b8095a6fe335fb78..0bd1899a287f37b88595ac3dfc8e8f42ea5d845d 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -58,12 +58,14 @@ static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat) } #endif +static bool acpi_no_watchdog; + static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) { const struct acpi_table_wdat *wdat = NULL; acpi_status status; - if (acpi_disabled) + if (acpi_disabled || acpi_no_watchdog) return NULL; status = acpi_get_table(ACPI_SIG_WDAT, 0, @@ -91,6 +93,14 @@ bool acpi_has_watchdog(void) } EXPORT_SYMBOL_GPL(acpi_has_watchdog); +/* ACPI watchdog can be disabled on boot command line */ +static int __init disable_acpi_watchdog(char *str) +{ + acpi_no_watchdog = true; + return 1; +} +__setup("acpi_no_watchdog", disable_acpi_watchdog); + void __init acpi_watchdog_init(void) { const struct acpi_wdat_entry *entries; @@ -129,12 +139,11 @@ void __init acpi_watchdog_init(void) gas = &entries[i].register_region; res.start = gas->address; + res.end = res.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1; if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { res.flags = IORESOURCE_MEM; - res.end = res.start + ALIGN(gas->access_width, 4) - 1; } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { res.flags = IORESOURCE_IO; - res.end = res.start + gas->access_width - 1; } else { pr_warn("Unsupported address space: %u\n", gas->space_id); diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 7bcf5f5ea0297ffcec2cbd39b9171e4ba93afd50..8df4a49a99a6b1031b47f8767ab31f0c59b125da 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -273,7 +273,7 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, * FUNCTION: acpi_ds_get_field_names * * PARAMETERS: info - create_field info structure - * ` walk_state - Current method state + * walk_state - Current method state * arg - First parser arg for the field name list * * RETURN: Status diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index eaa859a89702a2290d62e87ecf5ef9131afe708a..1d82e1419397e469146ed101f0d044d6f368d6d6 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -444,6 +444,27 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); + /* + * Disassembler: handle create field operators here. + * + * create_buffer_field is a deferred op that is typically processed in load + * pass 2. However, disassembly of control method contents walk the parse + * tree with ACPI_PARSE_LOAD_PASS1 and AML_CREATE operators are processed + * in a later walk. This is a problem when there is a control method that + * has the same name as the AML_CREATE object. In this case, any use of the + * name segment will be detected as a method call rather than a reference + * to a buffer field. + * + * This earlier creation during disassembly solves this issue by inserting + * the named object in the ACPI namespace so that references to this name + * would be a name string rather than a method call. + */ + if ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) && + (walk_state->op_info->flags & AML_CREATE)) { + status = acpi_ds_create_buffer_field(op, walk_state); + return_ACPI_STATUS(status); + } + /* We are only interested in opcodes that have an associated name */ if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) { diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index cd6fae6ad4c2a02948e2fdd8790bcd7c41c39b84..3f9f286088fae68ba41ebceb74bbba7c4bd23ba8 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -201,7 +201,7 @@ static int ghes_estatus_pool_expand(unsigned long len) * New allocation must be visible in all pgd before it can be found by * an NMI allocating from the pool. */ - vmalloc_sync_all(); + vmalloc_sync_mappings(); return gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1); } diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index d21ee85ab260bad52f6bb7750d654b83dc3ee684..a75f4d9a2729d23c71d15940ae10d03ca48326e4 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -227,13 +227,13 @@ int acpi_device_set_power(struct acpi_device *device, int state) end: if (result) { dev_warn(&device->dev, "Failed to change power state to %s\n", - acpi_power_state_string(state)); + acpi_power_state_string(target_state)); } else { device->power.state = target_state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to %s\n", device->pnp.bus_id, - acpi_power_state_string(state))); + acpi_power_state_string(target_state))); } return result; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 7e91575496b6703939270362b57311a50370e399..1872dc01be132092c0e0a30582e291a2433563f7 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -214,7 +214,7 @@ static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd, if (call_pkg) { int i; - if (nfit_mem->family != call_pkg->nd_family) + if (nfit_mem && nfit_mem->family != call_pkg->nd_family) return -ENOTTY; for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++) @@ -223,6 +223,10 @@ static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd, return call_pkg->nd_command; } + /* In the !call_pkg case, bus commands == bus functions */ + if (!nfit_mem) + return cmd; + /* Linux ND commands == NVDIMM_FAMILY_INTEL function numbers */ if (nfit_mem->family == NVDIMM_FAMILY_INTEL) return cmd; @@ -238,6 +242,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) { struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); union acpi_object in_obj, in_buf, *out_obj; const struct nd_cmd_desc *desc = NULL; struct device *dev = acpi_desc->dev; @@ -252,18 +257,18 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, if (cmd_rc) *cmd_rc = -EINVAL; + if (cmd == ND_CMD_CALL) + call_pkg = buf; + func = cmd_to_func(nfit_mem, cmd, call_pkg); + if (func < 0) + return func; + if (nvdimm) { - struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); struct acpi_device *adev = nfit_mem->adev; if (!adev) return -ENOTTY; - if (cmd == ND_CMD_CALL) - call_pkg = buf; - func = cmd_to_func(nfit_mem, cmd, call_pkg); - if (func < 0) - return func; dimm_name = nvdimm_name(nvdimm); cmd_name = nvdimm_cmd_name(cmd); cmd_mask = nvdimm_cmd_mask(nvdimm); @@ -274,12 +279,9 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, } else { struct acpi_device *adev = to_acpi_dev(acpi_desc); - func = cmd; cmd_name = nvdimm_bus_cmd_name(cmd); cmd_mask = nd_desc->cmd_mask; - dsm_mask = cmd_mask; - if (cmd == ND_CMD_CALL) - dsm_mask = nd_desc->bus_dsm_mask; + dsm_mask = nd_desc->bus_dsm_mask; desc = nd_cmd_bus_desc(cmd); guid = to_nfit_uuid(NFIT_DEV_BUS); handle = adev->handle; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 7f9aff4b8d627db3accf80a12054b698887a314d..9fdc13a2f2d5986af51e73a22a72c1df67484ece 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -909,13 +909,6 @@ static long __acpi_processor_get_throttling(void *data) return pr->throttling.acpi_processor_get_throttling(pr); } -static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) -{ - if (direct || (is_percpu_thread() && cpu == smp_processor_id())) - return fn(arg); - return work_on_cpu(cpu, fn, arg); -} - static int acpi_processor_get_throttling(struct acpi_processor *pr) { if (!pr) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 43587ac680e472afe6ac5cbb0bbbfa3b0c9f93e7..214c4e2e8ade1db216621f9921e389ca50215df2 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -328,6 +328,11 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"), }, }, + + /* + * Desktops which falsely report a backlight and which our heuristics + * for this do not catch. + */ { .callback = video_detect_force_none, .ident = "Dell OptiPlex 9020M", @@ -336,6 +341,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"), }, }, + { + .callback = video_detect_force_none, + .ident = "MSI MS-7721", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MSI"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"), + }, + }, { }, }; diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 920b1ca35bf03f456781fc13ade77ac747122c46..7bd038edc1f77728e1cb800e706b5c1281ef9d10 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5192,6 +5192,7 @@ static int binder_open(struct inode *nodp, struct file *filp) binder_dev = container_of(filp->private_data, struct binder_device, miscdev); } + refcount_inc(&binder_dev->ref); proc->context = &binder_dev->context; binder_alloc_init(&proc->alloc); @@ -5369,6 +5370,7 @@ static int binder_node_release(struct binder_node *node, int refs) static void binder_deferred_release(struct binder_proc *proc) { struct binder_context *context = proc->context; + struct binder_device *device; struct rb_node *n; int threads, nodes, incoming_refs, outgoing_refs, active_transactions; @@ -5387,6 +5389,12 @@ static void binder_deferred_release(struct binder_proc *proc) context->binder_context_mgr_node = NULL; } mutex_unlock(&context->context_mgr_node_lock); + device = container_of(proc->context, struct binder_device, context); + if (refcount_dec_and_test(&device->ref)) { + kfree(context->name); + kfree(device); + } + proc->context = NULL; binder_inner_proc_lock(proc); /* * Make sure proc stays alive after we @@ -6058,6 +6066,7 @@ static int __init init_binder_device(const char *name) binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; binder_device->miscdev.name = name; + refcount_set(&binder_device->ref, 1); binder_device->context.binder_context_mgr_uid = INVALID_UID; binder_device->context.name = name; mutex_init(&binder_device->context.context_mgr_node_lock); diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index ad2d54d2023dcf110fe459df4f706910181abaf8..880affe45b07921297dc109cf99240b1fa6ddac2 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -922,8 +922,8 @@ enum lru_status binder_alloc_free_page(struct list_head *item, mm = alloc->vma_vm_mm; if (!mmget_not_zero(mm)) goto err_mmget; - if (!down_write_trylock(&mm->mmap_sem)) - goto err_down_write_mmap_sem_failed; + if (!down_read_trylock(&mm->mmap_sem)) + goto err_down_read_mmap_sem_failed; vma = binder_alloc_get_vma(alloc); list_lru_isolate(lru, item); @@ -936,7 +936,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item, trace_binder_unmap_user_end(alloc, index); } - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); trace_binder_unmap_kernel_start(alloc, index); @@ -950,7 +950,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item, mutex_unlock(&alloc->mutex); return LRU_REMOVED_RETRY; -err_down_write_mmap_sem_failed: +err_down_read_mmap_sem_failed: mmput_async(mm); err_mmget: err_page_already_freed: diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index bd47f7f72075a9676e84380d7c2f9f875878ebca..8d0bffcc9e271fd649a65a7e0df68eee1cd7bfcd 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ struct binder_device { struct miscdevice miscdev; struct binder_context context; struct inode *binderfs_inode; + refcount_t ref; }; /** diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index a4f73af4fa4e20be2a4b9c549de1ca80f7f17386..bfdbc9c640ff885a7ba035075c9dbc98f000869d 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -154,6 +154,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, if (!name) goto err; + refcount_set(&device->ref, 1); device->binderfs_inode = inode; device->context.binder_context_mgr_uid = INVALID_UID; device->context.name = name; @@ -257,8 +258,10 @@ static void binderfs_evict_inode(struct inode *inode) ida_remove(&binderfs_minors, device->miscdev.minor); mutex_unlock(&binderfs_minors_mutex); - kfree(device->context.name); - kfree(device); + if (refcount_dec_and_test(&device->ref)) { + kfree(device->context.name); + kfree(device); + } } /** @@ -445,6 +448,7 @@ static int binderfs_binder_ctl_create(struct super_block *sb) inode->i_uid = info->root_uid; inode->i_gid = info->root_gid; + refcount_set(&device->ref, 1); device->binderfs_inode = inode; device->miscdev.minor = minor; @@ -654,7 +658,7 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) int ret; struct binderfs_info *info; struct inode *inode = NULL; - struct binderfs_device device_info = { 0 }; + struct binderfs_device device_info = { { 0 } }; const char *name; size_t len; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f003e301723a4a21d8e3e479d7f2e37d64fa7899..0905c07b8c7eb2a690e37f48ef146a771257a1f7 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -88,6 +88,7 @@ enum board_ids { static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void ahci_remove_one(struct pci_dev *dev); +static void ahci_shutdown_one(struct pci_dev *dev); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, @@ -586,6 +587,7 @@ static struct pci_driver ahci_pci_driver = { .id_table = ahci_pci_tbl, .probe = ahci_init_one, .remove = ahci_remove_one, + .shutdown = ahci_shutdown_one, .driver = { .pm = &ahci_pci_pm_ops, }, @@ -1823,6 +1825,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; } +static void ahci_shutdown_one(struct pci_dev *pdev) +{ + ata_pci_shutdown_one(pdev); +} + static void ahci_remove_one(struct pci_dev *pdev) { pm_runtime_get_noresume(&pdev->dev); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 08f67c109429441e95ce639772b4532c902aa26d..33eb5e342a7a9293654859c33fcad0fc9f218a5f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6706,6 +6706,26 @@ void ata_pci_remove_one(struct pci_dev *pdev) ata_host_detach(host); } +void ata_pci_shutdown_one(struct pci_dev *pdev) +{ + struct ata_host *host = pci_get_drvdata(pdev); + int i; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + ap->pflags |= ATA_PFLAG_FROZEN; + + /* Disable port interrupts */ + if (ap->ops->freeze) + ap->ops->freeze(ap); + + /* Stop the port DMA engines */ + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + } +} + /* move to PCI subsystem */ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) { @@ -7326,6 +7346,7 @@ EXPORT_SYMBOL_GPL(ata_timing_cycle2mode); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); +EXPORT_SYMBOL_GPL(ata_pci_shutdown_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); #ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 85aa76116a305eb50d77f2544c87f09914998bed..7924d0635718dc0428f1679339e7f86aa3b18ee5 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -764,6 +764,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, if (dev->flags & ATA_DFLAG_DETACH) { detach = 1; + rc = -ENODEV; goto fail; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index eb0c4ee205258eeed13cda74931764f230b8a81f..2f81d65342709c8b75b5cbf37ced79d8f1bf6572 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4571,22 +4571,19 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) */ shost->max_host_blocked = 1; - rc = scsi_add_host_with_dma(ap->scsi_host, - &ap->tdev, ap->host->dev); + rc = scsi_add_host_with_dma(shost, &ap->tdev, ap->host->dev); if (rc) - goto err_add; + goto err_alloc; } return 0; - err_add: - scsi_host_put(host->ports[i]->scsi_host); err_alloc: while (--i >= 0) { struct Scsi_Host *shost = host->ports[i]->scsi_host; + /* scsi_host_put() is in ata_devres_release() */ scsi_remove_host(shost); - scsi_host_put(shost); } return rc; } diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index f8b7e86907cc2b088ff6453b26fedaf70d206daa..0a1ad1a1d34fbc85058e607867febab32e8d906e 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -1496,12 +1496,14 @@ fore200e_open(struct atm_vcc *vcc) static void fore200e_close(struct atm_vcc* vcc) { - struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e_vcc* fore200e_vcc; + struct fore200e* fore200e; struct fore200e_vc_map* vc_map; unsigned long flags; ASSERT(vcc); + fore200e = FORE200E_DEV(vcc->dev); + ASSERT((vcc->vpi >= 0) && (vcc->vpi < 1<vci >= 0) && (vcc->vci < 1<dev); - struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct fore200e* fore200e; + struct fore200e_vcc* fore200e_vcc; struct fore200e_vc_map* vc_map; - struct host_txq* txq = &fore200e->host_txq; + struct host_txq* txq; struct host_txq_entry* entry; struct tpd* tpd; struct tpd_haddr tpd_haddr; @@ -1562,9 +1564,18 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) unsigned char* data; unsigned long flags; - ASSERT(vcc); - ASSERT(fore200e); - ASSERT(fore200e_vcc); + if (!vcc) + return -EINVAL; + + fore200e = FORE200E_DEV(vcc->dev); + fore200e_vcc = FORE200E_VCC(vcc); + + if (!fore200e) + return -EINVAL; + + txq = &fore200e->host_txq; + if (!fore200e_vcc) + return -EINVAL; if (!test_bit(ATM_VF_READY, &vcc->flags)) { DPRINTK(1, "VC %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16f8f2626c9077dc468038ca42b7006763e7ae17..e80fd3da4e87940003b412e6594a64362fb6ace4 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -401,7 +401,10 @@ static int really_probe(struct device *dev, struct device_driver *drv) atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); - WARN_ON(!list_empty(&dev->devres_head)); + if (!list_empty(&dev->devres_head)) { + dev_crit(dev, "Resources present before probing\n"); + return -EBUSY; + } re_probe: dev->driver = drv; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f1105de0d9fed2d68c5d12ce0da8b5545c509418..bcb6519fe2113fd891e82e2b22feb3f0fa329d54 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -68,7 +69,7 @@ void __weak arch_setup_pdev_archdata(struct platform_device *pdev) struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) { - int i; + u32 i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; @@ -163,7 +164,7 @@ struct resource *platform_get_resource_byname(struct platform_device *dev, unsigned int type, const char *name) { - int i; + u32 i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; @@ -360,7 +361,8 @@ EXPORT_SYMBOL_GPL(platform_device_add_properties); */ int platform_device_add(struct platform_device *pdev) { - int i, ret; + u32 i; + int ret; if (!pdev) return -EINVAL; @@ -426,7 +428,7 @@ int platform_device_add(struct platform_device *pdev) pdev->id = PLATFORM_DEVID_AUTO; } - while (--i >= 0) { + while (i--) { struct resource *r = &pdev->resource[i]; if (r->parent) release_resource(r); @@ -447,7 +449,7 @@ EXPORT_SYMBOL_GPL(platform_device_add); */ void platform_device_del(struct platform_device *pdev) { - int i; + u32 i; if (pdev) { device_remove_properties(&pdev->dev); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c0ebee56cde48772ac6b6ecb927a0474c2c2f33f..f3b6afaf09c7237032f319463d13f58c8bf357d0 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -277,10 +277,38 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async) device_links_read_unlock(idx); } -static void dpm_wait_for_superior(struct device *dev, bool async) +static bool dpm_wait_for_superior(struct device *dev, bool async) { - dpm_wait(dev->parent, async); + struct device *parent; + + /* + * If the device is resumed asynchronously and the parent's callback + * deletes both the device and the parent itself, the parent object may + * be freed while this function is running, so avoid that by reference + * counting the parent once more unless the device has been deleted + * already (in which case return right away). + */ + mutex_lock(&dpm_list_mtx); + + if (!device_pm_initialized(dev)) { + mutex_unlock(&dpm_list_mtx); + return false; + } + + parent = get_device(dev->parent); + + mutex_unlock(&dpm_list_mtx); + + dpm_wait(parent, async); + put_device(parent); + dpm_wait_for_suppliers(dev, async); + + /* + * If the parent's callback has deleted the device, attempting to resume + * it would be invalid, so avoid doing that then. + */ + return device_pm_initialized(dev); } static void dpm_wait_for_consumers(struct device *dev, bool async) @@ -559,7 +587,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn if (!dev->power.is_noirq_suspended) goto Out; - dpm_wait_for_superior(dev, async); + if (!dpm_wait_for_superior(dev, async)) + goto Out; if (dev->pm_domain) { info = "noirq power domain "; @@ -699,7 +728,8 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn if (!dev->power.is_late_suspended) goto Out; - dpm_wait_for_superior(dev, async); + if (!dpm_wait_for_superior(dev, async)) + goto Out; if (dev->pm_domain) { info = "early power domain "; @@ -831,7 +861,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) goto Complete; } - dpm_wait_for_superior(dev, async); + if (!dpm_wait_for_superior(dev, async)) + goto Complete; + dpm_watchdog_set(&wd, dev); device_lock(dev); @@ -1141,10 +1173,13 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a } error = dpm_run_callback(callback, dev, state, info); - if (!error) + if (!error) { dev->power.is_noirq_suspended = true; - else + } else { async_error = error; + log_suspend_abort_reason("Callback failed on %s in %pS returned %d", + dev_name(dev), callback, error); + } Complete: complete_all(&dev->power.completion); @@ -1302,10 +1337,13 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as } error = dpm_run_callback(callback, dev, state, info); - if (!error) + if (!error) { dev->power.is_late_suspended = true; - else + } else { async_error = error; + log_suspend_abort_reason("Callback failed on %s in %pS returned %d", + dev_name(dev), callback, error); + } Complete: TRACE_SUSPEND(error); @@ -1463,7 +1501,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_callback_t callback = NULL; const char *info = NULL; int error = 0; - char suspend_abort[MAX_SUSPEND_ABORT_LEN]; DECLARE_DPM_WATCHDOG_ON_STACK(wd); TRACE_DEVICE(dev); @@ -1486,9 +1523,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_wakeup_event(dev, 0); if (pm_wakeup_pending()) { - pm_get_active_wakeup_sources(suspend_abort, - MAX_SUSPEND_ABORT_LEN); - log_suspend_abort_reason(suspend_abort); dev->power.direct_complete = false; async_error = -EBUSY; goto Complete; @@ -1567,7 +1601,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dev->power.is_suspended = true; if (parent) { spin_lock_irq(&parent->power.lock); - dev->parent->power.direct_complete = false; if (dev->power.wakeup_path && !dev->parent->power.ignore_children) @@ -1576,6 +1609,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) spin_unlock_irq(&parent->power.lock); } dpm_clear_suppliers_direct_complete(dev); + } else { + log_suspend_abort_reason("Callback failed on %s in %pS returned %d", + dev_name(dev), callback, error); } device_unlock(dev); @@ -1785,6 +1821,8 @@ int dpm_prepare(pm_message_t state) printk(KERN_INFO "PM: Device %s not prepared " "for power transition: code %d\n", dev_name(dev), error); + log_suspend_abort_reason("Device %s not prepared for power transition: code %d", + dev_name(dev), error); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 3ccbf5e0eefc2b42afb85d6823b4277d137b2e29..db2a02b8b54ab52b54fa3bc67f672fe3dcd7ec48 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -15,7 +15,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -929,6 +931,7 @@ bool pm_wakeup_pending(void) { unsigned long flags; bool ret = false; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; spin_lock_irqsave(&events_lock, flags); if (events_check_enabled) { @@ -941,8 +944,10 @@ bool pm_wakeup_pending(void) spin_unlock_irqrestore(&events_lock, flags); if (ret) { - pr_info("PM: Wakeup pending, aborting suspend\n"); - pm_print_active_wakeup_sources(); + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); + pr_info("PM: %s\n", suspend_abort); } return ret || atomic_read(&pm_abort_suspend) > 0; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 16965964873e9a8a26d43d907d282cc9cba09d1d..a34e36d3bc2737c73ef07df92238e2d959164d64 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -531,6 +531,25 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data) return kobj; } +static inline void brd_check_and_reset_par(void) +{ + if (unlikely(!max_part)) + max_part = 1; + + /* + * make sure 'max_part' can be divided exactly by (1U << MINORBITS), + * otherwise, it is possiable to get same dev_t when adding partitions. + */ + if ((1U << MINORBITS) % max_part != 0) + max_part = 1UL << fls(max_part); + + if (max_part > DISK_MAX_PARTS) { + pr_info("brd: max_part can't be larger than %d, reset max_part = %d.\n", + DISK_MAX_PARTS, DISK_MAX_PARTS); + max_part = DISK_MAX_PARTS; + } +} + static int __init brd_init(void) { struct brd_device *brd, *next; @@ -554,8 +573,7 @@ static int __init brd_init(void) if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) return -EIO; - if (unlikely(!max_part)) - max_part = 1; + brd_check_and_reset_par(); for (i = 0; i < rd_nr; i++) { brd = brd_alloc(i); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 5f1aa31972441a703b7411d704eb4ec6e616be96..cbf74731cfce633e369ffba343ea087df8d2a9f5 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -848,14 +848,17 @@ static void reset_fdc_info(int mode) /* selects the fdc and drive, and enables the fdc's input/dma. */ static void set_fdc(int drive) { + unsigned int new_fdc = fdc; + if (drive >= 0 && drive < N_DRIVE) { - fdc = FDC(drive); + new_fdc = FDC(drive); current_drive = drive; } - if (fdc != 1 && fdc != 0) { + if (new_fdc >= N_FDC) { pr_info("bad fdc value\n"); return; } + fdc = new_fdc; set_dor(fdc, ~0, 8); #if N_FDC > 1 set_dor(1 - fdc, ~8, 0); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 453e3728e65736e45604e8c68290aa387d9a2bff..39b119af65f72c57e90e30641dc9e8cb6a5c0da3 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -211,7 +211,8 @@ static void __loop_update_dio(struct loop_device *lo, bool dio) * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup * will get updated by ioctl(LOOP_GET_STATUS) */ - blk_mq_freeze_queue(lo->lo_queue); + if (lo->lo_state == Lo_bound) + blk_mq_freeze_queue(lo->lo_queue); lo->use_dio = use_dio; if (use_dio) { queue_flag_clear_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue); @@ -220,7 +221,8 @@ static void __loop_update_dio(struct loop_device *lo, bool dio) queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue); lo->lo_flags &= ~LO_FLAGS_DIRECT_IO; } - blk_mq_unfreeze_queue(lo->lo_queue); + if (lo->lo_state == Lo_bound) + blk_mq_unfreeze_queue(lo->lo_queue); } static int @@ -1378,16 +1380,16 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg) if (arg < 512 || arg > PAGE_SIZE || !is_power_of_2(arg)) return -EINVAL; - if (lo->lo_queue->limits.logical_block_size != arg) { - sync_blockdev(lo->lo_device); - kill_bdev(lo->lo_device); - } + if (lo->lo_queue->limits.logical_block_size == arg) + return 0; + + sync_blockdev(lo->lo_device); + kill_bdev(lo->lo_device); blk_mq_freeze_queue(lo->lo_queue); /* kill_bdev should have truncated all the pages */ - if (lo->lo_queue->limits.logical_block_size != arg && - lo->lo_device->bd_inode->i_mapping->nrpages) { + if (lo->lo_device->bd_inode->i_mapping->nrpages) { err = -EAGAIN; pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", __func__, lo->lo_number, lo->lo_file_name, @@ -1615,6 +1617,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, arg = (unsigned long) compat_ptr(arg); case LOOP_SET_FD: case LOOP_CHANGE_FD: + case LOOP_SET_BLOCK_SIZE: case LOOP_SET_DIRECT_IO: err = lo_ioctl(bdev, mode, cmd, arg); break; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 4c661ad91e7d32796592e8a159869a753c374971..8f56e6b2f114f17fb49d5824f22987097f7e0524 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1203,6 +1203,16 @@ static int nbd_start_device(struct nbd_device *nbd) args = kzalloc(sizeof(*args), GFP_KERNEL); if (!args) { sock_shutdown(nbd); + /* + * If num_connections is m (2 < m), + * and NO.1 ~ NO.n(1 < n < m) kzallocs are successful. + * But NO.(n + 1) failed. We still have n recv threads. + * So, add flush_workqueue here to prevent recv threads + * dropping the last config_refs and trying to destroy + * the workqueue from inside the workqueue. + */ + if (i) + flush_workqueue(nbd->recv_workq); return -ENOMEM; } sk_set_memalloc(config->socks[i]->sock->sk); diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index f01d4a8a783ace1d03157d64c419e289d62f8920..b12e373aa956ade22fbe12434469dcae998cc3ee 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -622,6 +622,7 @@ static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq) if (tag != -1U) { cmd = &nq->cmds[tag]; cmd->tag = tag; + cmd->error = BLK_STS_OK; cmd->nq = nq; if (nq->dev->irqmode == NULL_IRQ_TIMER) { hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, @@ -1399,6 +1400,7 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, cmd->timer.function = null_cmd_timer_expired; } cmd->rq = bd->rq; + cmd->error = BLK_STS_OK; cmd->nq = nq; blk_mq_start_request(bd->rq); @@ -1593,7 +1595,12 @@ static void null_nvm_unregister(struct nullb *nullb) {} static void null_del_dev(struct nullb *nullb) { - struct nullb_device *dev = nullb->dev; + struct nullb_device *dev; + + if (!nullb) + return; + + dev = nullb->dev; ida_simple_remove(&nullb_indexes, nullb->index); @@ -1919,6 +1926,7 @@ static int null_add_dev(struct nullb_device *dev) cleanup_queues(nullb); out_free_nullb: kfree(nullb); + dev->nullb = NULL; out: return rv; } diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index f2b1994d58a067e9b81bbd30af9327fcf7f601fe..557cf52f674b5e3ffbe723bf7acf8a6b8ca7a08a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3847,6 +3847,10 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev) cancel_work_sync(&rbd_dev->unlock_work); } +/* + * header_rwsem must not be held to avoid a deadlock with + * rbd_dev_refresh() when flushing notifies. + */ static void rbd_unregister_watch(struct rbd_device *rbd_dev) { WARN_ON(waitqueue_active(&rbd_dev->lock_waitq)); @@ -6044,9 +6048,10 @@ static int rbd_dev_header_name(struct rbd_device *rbd_dev) static void rbd_dev_image_release(struct rbd_device *rbd_dev) { - rbd_dev_unprobe(rbd_dev); if (rbd_dev->opts) rbd_unregister_watch(rbd_dev); + + rbd_dev_unprobe(rbd_dev); rbd_dev->image_format = 0; kfree(rbd_dev->spec->image_id); rbd_dev->spec->image_id = NULL; @@ -6057,6 +6062,9 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev) * device. If this image is the one being mapped (i.e., not a * parent), initiate a watch on its header object before using that * object to get detailed information about the rbd image. + * + * On success, returns with header_rwsem held for write if called + * with @depth == 0. */ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) { @@ -6087,9 +6095,12 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) } } + if (!depth) + down_write(&rbd_dev->header_rwsem); + ret = rbd_dev_header_info(rbd_dev); if (ret) - goto err_out_watch; + goto err_out_probe; /* * If this image is the one being mapped, we have pool name and @@ -6133,10 +6144,11 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) return 0; err_out_probe: - rbd_dev_unprobe(rbd_dev); -err_out_watch: + if (!depth) + up_write(&rbd_dev->header_rwsem); if (!depth) rbd_unregister_watch(rbd_dev); + rbd_dev_unprobe(rbd_dev); err_out_format: rbd_dev->image_format = 0; kfree(rbd_dev->spec->image_id); @@ -6194,12 +6206,9 @@ static ssize_t do_rbd_add(struct bus_type *bus, goto err_out_rbd_dev; } - down_write(&rbd_dev->header_rwsem); rc = rbd_dev_image_probe(rbd_dev, 0); - if (rc < 0) { - up_write(&rbd_dev->header_rwsem); + if (rc < 0) goto err_out_rbd_dev; - } /* If we are mapping a snapshot it must be marked read-only */ diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index db7b36fd8d8544eef9ffc735425b31aaf51630f3..763308990dd8119578267ec6160456d86b250033 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -15,7 +15,9 @@ #include #include #include +#ifdef CONFIG_PFK #include +#endif #include #define PART_BITS 4 @@ -364,10 +366,12 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); if (err) { virtqueue_kick(vblk->vqs[qid].vq); - blk_mq_stop_hw_queue(hctx); + /* Don't stop the queue if -ENOMEM: we may have failed to + * bounce the buffer due to global resource outage. + */ + if (err == -ENOSPC) + blk_mq_stop_hw_queue(hctx); spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); - /* Out of mem doesn't actually happen, since we fall back - * to direct descriptors */ if (err == -ENOMEM || err == -ENOSPC) return BLK_STS_RESOURCE; return BLK_STS_IOERR; diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index d675fd83476e00f5531110eb9d54a6b74539caf2..b074c9c15279fef28e2a571bb59ebcccd0b21a29 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -242,6 +242,64 @@ static int bt_clk_disable(struct bt_power_clk_data *clk) return rc; } +static int bt_configure_gpios_2wcn(int on) +{ + int rc = 0; + int bt_3p3_en_gpio = bt_power_pdata->bt_gpio_3p3_en; + int bt_1p3_en_gpio = bt_power_pdata->bt_gpio_1p3_en; + + BT_PWR_DBG("2wcn - bt_gpio= %d on: %d", bt_3p3_en_gpio, on); + + if (on) { + rc = gpio_request(bt_3p3_en_gpio, "bt_3p3_en_n"); + if (rc) { + BT_PWR_ERR("unable to request gpio %d (%d)\n", + bt_3p3_en_gpio, rc); + return rc; + } + + rc = gpio_direction_output(bt_3p3_en_gpio, 0); + if (rc) { + BT_PWR_ERR("Unable to set direction\n"); + return rc; + } + msleep(50); + rc = gpio_direction_output(bt_3p3_en_gpio, 1); + if (rc) { + BT_PWR_ERR("Unable to set direction\n"); + return rc; + } + msleep(50); + + rc = gpio_request(bt_1p3_en_gpio, "bt_1p3_en_n"); + if (rc) { + BT_PWR_ERR("unable to request gpio %d (%d)\n", + bt_1p3_en_gpio, rc); + return rc; + } + + rc = gpio_direction_output(bt_1p3_en_gpio, 0); + if (rc) { + BT_PWR_ERR("Unable to set direction\n"); + return rc; + } + msleep(50); + rc = gpio_direction_output(bt_1p3_en_gpio, 1); + if (rc) { + BT_PWR_ERR("Unable to set direction\n"); + return rc; + } + msleep(50); + } else { + gpio_set_value(bt_3p3_en_gpio, 0); + msleep(100); + gpio_set_value(bt_1p3_en_gpio, 0); + msleep(100); + } + return rc; +} + + static int bt_configure_gpios(int on) { int rc = 0; @@ -305,12 +363,27 @@ static int bluetooth_power(int on) goto gpio_fail; } } + if (bt_power_pdata->bt_gpio_3p3_en > 0) { + BT_PWR_ERR( + "bt_power gpio config start for 2wcn gpios"); + rc = bt_configure_gpios_2wcn(on); + if (rc < 0) { + BT_PWR_ERR("bt_power gpio config failed"); + goto gpio_fail; + } + } } else { if (bt_power_pdata->bt_gpio_sys_rst > 0) bt_configure_gpios(on); + if (bt_power_pdata->bt_gpio_3p3_en > 0) + bt_configure_gpios_2wcn(on); gpio_fail: if (bt_power_pdata->bt_gpio_sys_rst > 0) gpio_free(bt_power_pdata->bt_gpio_sys_rst); + if (bt_power_pdata->bt_gpio_3p3_en > 0) + gpio_free(bt_power_pdata->bt_gpio_3p3_en); + if (bt_power_pdata->bt_gpio_1p3_en > 0) + gpio_free(bt_power_pdata->bt_gpio_1p3_en); if (bt_power_pdata->bt_chip_clk) bt_clk_disable(bt_power_pdata->bt_chip_clk); clk_fail: @@ -584,6 +657,18 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) if (bt_power_pdata->bt_gpio_sys_rst < 0) BT_PWR_ERR("bt-reset-gpio not provided in device tree"); + bt_power_pdata->bt_gpio_3p3_en = + of_get_named_gpio(pdev->dev.of_node, + "qca,bt-3P3-en-gpio", 0); + if (bt_power_pdata->bt_gpio_3p3_en < 0) + BT_PWR_INFO("bt-3P3-gpio not provided in devicetree"); + + bt_power_pdata->bt_gpio_1p3_en = + of_get_named_gpio(pdev->dev.of_node, + "qca,bt-1P3-en-gpio", 0); + if (bt_power_pdata->bt_gpio_1p3_en < 0) + BT_PWR_INFO("bt-1P3-gpio not provided in devicetree"); + rc = bt_dt_parse_clk_info(&pdev->dev, &bt_power_pdata->bt_chip_clk); if (rc < 0) diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 26811368e6c3387f492db4f12d6b29b5d731fcd7..e0154b549b4f35466952eabfbdf10dc6a90f8f19 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -33,7 +33,7 @@ struct firmware_info { }; static const struct firmware_info firmware_table[] = { - {.dev_id = 0x308, .fw_image = "sdx65m/sbl1.mbn", + {.dev_id = 0x308, .fw_image = "sdx65m/xbl.elf", .edl_image = "sdx65m/edl.mbn"}, {.dev_id = 0x307, .fw_image = "sdx60m/sbl1.mbn", .edl_image = "sdx60m/edl.mbn"}, diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index d0245cb0147fabcb559ca96e464e537955450860..878c6bca461d26266faf06c984570694fe3de9e9 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1540,9 +1540,9 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker); init_waitqueue_head(&mhi_cntrl->state_event); - mhi_cntrl->special_wq = alloc_ordered_workqueue("mhi_special_w", + mhi_cntrl->wq = alloc_ordered_workqueue("mhi_w", WQ_MEM_RECLAIM | WQ_HIGHPRI); - if (!mhi_cntrl->special_wq) + if (!mhi_cntrl->wq) goto error_alloc_cmd; INIT_WORK(&mhi_cntrl->special_work, mhi_special_purpose_work); @@ -1668,7 +1668,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) error_alloc_dev: kfree(mhi_cntrl->mhi_cmd); - destroy_workqueue(mhi_cntrl->special_wq); + destroy_workqueue(mhi_cntrl->wq); error_alloc_cmd: vfree(mhi_cntrl->mhi_chan); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 4941151ef2692002c2ef280e51e7b0fa1248c937..0948c684b424020e8caec272368d7d756c8191e1 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1698,7 +1698,7 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev) MHI_VERB("Exit\n"); if (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) - queue_work(mhi_cntrl->special_wq, &mhi_cntrl->special_work); + queue_work(mhi_cntrl->wq, &mhi_cntrl->special_work); return IRQ_WAKE_THREAD; } @@ -1912,7 +1912,8 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, return 0; error_dec_pendpkt: - atomic_dec(&mhi_cntrl->pending_pkts); + if (in_mission_mode) + atomic_dec(&mhi_cntrl->pending_pkts); error_pm_state: if (!mhi_chan->offload_ch) mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); @@ -2603,6 +2604,7 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, ret = -EIO; goto error_invalid_state; } + read_unlock_bh(&mhi_cntrl->pm_lock); /* disable link level low power modes */ ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data); @@ -2625,6 +2627,7 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data); + read_lock_bh(&mhi_cntrl->pm_lock); error_invalid_state: mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); @@ -2695,8 +2698,11 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, tsync_node->cb_func = cb_func; tsync_node->mhi_dev = mhi_dev; - if (mhi_tsync->db_response_pending) + if (mhi_tsync->db_response_pending) { + mhi_device_put(mhi_cntrl->mhi_dev, + MHI_VOTE_DEVICE | MHI_VOTE_BUS); goto skip_tsync_db; + } mhi_tsync->int_sequence++; if (mhi_tsync->int_sequence == 0xFFFFFFFF) diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 550d0effa98d49ee83a5046d7825000a16a8b187..54fec3cd1056160a6f99f416385893af1c38532d 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -786,7 +786,7 @@ static int mhi_queue_disable_transition(struct mhi_controller *mhi_cntrl, list_add_tail(&item->node, &mhi_cntrl->transition_list); spin_unlock_irqrestore(&mhi_cntrl->transition_lock, flags); - schedule_work(&mhi_cntrl->st_worker); + queue_work(mhi_cntrl->wq, &mhi_cntrl->st_worker); return 0; } @@ -806,7 +806,7 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl, list_add_tail(&item->node, &mhi_cntrl->transition_list); spin_unlock_irqrestore(&mhi_cntrl->transition_lock, flags); - schedule_work(&mhi_cntrl->st_worker); + queue_work(mhi_cntrl->wq, &mhi_cntrl->st_worker); return 0; } @@ -822,8 +822,7 @@ static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl) spin_lock_bh(&mhi_event->lock); if (ev_ring->rp != mhi_to_virtual(ev_ring, er_ctxt->rp)) { - queue_work(mhi_cntrl->special_wq, - &mhi_cntrl->special_work); + queue_work(mhi_cntrl->wq, &mhi_cntrl->special_work); spin_unlock_bh(&mhi_event->lock); break; } diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 1b76d958590275daa6b9c2f8c69ecd2d51655da7..2ca2cc56bcef6f849c98d465a59e43ad62214a10 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -345,7 +345,7 @@ static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr, if (ret) goto unlock; - *buf = readl(rsb->regs + RSB_DATA); + *buf = readl(rsb->regs + RSB_DATA) & GENMASK(len * 8 - 1, 0); unlock: mutex_unlock(&rsb->lock); diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 8ed94351e897238c09a4da1a056d6fcc29a66829..d846f2cd1a6a49ff0fc1ab98e6709647d81c7cec 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -648,12 +648,20 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, static int dma_alloc_memory(dma_addr_t *region_phys, void **vaddr, size_t size, unsigned long dma_attr) { + int err = 0; struct fastrpc_apps *me = &gfa; if (me->dev == NULL) { pr_err("device adsprpc-mem is not initialized\n"); return -ENODEV; } + VERIFY(err, size > 0 && size < MAX_SIZE_LIMIT); + if (err) { + err = -EFAULT; + pr_err("adsprpc: %s: invalid allocation size 0x%zx\n", + __func__, size); + return err; + } *vaddr = dma_alloc_attrs(me->dev, size, region_phys, GFP_KERNEL, dma_attr); if (IS_ERR_OR_NULL(*vaddr)) { @@ -725,9 +733,11 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) } if (map->flags == ADSP_MMAP_HEAP_ADDR || map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + spin_lock(&me->hlock); map->refs--; if (!map->refs) hlist_del_init(&map->hn); + spin_unlock(&me->hlock); if (map->refs > 0) return; } else { @@ -1599,9 +1609,10 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) PERF_END); for (i = bufs; i < bufs + handles; ++i) { struct fastrpc_mmap *map = ctx->maps[i]; - - pages[i].addr = map->phys; - pages[i].size = map->size; + if (map) { + pages[i].addr = map->phys; + pages[i].size = map->size; + } } fdlist = (uint64_t *)&pages[bufs + handles]; for (i = 0; i < M_FDLIST; i++) @@ -1679,7 +1690,8 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) } PERF_END); for (i = bufs; rpra && lrpra && i < bufs + handles; i++) { - rpra[i].dma.fd = lrpra[i].dma.fd = ctx->fds[i]; + if (ctx->fds) + rpra[i].dma.fd = lrpra[i].dma.fd = ctx->fds[i]; rpra[i].dma.len = lrpra[i].dma.len = (uint32_t)lpra[i].buf.len; rpra[i].dma.offset = lrpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; @@ -3733,8 +3745,6 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, ctx->ssrcount++; ctx->issubsystemup = 0; mutex_unlock(&me->channel[cid].smd_mutex); - if (cid == 0) - me->staticpd_flags = 0; } else if (code == SUBSYS_RAMDUMP_NOTIFICATION) { if (me->channel[0].remoteheap_ramdump_dev && notifdata->enable_ramdump) { diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index 6910d5c810018fac62128193f84529d06ce4a5be..1d95dcb3fa1261d0efc8bca678da1137cf40fb9e 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -445,8 +445,7 @@ static ssize_t diag_dbgfs_read_usbinfo(struct file *file, char __user *ubuf, "write count: %lu\n" "read work pending: %d\n" "read done work pending: %d\n" - "connect work pending: %d\n" - "disconnect work pending: %d\n" + "event work pending: %d\n" "max size supported: %d\n\n", usb_info->id, usb_info->name, @@ -460,8 +459,7 @@ static ssize_t diag_dbgfs_read_usbinfo(struct file *file, char __user *ubuf, usb_info->write_cnt, work_pending(&usb_info->read_work), work_pending(&usb_info->read_done_work), - work_pending(&usb_info->connect_work), - work_pending(&usb_info->disconnect_work), + work_pending(&usb_info->event_work), usb_info->max_size); bytes_in_buffer += bytes_written; diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index 92c4fc187001c438555dd5024da57f9843e2f5d5..46e4c5692c1629837afd961c1402893e8b062096 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -94,7 +94,29 @@ struct diag_usb_info diag_usb[NUM_DIAG_USB_DEV] = { } #endif }; +static int diag_usb_event_add(struct diag_usb_info *usb_info, int data) +{ + struct diag_usb_event_q *entry = NULL; + + entry = kzalloc(sizeof(struct diag_usb_event_q), GFP_ATOMIC); + if (!entry) + return -ENOMEM; + + entry->data = data; + INIT_LIST_HEAD(&entry->link); + list_add_tail(&entry->link, &usb_info->event_q); + + return 0; +} +static void diag_usb_event_remove(struct diag_usb_event_q *entry) +{ + if (!entry) + return; + list_del(&entry->link); + kfree(entry); + entry = NULL; +} static int diag_usb_buf_tbl_add(struct diag_usb_info *usb_info, unsigned char *buf, uint32_t len, int ctxt) { @@ -202,25 +224,6 @@ static void usb_connect(struct diag_usb_info *ch) queue_work(ch->usb_wq, &(ch->read_work)); } -static void usb_connect_work_fn(struct work_struct *work) -{ - struct diag_usb_info *ch = container_of(work, struct diag_usb_info, - connect_work); - - wait_event_interruptible(ch->wait_q, ch->enabled > 0); - ch->max_size = usb_diag_request_size(ch->hdl); - atomic_set(&ch->connected, 1); - - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: USB channel %s: disconnected_status: %d, connected_status: %d\n", - ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected)); - - usb_connect(ch); - - if (atomic_read(&ch->disconnected)) - wake_up_interruptible(&ch->wait_q); -} - /* * This function is called asynchronously when USB is disconnected * and synchronously when Diag wants to disconnect from USB @@ -232,31 +235,63 @@ static void usb_disconnect(struct diag_usb_info *ch) ch->ops->close(ch->ctxt, DIAG_USB_MODE); } -static void usb_disconnect_work_fn(struct work_struct *work) +static void usb_event_work_fn(struct work_struct *work) { struct diag_usb_info *ch = container_of(work, struct diag_usb_info, - disconnect_work); + event_work); + struct diag_usb_event_q *entry = NULL; + unsigned long flags; if (!ch) return; + spin_lock_irqsave(&ch->event_lock, flags); + entry = list_first_entry(&(ch->event_q), struct diag_usb_event_q, link); + if (!entry) { + spin_unlock_irqrestore(&ch->event_lock, flags); + return; + } - atomic_set(&ch->disconnected, 1); - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: USB channel %s: disconnected_status: %d, connected_status: %d\n", - ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected)); + switch (entry->data) { + case USB_DIAG_CONNECT: - wait_event_interruptible(ch->wait_q, atomic_read(&ch->connected) > 0); - atomic_set(&ch->connected, 0); - atomic_set(&ch->disconnected, 0); - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: USB channel %s: Cleared disconnected(%d) and connected(%d) status\n", - ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected)); + diag_usb_event_remove(entry); + spin_unlock_irqrestore(&ch->event_lock, flags); + + wait_event_interruptible(ch->wait_q, ch->enabled > 0); + ch->max_size = usb_diag_request_size(ch->hdl); + atomic_set(&ch->connected, 1); + + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: USB channel %s: connected_status: %d\n", + ch->name, atomic_read(&ch->connected)); + + usb_connect(ch); + break; + case USB_DIAG_DISCONNECT: + + diag_usb_event_remove(entry); + spin_unlock_irqrestore(&ch->event_lock, flags); - if (!atomic_read(&ch->connected) && - driver->usb_connected && diag_mask_param()) - diag_clear_masks(0); + atomic_set(&ch->connected, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: USB channel %s: Cleared connected(%d) status\n", + ch->name, atomic_read(&ch->connected)); + + if (!atomic_read(&ch->connected) && + driver->usb_connected && + (ch->id == DIAG_USB_LOCAL) && diag_mask_param()) + diag_clear_masks(0); + + usb_disconnect(ch); + break; + default: + spin_unlock_irqrestore(&ch->event_lock, flags); + break; + } + + if (!list_empty(&ch->event_q)) + queue_work(ch->usb_wq, &(ch->event_work)); - usb_disconnect(ch); } static void usb_read_work_fn(struct work_struct *work) @@ -351,8 +386,7 @@ static void diag_usb_write_done(struct diag_usb_info *ch, spin_unlock_irqrestore(&ch->write_lock, flags); return; } - DIAG_LOG(DIAG_DEBUG_MUX, "full write_done, ctxt: %d\n", - ctxt); + DIAG_LOG(DIAG_DEBUG_MUX, "full write_done\n"); list_del(&entry->track); ctxt = entry->ctxt; buf = entry->buf; @@ -385,15 +419,20 @@ static void diag_usb_notifier(void *priv, unsigned int event, case USB_DIAG_CONNECT: pr_info("diag: USB channel %s: Received Connect event\n", usb_info->name); - if (!atomic_read(&usb_info->connected)) - queue_work(usb_info->usb_wq, - &usb_info->connect_work); + spin_lock_irqsave(&usb_info->event_lock, flags); + diag_usb_event_add(usb_info, USB_DIAG_CONNECT); + spin_unlock_irqrestore(&usb_info->event_lock, flags); + queue_work(usb_info->usb_wq, + &usb_info->event_work); break; case USB_DIAG_DISCONNECT: pr_info("diag: USB channel %s: Received Disconnect event\n", usb_info->name); + spin_lock_irqsave(&usb_info->event_lock, flags); + diag_usb_event_add(usb_info, USB_DIAG_DISCONNECT); + spin_unlock_irqrestore(&usb_info->event_lock, flags); queue_work(usb_info->usb_wq, - &usb_info->disconnect_work); + &usb_info->event_work); break; case USB_DIAG_READ_DONE: spin_lock_irqsave(&usb_info->lock, flags); @@ -664,6 +703,7 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops) ch->ctxt = ctxt; spin_lock_init(&ch->lock); spin_lock_init(&ch->write_lock); + spin_lock_init(&ch->event_lock); ch->read_buf = kzalloc(USB_MAX_OUT_BUF, GFP_KERNEL); if (!ch->read_buf) goto err; @@ -671,7 +711,6 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops) if (!ch->read_ptr) goto err; atomic_set(&ch->connected, 0); - atomic_set(&ch->disconnected, 0); atomic_set(&ch->read_pending, 0); /* * This function is called when the mux registers with Diag-USB. @@ -680,11 +719,11 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops) */ atomic_set(&ch->diag_state, 1); INIT_LIST_HEAD(&ch->buf_tbl); + INIT_LIST_HEAD(&ch->event_q); diagmem_init(driver, ch->mempool); INIT_WORK(&(ch->read_work), usb_read_work_fn); INIT_WORK(&(ch->read_done_work), usb_read_done_work_fn); - INIT_WORK(&(ch->connect_work), usb_connect_work_fn); - INIT_WORK(&(ch->disconnect_work), usb_disconnect_work_fn); + INIT_WORK(&(ch->event_work), usb_event_work_fn); init_waitqueue_head(&ch->wait_q); strlcpy(wq_name, "DIAG_USB_", sizeof(wq_name)); strlcat(wq_name, ch->name, sizeof(wq_name)); diff --git a/drivers/char/diag/diag_usb.h b/drivers/char/diag/diag_usb.h index 95ef5ed5877484fcceef76b50d9cf8b0afca36da..abebb0c309aa7e4eb889815ce373df30396c8cbe 100644 --- a/drivers/char/diag/diag_usb.h +++ b/drivers/char/diag/diag_usb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,11 @@ struct diag_usb_buf_tbl_t { int ctxt; }; +struct diag_usb_event_q { + struct list_head link; + int data; +}; + struct diag_usb_info { int id; int ctxt; @@ -53,7 +58,6 @@ struct diag_usb_info { atomic_t connected; atomic_t diag_state; atomic_t read_pending; - atomic_t disconnected; int enabled; int mempool; int max_size; @@ -62,16 +66,17 @@ struct diag_usb_info { unsigned long write_cnt; spinlock_t lock; spinlock_t write_lock; + spinlock_t event_lock; struct usb_diag_ch *hdl; struct diag_mux_ops *ops; unsigned char *read_buf; struct diag_request *read_ptr; struct work_struct read_work; struct work_struct read_done_work; - struct work_struct connect_work; - struct work_struct disconnect_work; + struct work_struct event_work; struct workqueue_struct *usb_wq; wait_queue_head_t wait_q; + struct list_head event_q; }; #ifdef CONFIG_DIAG_OVER_USB diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 4b1df988c527641e8d0e7e54b8594826b1a033f4..15801eb2d8aa60746ad66e6e96774b6b47dd222f 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -886,6 +886,9 @@ void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf, while (read_len + header_len < len) { ctrl_pkt = (struct diag_ctrl_pkt_header_t *)ptr; + if (((size_t)read_len + (size_t)ctrl_pkt->len + + header_len) > len) + return; switch (ctrl_pkt->pkt_id) { case DIAG_CTRL_MSG_REG: process_command_registration(ptr, ctrl_pkt->len, diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c index 88db42d30760645d84cd8e5f4ecd70f1239457b9..48194d1a607673c7605cbcf4e1d6f26f707a231e 100644 --- a/drivers/char/hw_random/imx-rngc.c +++ b/drivers/char/hw_random/imx-rngc.c @@ -110,8 +110,10 @@ static int imx_rngc_self_test(struct imx_rngc *rngc) return -ETIMEDOUT; } - if (rngc->err_reg != 0) + if (rngc->err_reg != 0) { + imx_rngc_irq_mask_clear(rngc); return -EIO; + } return 0; } diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c82d9fd2f05af6c787ab640a88dd4a7b47717381..f72a272eeb9b28ce13ef9f20f03a23baed15ecbe 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2647,7 +2647,9 @@ get_guid(ipmi_smi_t intf) if (rv) /* Send failed, no GUID available. */ intf->bmc->guid_set = 0; - wait_event(intf->waitq, intf->bmc->guid_set != 2); + else + wait_event(intf->waitq, intf->bmc->guid_set != 2); + intf->null_user_handler = NULL; } diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 941bffd9b49cd53791831fffe39ecc62b6fc62cc..0146bc3252c5abcd3853190b38609c8d37b5f631 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -750,10 +750,14 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, flags = ipmi_ssif_lock_cond(ssif_info, &oflags); msg = ssif_info->curr_msg; if (msg) { + if (data) { + if (len > IPMI_MAX_MSG_LENGTH) + len = IPMI_MAX_MSG_LENGTH; + memcpy(msg->rsp, data, len); + } else { + len = 0; + } msg->rsp_size = len; - if (msg->rsp_size > IPMI_MAX_MSG_LENGTH) - msg->rsp_size = IPMI_MAX_MSG_LENGTH; - memcpy(msg->rsp, data, msg->rsp_size); ssif_info->curr_msg = NULL; } diff --git a/drivers/char/random.c b/drivers/char/random.c index 07d7e0ec393b270707348e7965e37f653463c697..7ac94875300735d30378fee47c26299caa42f43b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2192,11 +2192,11 @@ struct batched_entropy { /* * Get a random word for internal kernel use only. The quality of the random - * number is either as good as RDRAND or as good as /dev/urandom, with the - * goal of being quite fast and not depleting entropy. In order to ensure + * number is good as /dev/urandom, but there is no backtrack protection, with + * the goal of being quite fast and not depleting entropy. In order to ensure * that the randomness provided by this function is okay, the function - * wait_for_random_bytes() should be called and return 0 at least once - * at any point prior. + * wait_for_random_bytes() should be called and return 0 at least once at any + * point prior. */ static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = { .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock), @@ -2209,15 +2209,6 @@ u64 get_random_u64(void) struct batched_entropy *batch; static void *previous; -#if BITS_PER_LONG == 64 - if (arch_get_random_long((unsigned long *)&ret)) - return ret; -#else - if (arch_get_random_long((unsigned long *)&ret) && - arch_get_random_long((unsigned long *)&ret + 1)) - return ret; -#endif - warn_unseeded_randomness(&previous); batch = raw_cpu_ptr(&batched_entropy_u64); @@ -2242,9 +2233,6 @@ u32 get_random_u32(void) struct batched_entropy *batch; static void *previous; - if (arch_get_random_int(&ret)) - return ret; - warn_unseeded_randomness(&previous); batch = raw_cpu_ptr(&batched_entropy_u32); diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 77e47dc5aacc5705b465583d2c02f26f8b393d56..569e93e1f06ccdc978d30ee6035aa850dc2f5e72 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 IBM Corporation + * Copyright (C) 2012-2020 IBM Corporation * * Author: Ashley Lai * @@ -140,6 +140,64 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) return len; } +/** + * ibmvtpm_crq_send_init - Send a CRQ initialize message + * @ibmvtpm: vtpm device struct + * + * Return: + * 0 on success. + * Non-zero on failure. + */ +static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) +{ + int rc; + + rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD); + if (rc != H_SUCCESS) + dev_err(ibmvtpm->dev, + "%s failed rc=%d\n", __func__, rc); + + return rc; +} + +/** + * tpm_ibmvtpm_resume - Resume from suspend + * + * @dev: device struct + * + * Return: Always 0. + */ +static int tpm_ibmvtpm_resume(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); + int rc = 0; + + do { + if (rc) + msleep(100); + rc = plpar_hcall_norets(H_ENABLE_CRQ, + ibmvtpm->vdev->unit_address); + } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); + + if (rc) { + dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc); + return rc; + } + + rc = vio_enable_interrupts(ibmvtpm->vdev); + if (rc) { + dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc); + return rc; + } + + rc = ibmvtpm_crq_send_init(ibmvtpm); + if (rc) + dev_err(dev, "Error send_init rc=%d\n", rc); + + return rc; +} + /** * tpm_ibmvtpm_send() - Send a TPM command * @chip: tpm chip struct @@ -153,6 +211,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); + bool retry = true; int rc, sig; if (!ibmvtpm->rtce_buf) { @@ -186,18 +245,27 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) */ ibmvtpm->tpm_processing_cmd = true; +again: rc = ibmvtpm_send_crq(ibmvtpm->vdev, IBMVTPM_VALID_CMD, VTPM_TPM_COMMAND, count, ibmvtpm->rtce_dma_handle); if (rc != H_SUCCESS) { + /* + * H_CLOSED can be returned after LPM resume. Call + * tpm_ibmvtpm_resume() to re-enable the CRQ then retry + * ibmvtpm_send_crq() once before failing. + */ + if (rc == H_CLOSED && retry) { + tpm_ibmvtpm_resume(ibmvtpm->dev); + retry = false; + goto again; + } dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); - rc = 0; ibmvtpm->tpm_processing_cmd = false; - } else - rc = 0; + } spin_unlock(&ibmvtpm->rtce_lock); - return rc; + return 0; } static void tpm_ibmvtpm_cancel(struct tpm_chip *chip) @@ -275,26 +343,6 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) return rc; } -/** - * ibmvtpm_crq_send_init - Send a CRQ initialize message - * @ibmvtpm: vtpm device struct - * - * Return: - * 0 on success. - * Non-zero on failure. - */ -static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) -{ - int rc; - - rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD); - if (rc != H_SUCCESS) - dev_err(ibmvtpm->dev, - "ibmvtpm_crq_send_init failed rc=%d\n", rc); - - return rc; -} - /** * tpm_ibmvtpm_remove - ibm vtpm remove entry point * @vdev: vio device struct @@ -407,44 +455,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); } -/** - * tpm_ibmvtpm_resume - Resume from suspend - * - * @dev: device struct - * - * Return: Always 0. - */ -static int tpm_ibmvtpm_resume(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); - int rc = 0; - - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_ENABLE_CRQ, - ibmvtpm->vdev->unit_address); - } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); - - if (rc) { - dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc); - return rc; - } - - rc = vio_enable_interrupts(ibmvtpm->vdev); - if (rc) { - dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc); - return rc; - } - - rc = ibmvtpm_crq_send_init(ibmvtpm); - if (rc) - dev_err(dev, "Error send_init rc=%d\n", rc); - - return rc; -} - static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status) { return (status == 0); diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index a7d9c0c53fcd0976e2870347ba69b4f82b602eb9..9b1116501f209fe19220d81d0a04080e47a51266 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -331,6 +331,9 @@ static void disable_interrupts(struct tpm_chip *chip) u32 intmask; int rc; + if (priv->irq == 0) + return; + rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); if (rc < 0) intmask = 0; @@ -874,9 +877,12 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, if (irq) { tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, irq); - if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) + if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { dev_err(&chip->dev, FW_BUG "TPM interrupt not working, polling instead\n"); + + disable_interrupts(chip); + } } else { tpm_tis_probe_irq(chip, intmask); } diff --git a/drivers/char/virtio_fastrpc.c b/drivers/char/virtio_fastrpc.c index 845acd8c1d6cfb3f3a83058194bb510ab3135ee1..5d9e6ce6f695c71ad227b584c02c6ac3ca2b8ceb 100644 --- a/drivers/char/virtio_fastrpc.c +++ b/drivers/char/virtio_fastrpc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -512,6 +513,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, struct fastrpc_apps *me = &gfa; struct fastrpc_mmap *map = NULL; int err = 0, sgl_index = 0; + unsigned long flags; struct scatterlist *sgl = NULL; map = kzalloc(sizeof(*map), GFP_KERNEL); @@ -535,12 +537,21 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, dev_err(me->dev, "can't get dma buf fd %d\n", fd); goto bail; } + VERIFY(err, !dma_buf_get_flags(map->buf, &flags)); + if (err) { + dev_err(me->dev, "can't get dma buf flags %d\n", fd); + goto bail; + } + VERIFY(err, !IS_ERR_OR_NULL(map->attach = dma_buf_attach(map->buf, me->dev))); if (err) { dev_err(me->dev, "can't attach dma buf\n"); goto bail; } + + if (!(flags & ION_FLAG_CACHED)) + map->attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; VERIFY(err, !IS_ERR_OR_NULL(map->table = dma_buf_map_attachment(map->attach, DMA_BIDIRECTIONAL))); diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 791770a563fcce83d5538a52b5cc86bcc7a925c7..6fac6383d024ea7ff88b58f1cbf22225af6c3692 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -78,6 +78,9 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, tmp_parent_rate = req->rate * div; tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate); + if (!tmp_parent_rate) + continue; + tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); if (tmp_rate < req->rate) tmp_diff = req->rate - tmp_rate; diff --git a/drivers/clk/qcom/gcc-qcs405.c b/drivers/clk/qcom/gcc-qcs405.c index 081df4a32e5bad3eb31b55162ee12bdab42625f9..da0fc7d409d0995273c14eea76436c68cdec2787 100644 --- a/drivers/clk/qcom/gcc-qcs405.c +++ b/drivers/clk/qcom/gcc-qcs405.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -853,7 +853,9 @@ static struct clk_rcg2 byte0_clk_src = { }; static const struct freq_tbl ftbl_emac_clk_src[] = { + F(2500000, P_GPLL1_OUT_MAIN, 4, 1, 50), F(5000000, P_GPLL1_OUT_MAIN, 2, 1, 50), + F(25000000, P_GPLL1_OUT_MAIN, 1, 1, 20), F(50000000, P_GPLL1_OUT_MAIN, 10, 0, 0), F(125000000, P_GPLL1_OUT_MAIN, 4, 0, 0), F(250000000, P_GPLL1_OUT_MAIN, 2, 0, 0), diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 89fc5824c85d199881c6a28828a6c75f0ce9199f..f689661cfc3d2e6b5b46de03749e405e11bb6e9e 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -88,6 +88,7 @@ struct gdsc { int reset_count; int root_clk_idx; u32 gds_timeout; + bool skip_disable_before_enable; }; enum gdscr_status { @@ -166,6 +167,9 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) if (!sc->toggle_logic) return !sc->resets_asserted; + if (sc->skip_disable_before_enable) + return false; + if (sc->parent_regulator) { /* * The parent regulator for the GDSC is required to be on to @@ -258,6 +262,9 @@ static int gdsc_enable(struct regulator_dev *rdev) uint32_t regval, hw_ctrl_regval = 0x0; int i, ret = 0; + if (sc->skip_disable_before_enable) + return 0; + if (sc->parent_regulator) { ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); @@ -423,6 +430,8 @@ static int gdsc_enable(struct regulator_dev *rdev) sc->is_bus_enabled = false; } + sc->skip_disable_before_enable = false; + if (ret && sc->parent_regulator) regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); @@ -994,6 +1003,9 @@ static int gdsc_probe(struct platform_device *pdev) clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH); } + sc->skip_disable_before_enable = of_property_read_bool( + pdev->dev.of_node, "qcom,skip-disable-before-sw-enable"); + reg_config.dev = &pdev->dev; reg_config.init_data = init_data; reg_config.driver_data = sc; diff --git a/drivers/clk/qcom/npucc-atoll.c b/drivers/clk/qcom/npucc-atoll.c index b2be104de7f6977fdc982ac0781c759bf0e3f53a..a58d96d0c017a419f1f38426a7b08e3d117fe91c 100644 --- a/drivers/clk/qcom/npucc-atoll.c +++ b/drivers/clk/qcom/npucc-atoll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -357,13 +357,13 @@ static struct clk_rcg2 npu_cc_core_clk_src = { }; static const struct freq_tbl ftbl_npu_dsp_core_clk_src[] = { - F(250000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(300000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(400000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(500000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(600000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(660000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(800000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), + F(250000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(300000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(400000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(500000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(600000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(660000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(800000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), { } }; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index eaafc038368f57c8368f86ade2a488def08fe9f9..183985c8c9babfb12afa93587ddbf45534665ffc 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -884,11 +884,26 @@ static const struct sunxi_ccu_desc sun50i_a64_ccu_desc = { .num_resets = ARRAY_SIZE(sun50i_a64_ccu_resets), }; +static struct ccu_pll_nb sun50i_a64_pll_cpu_nb = { + .common = &pll_cpux_clk.common, + /* copy from pll_cpux_clk */ + .enable = BIT(31), + .lock = BIT(28), +}; + +static struct ccu_mux_nb sun50i_a64_cpu_nb = { + .common = &cpux_clk.common, + .cm = &cpux_clk.mux, + .delay_us = 1, /* > 8 clock cycles at 24 MHz */ + .bypass_index = 1, /* index of 24 MHz oscillator */ +}; + static int sun50i_a64_ccu_probe(struct platform_device *pdev) { struct resource *res; void __iomem *reg; u32 val; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg = devm_ioremap_resource(&pdev->dev, res); @@ -902,7 +917,18 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev) writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); - return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); + ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); + if (ret) + return ret; + + /* Gate then ungate PLL CPU after any rate changes */ + ccu_pll_notifier_register(&sun50i_a64_pll_cpu_nb); + + /* Reparent CPU during PLL CPU rate changes */ + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, + &sun50i_a64_cpu_nb); + + return 0; } static const struct of_device_id sun50i_a64_ccu_ids[] = { diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 848255cc0209911ec5781ceb2d09107244bcf659..d300a256fcacb8e8be3de7d5498373d8dab7b1f9 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -825,7 +825,11 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("vcp", "clk_m", 29, 0, tegra_clk_vcp, 0), GATE("apbdma", "clk_m", 34, 0, tegra_clk_apbdma, 0), GATE("kbc", "clk_32k", 36, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_kbc, 0), - GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, 0), + /* + * Critical for RAM re-repair operation, which must occur on resume + * from LP1 system suspend and as part of CCPLEX cluster switching. + */ + GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, CLK_IS_CRITICAL), GATE("fuse_burn", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse_burn, 0), GATE("kfuse", "clk_m", 40, TEGRA_PERIPH_ON_APB, tegra_clk_kfuse, 0), GATE("apbif", "clk_m", 107, TEGRA_PERIPH_ON_APB, tegra_clk_apbif, 0), diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c index a35579a3f884fbd3fa920e6d30950144c385c3f2..476dab494c44d3d5ea802ea863281fe585ae6edc 100644 --- a/drivers/clk/tegra/clk-tegra-pmc.c +++ b/drivers/clk/tegra/clk-tegra-pmc.c @@ -60,16 +60,16 @@ struct pmc_clk_init_data { static DEFINE_SPINLOCK(clk_out_lock); -static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern1", +static const char *clk_out1_parents[] = { "osc", "osc_div2", + "osc_div4", "extern1", }; -static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern2", +static const char *clk_out2_parents[] = { "osc", "osc_div2", + "osc_div4", "extern2", }; -static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern3", +static const char *clk_out3_parents[] = { "osc", "osc_div2", + "osc_div4", "extern3", }; static struct pmc_clk_init_data pmc_clks[] = { diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 39e489a96ad74f0f8e341aa2b3f9c8e6acfc4bfe..8894cfc32be06b62f0c0d1eaff4f2632d6ffd89f 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -134,7 +134,7 @@ static int __init bcm2835_timer_init(struct device_node *node) ret = setup_irq(irq, &timer->act); if (ret) { pr_err("Can't set up timer IRQ\n"); - goto err_iounmap; + goto err_timer_free; } clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff); @@ -143,6 +143,9 @@ static int __init bcm2835_timer_init(struct device_node *node) return 0; +err_timer_free: + kfree(timer); + err_iounmap: iounmap(base); return ret; diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 33854bf127f92bce16e0573ec3b5c1dba8709c20..25c9a6cdd8614503eb8a47fde088b86c96f6402f 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -1041,6 +1041,12 @@ static int init_chip_info(void) static inline void clean_chip_info(void) { + int i; + + /* flush any pending work items */ + if (chips) + for (i = 0; i < nr_chips; i++) + cancel_work_sync(&chips[i].throttle); kfree(chips); } diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 8964462d5e17a2936c2f3e5d97680c82eaf47310..b2c958a79eaa3bac09ed4131dd9ad2304cdc3bb0 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1234,7 +1234,8 @@ static void cluster_prepare(struct lpm_cluster *cluster, if (cluster_configure(cluster, i, from_idle, predicted)) goto failed; - cluster->stats->sleep_time = start_time; + if (!IS_ERR_OR_NULL(cluster->stats)) + cluster->stats->sleep_time = start_time; cluster_prepare(cluster->parent, &cluster->num_children_in_sync, i, from_idle, start_time); @@ -1242,7 +1243,8 @@ static void cluster_prepare(struct lpm_cluster *cluster, return; failed: spin_unlock(&cluster->sync_lock); - cluster->stats->sleep_time = 0; + if (!IS_ERR_OR_NULL(cluster->stats)) + cluster->stats->sleep_time = 0; } static void cluster_unprepare(struct lpm_cluster *cluster, @@ -1281,7 +1283,7 @@ static void cluster_unprepare(struct lpm_cluster *cluster, if (!first_cpu || cluster->last_level == cluster->default_level) goto unlock_return; - if (cluster->stats->sleep_time) + if (!IS_ERR_OR_NULL(cluster->stats) && cluster->stats->sleep_time) cluster->stats->sleep_time = end_time - cluster->stats->sleep_time; lpm_stats_cluster_exit(cluster->stats, cluster->last_level, success); @@ -1723,6 +1725,9 @@ static void register_cluster_lpm_stats(struct lpm_cluster *cl, cl->stats = lpm_stats_config_level(cl->cluster_name, level_name, cl->nlevels, parent ? parent->stats : NULL, NULL); + if (IS_ERR_OR_NULL(cl->stats)) + pr_info("Cluster (%s) stats not registered\n", + cl->cluster_name); kfree(level_name); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 113cd787ec7caec3abbf7c449bafc87ea1984e91..26e1103e49a6a0b51a43ee5bdb5deadea90bf10a 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -771,8 +771,4 @@ config CRYPTO_DEV_ARTPEC6 To compile this driver as a module, choose M here. -if ARCH_QCOM -source drivers/crypto/msm/Kconfig -endif - endif # CRYPTO_HW diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 11129b796ddaf0f41df8afcbd7c047cd19d2bb7e..b8153142bcc6723c591b11f425a52fe995b2fd6a 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -91,7 +91,6 @@ struct atmel_aes_caps { bool has_dualbuff; bool has_cfb64; - bool has_ctr32; bool has_gcm; bool has_xts; bool has_authenc; @@ -990,8 +989,9 @@ static int atmel_aes_ctr_transfer(struct atmel_aes_dev *dd) struct atmel_aes_ctr_ctx *ctx = atmel_aes_ctr_ctx_cast(dd->ctx); struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq); struct scatterlist *src, *dst; - u32 ctr, blocks; size_t datalen; + u32 ctr; + u16 blocks, start, end; bool use_dma, fragmented = false; /* Check for transfer completion. */ @@ -1003,27 +1003,17 @@ static int atmel_aes_ctr_transfer(struct atmel_aes_dev *dd) datalen = req->nbytes - ctx->offset; blocks = DIV_ROUND_UP(datalen, AES_BLOCK_SIZE); ctr = be32_to_cpu(ctx->iv[3]); - if (dd->caps.has_ctr32) { - /* Check 32bit counter overflow. */ - u32 start = ctr; - u32 end = start + blocks - 1; - - if (end < start) { - ctr |= 0xffffffff; - datalen = AES_BLOCK_SIZE * -start; - fragmented = true; - } - } else { - /* Check 16bit counter overflow. */ - u16 start = ctr & 0xffff; - u16 end = start + (u16)blocks - 1; - - if (blocks >> 16 || end < start) { - ctr |= 0xffff; - datalen = AES_BLOCK_SIZE * (0x10000-start); - fragmented = true; - } + + /* Check 16bit counter overflow. */ + start = ctr & 0xffff; + end = start + blocks - 1; + + if (blocks >> 16 || end < start) { + ctr |= 0xffff; + datalen = AES_BLOCK_SIZE * (0x10000 - start); + fragmented = true; } + use_dma = (datalen >= ATMEL_AES_DMA_THRESHOLD); /* Jump to offset. */ @@ -2536,7 +2526,6 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) { dd->caps.has_dualbuff = 0; dd->caps.has_cfb64 = 0; - dd->caps.has_ctr32 = 0; dd->caps.has_gcm = 0; dd->caps.has_xts = 0; dd->caps.has_authenc = 0; @@ -2547,7 +2536,6 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) case 0x500: dd->caps.has_dualbuff = 1; dd->caps.has_cfb64 = 1; - dd->caps.has_ctr32 = 1; dd->caps.has_gcm = 1; dd->caps.has_xts = 1; dd->caps.has_authenc = 1; @@ -2556,7 +2544,6 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) case 0x200: dd->caps.has_dualbuff = 1; dd->caps.has_cfb64 = 1; - dd->caps.has_ctr32 = 1; dd->caps.has_gcm = 1; dd->caps.max_burst_size = 4; break; diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 3e2f41b3eaf3afb08f75097d735a1d48e27f3305..15e68774034ae6518c282d5766eba620e5b6a0f7 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1921,12 +1921,7 @@ static int atmel_sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, { struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); - if (atmel_sha_hmac_key_set(&hmac->hkey, key, keylen)) { - crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return 0; + return atmel_sha_hmac_key_set(&hmac->hkey, key, keylen); } static int atmel_sha_hmac_init(struct ahash_request *req) diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 9f82e14983f65677b02fc56df85d5f4fb28a0e34..a886245b931e6596b65d04db72761f71d5e39537 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -1256,7 +1256,7 @@ static int artpec6_crypto_aead_set_key(struct crypto_aead *tfm, const u8 *key, if (len != 16 && len != 24 && len != 32) { crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -1; + return -EINVAL; } ctx->key_length = len; diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index b23c7b72525c0f64d1a23dcb3717e874b4b627f3..a3d507fb9ea5ab4324b757bcb1015cb88f88d668 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -1280,7 +1280,13 @@ EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_givencap); */ void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata) { - __be64 sector_size = cpu_to_be64(512); + /* + * Set sector size to a big value, practically disabling + * sector size segmentation in xts implementation. We cannot + * take full advantage of this HW feature with existing + * crypto API / dm-crypt SW architecture. + */ + __be64 sector_size = cpu_to_be64(BIT(15)); u32 *key_jump_cmd; init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); @@ -1332,7 +1338,13 @@ EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_encap); */ void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) { - __be64 sector_size = cpu_to_be64(512); + /* + * Set sector size to a big value, practically disabling + * sector size segmentation in xts implementation. We cannot + * take full advantage of this HW feature with existing + * crypto API / dm-crypt SW architecture. + */ + __be64 sector_size = cpu_to_be64(BIT(15)); u32 *key_jump_cmd; init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 240bebbcb8ac7c52eb7dfa2b93a00b5b9cb53cc9..ae0cc0a4dc5c76e70fe9d7c5e82a46c2cea62def 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -590,6 +590,7 @@ const struct ccp_vdata ccpv3_platform = { .setup = NULL, .perform = &ccp3_actions, .offset = 0, + .rsamax = CCP_RSA_MAX_WIDTH, }; const struct ccp_vdata ccpv3 = { diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index fd34c0bc39f5a920023d8540a71474cab5127c90..79301bbed9694d8127cf300a39a4c2fcc98bdf2a 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1443,9 +1443,9 @@ static void qcom_ice_debug(struct platform_device *pdev) qcom_ice_dump_test_bus(ice_dev); pr_err("%s: ICE reset start time: %llu ICE reset done time: %llu\n", - ice_dev->ice_instance_type, - (unsigned long long)ice_dev->ice_reset_start_time, - (unsigned long long)ice_dev->ice_reset_complete_time); + ice_dev->ice_instance_type, + (unsigned long long)ice_dev->ice_reset_start_time.tv64, + (unsigned long long)ice_dev->ice_reset_complete_time.tv64); if (ktime_to_us(ktime_sub(ice_dev->ice_reset_complete_time, ice_dev->ice_reset_start_time)) > 0) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index e1e1e81107904f5304cff08956c1a0935a2edb4c..eb569cf0630955f4dfa378fc3927b2a1d788c44e 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -25,6 +25,7 @@ #include #include #include +#include #define DCP_MAX_CHANS 4 #define DCP_BUF_SZ PAGE_SIZE @@ -36,11 +37,11 @@ * Null hashes to align with hw behavior on imx6sl and ull * these are flipped for consistency with hw output */ -const uint8_t sha1_null_hash[] = +static const uint8_t sha1_null_hash[] = "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf" "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda"; -const uint8_t sha256_null_hash[] = +static const uint8_t sha256_null_hash[] = "\x55\xb8\x52\x78\x1b\x99\x95\xa4" "\x4c\x93\x9b\x64\xe4\x41\xae\x27" "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a" @@ -621,49 +622,46 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); struct hash_alg_common *halg = crypto_hash_alg_common(tfm); - const int nents = sg_nents(req->src); uint8_t *in_buf = sdcp->coh->sha_in_buf; uint8_t *out_buf = sdcp->coh->sha_out_buf; - uint8_t *src_buf; - struct scatterlist *src; - unsigned int i, len, clen; + unsigned int i, len, clen, oft = 0; int ret; int fin = rctx->fini; if (fin) rctx->fini = 0; - for_each_sg(req->src, src, nents, i) { - src_buf = sg_virt(src); - len = sg_dma_len(src); - - do { - if (actx->fill + len > DCP_BUF_SZ) - clen = DCP_BUF_SZ - actx->fill; - else - clen = len; - - memcpy(in_buf + actx->fill, src_buf, clen); - len -= clen; - src_buf += clen; - actx->fill += clen; + src = req->src; + len = req->nbytes; - /* - * If we filled the buffer and still have some - * more data, submit the buffer. - */ - if (len && actx->fill == DCP_BUF_SZ) { - ret = mxs_dcp_run_sha(req); - if (ret) - return ret; - actx->fill = 0; - rctx->init = 0; - } - } while (len); + while (len) { + if (actx->fill + len > DCP_BUF_SZ) + clen = DCP_BUF_SZ - actx->fill; + else + clen = len; + + scatterwalk_map_and_copy(in_buf + actx->fill, src, oft, clen, + 0); + + len -= clen; + oft += clen; + actx->fill += clen; + + /* + * If we filled the buffer and still have some + * more data, submit the buffer. + */ + if (len && actx->fill == DCP_BUF_SZ) { + ret = mxs_dcp_run_sha(req); + if (ret) + return ret; + actx->fill = 0; + rctx->init = 0; + } } if (fin) { diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index b6f14844702e0c866037c0079539fdfc09be9753..7eaeb8507e06f24d7a63f6a657e2c931fc8b0359 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -1616,6 +1616,11 @@ static const struct of_device_id spacc_of_id_table[] = { MODULE_DEVICE_TABLE(of, spacc_of_id_table); #endif /* CONFIG_OF */ +static void spacc_tasklet_kill(void *data) +{ + tasklet_kill(data); +} + static int spacc_probe(struct platform_device *pdev) { int i, err, ret = -EINVAL; @@ -1659,6 +1664,14 @@ static int spacc_probe(struct platform_device *pdev) return -ENXIO; } + tasklet_init(&engine->complete, spacc_spacc_complete, + (unsigned long)engine); + + ret = devm_add_action(&pdev->dev, spacc_tasklet_kill, + &engine->complete); + if (ret) + return ret; + if (devm_request_irq(&pdev->dev, irq->start, spacc_spacc_irq, 0, engine->name, engine)) { dev_err(engine->dev, "failed to request IRQ\n"); @@ -1721,8 +1734,6 @@ static int spacc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&engine->completed); INIT_LIST_HEAD(&engine->in_progress); engine->in_flight = 0; - tasklet_init(&engine->complete, spacc_spacc_complete, - (unsigned long)engine); platform_set_drvdata(pdev, engine); diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 70d8bcb2a93e8d2473d74529e0f815077cfa913c..813417c57703a59f1c6369fa49c58f9b0aebf464 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -203,7 +203,8 @@ config ARM_TEGRA_DEVFREQ config ARM_RK3399_DMC_DEVFREQ tristate "ARM RK3399 DMC DEVFREQ Driver" - depends on ARCH_ROCKCHIP + depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \ + (COMPILE_TEST && HAVE_ARM_SMCCC) select DEVFREQ_EVENT_ROCKCHIP_DFI select DEVFREQ_GOV_SIMPLE_ONDEMAND select PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig index cd949800eed962cffa34b599d3ce66f386763d11..8851bc4e8e3e17935b6fc109ff926722c3d68737 100644 --- a/drivers/devfreq/event/Kconfig +++ b/drivers/devfreq/event/Kconfig @@ -33,7 +33,7 @@ config DEVFREQ_EVENT_EXYNOS_PPMU config DEVFREQ_EVENT_ROCKCHIP_DFI tristate "ROCKCHIP DFI DEVFREQ event Driver" - depends on ARCH_ROCKCHIP + depends on ARCH_ROCKCHIP || COMPILE_TEST help This add the devfreq-event driver for Rockchip SoC. It provides DFI (DDR Monitor Module) driver to count ddr load. diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 4e8bcd708bffba8279de74bfddece50a850beb89..62a9fa8b9019e25e637df6c897d110bb6a7df7e2 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -92,10 +92,10 @@ static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen) goto out; } spin_unlock(&dentry->d_lock); - mutex_lock(&dmabuf->lock); + spin_lock(&dmabuf->name_lock); if (dmabuf->name) ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN); - mutex_unlock(&dmabuf->lock); + spin_unlock(&dmabuf->name_lock); dmabuf_dent_put(dmabuf); out: return dynamic_dname(dentry, buffer, buflen, "/%s:%s", @@ -392,8 +392,10 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf) kfree(name); goto out_unlock; } + spin_lock(&dmabuf->name_lock); kfree(dmabuf->name); dmabuf->name = name; + spin_unlock(&dmabuf->name_lock); out_unlock: mutex_unlock(&dmabuf->lock); @@ -463,10 +465,10 @@ static void dma_buf_show_fdinfo(struct seq_file *m, struct file *file) /* Don't count the temporary reference taken inside procfs seq_show */ seq_printf(m, "count:\t%ld\n", file_count(dmabuf->file) - 1); seq_printf(m, "exp_name:\t%s\n", dmabuf->exp_name); - mutex_lock(&dmabuf->lock); + spin_lock(&dmabuf->name_lock); if (dmabuf->name) seq_printf(m, "name:\t%s\n", dmabuf->name); - mutex_unlock(&dmabuf->lock); + spin_unlock(&dmabuf->name_lock); } static const struct file_operations dma_buf_fops = { @@ -623,6 +625,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->size = exp_info->size; dmabuf->exp_name = exp_info->exp_name; dmabuf->owner = exp_info->owner; + spin_lock_init(&dmabuf->name_lock); init_waitqueue_head(&dmabuf->poll); dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll; dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0; diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 6d7d2d54eacf8446156ed44c4598ba6911737e07..f0932f25a9b1ff03e0d8df782f4ddbdd26bd1000 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -1944,8 +1944,6 @@ static void dma_tc_handle(struct coh901318_chan *cohc) return; } - spin_lock(&cohc->lock); - /* * When we reach this point, at least one queue item * should have been moved over from cohc->queue to @@ -1966,8 +1964,6 @@ static void dma_tc_handle(struct coh901318_chan *cohc) if (coh901318_queue_start(cohc) == NULL) cohc->busy = 0; - spin_unlock(&cohc->lock); - /* * This tasklet will remove items from cohc->active * and thus terminates them. diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index b451354735d3d6b80b003f8e6c3ea098d37041e0..faaaf10311ec0b80a48af6910e035cb9051e5b8d 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -192,7 +192,7 @@ __dma_device_satisfies_mask(struct dma_device *device, static struct module *dma_chan_to_owner(struct dma_chan *chan) { - return chan->device->dev->driver->owner; + return chan->device->owner; } /** @@ -928,6 +928,8 @@ int dma_async_device_register(struct dma_device *device) return -EIO; } + device->owner = device->dev->driver->owner; + if (dma_has_cap(DMA_MEMCPY, device->cap_mask) && !device->device_prep_dma_memcpy) { dev_err(device->dev, "Device claims capability %s, but op is not defined\n", diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index e393361277415ef6effbcccd45b92edef68653cf..d19a602beebd15a6b7510b03649f2b661f0d2607 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -552,8 +552,8 @@ static int dmatest_func(void *data) flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; ktime = ktime_get(); - while (!kthread_should_stop() - && !(params->iterations && total_tests >= params->iterations)) { + while (!(kthread_should_stop() || + (params->iterations && total_tests >= params->iterations))) { struct dma_async_tx_descriptor *tx = NULL; struct dmaengine_unmap_data *um; dma_addr_t srcs[src_cnt]; diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index e7dfa1b9767e6402690e60258e10b9fbbbb0ce94..c4e466e16d017d69de137e68b945e939475193cb 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -287,6 +287,7 @@ static const char *const gpi_cb_event_str[MSM_GPI_QUP_MAX_EVENT] = { [MSM_GPI_QUP_NOTIFY] = "NOTIFY", [MSM_GPI_QUP_ERROR] = "GLOBAL ERROR", [MSM_GPI_QUP_CH_ERROR] = "CHAN ERROR", + [MSM_GPI_QUP_FW_ERROR] = "UNHANDLED ERROR", [MSM_GPI_QUP_PENDING_EVENT] = "PENDING EVENT", [MSM_GPI_QUP_EOT_DESC_MISMATCH] = "EOT/DESC MISMATCH", [MSM_GPI_QUP_SW_ERROR] = "SW ERROR", @@ -2191,6 +2192,10 @@ int gpi_terminate_all(struct dma_chan *chan) if (ret) { GPII_ERR(gpii, gpii_chan->chid, "Error resetting channel ret:%d\n", ret); + if (!gpii->reg_table_dump) { + gpi_dump_debug_reg(gpii); + gpii->reg_table_dump = true; + } goto terminate_exit; } diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 7db2766b5fe9e322994b6f5201ec966b671f6994..3402494cadf999a4bba5faf0e0dec5ba4733a404 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -288,7 +288,7 @@ static struct tegra_dma_desc *tegra_dma_desc_get( /* Do not allocate if desc are waiting for ack */ list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) { - if (async_tx_test_ack(&dma_desc->txd)) { + if (async_tx_test_ack(&dma_desc->txd) && !dma_desc->cb_count) { list_del(&dma_desc->node); spin_unlock_irqrestore(&tdc->lock, flags); dma_desc->txd.flags = 0; @@ -755,10 +755,6 @@ static int tegra_dma_terminate_all(struct dma_chan *dc) bool was_busy; spin_lock_irqsave(&tdc->lock, flags); - if (list_empty(&tdc->pending_sg_req)) { - spin_unlock_irqrestore(&tdc->lock, flags); - return 0; - } if (!tdc->busy) goto skip_dma_stop; diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 40fb0e7ff8fd9c018c4db831e8ba21d4df942b4f..b36abd2537863f15aa100ea2cad9627327b144b2 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2863,6 +2863,7 @@ static int init_csrows(struct mem_ctl_info *mci) dimm = csrow->channels[j]->dimm; dimm->mtype = pvt->dram_type; dimm->edac_mode = edac_mode; + dimm->grain = 64; } } diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index f50072b51aefbab846359786d01e26d534d80b96..b39b7e6d4e4dc1a6bcbde746472714b82f5ad521 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -550,7 +550,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, } } - if (efi_enabled(EFI_MEMMAP)) + if (!IS_ENABLED(CONFIG_X86_32) && efi_enabled(EFI_MEMMAP)) efi_memattr_init(); /* Parse the EFI Properties table if it exists */ diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 3e626fd9bd4e1fafe6e0f4da4597ed66a978bd08..1c65f5ac43686cea83939ad3672ca29ba00278f1 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -139,13 +139,16 @@ static ssize_t efivar_attr_read(struct efivar_entry *entry, char *buf) { struct efi_variable *var = &entry->var; + unsigned long size = sizeof(var->Data); char *str = buf; + int ret; if (!entry || !buf) return -EINVAL; - var->DataSize = 1024; - if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) + ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data); + var->DataSize = size; + if (ret) return -EIO; if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) @@ -172,13 +175,16 @@ static ssize_t efivar_size_read(struct efivar_entry *entry, char *buf) { struct efi_variable *var = &entry->var; + unsigned long size = sizeof(var->Data); char *str = buf; + int ret; if (!entry || !buf) return -EINVAL; - var->DataSize = 1024; - if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) + ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data); + var->DataSize = size; + if (ret) return -EIO; str += sprintf(str, "0x%lx\n", var->DataSize); @@ -189,12 +195,15 @@ static ssize_t efivar_data_read(struct efivar_entry *entry, char *buf) { struct efi_variable *var = &entry->var; + unsigned long size = sizeof(var->Data); + int ret; if (!entry || !buf) return -EINVAL; - var->DataSize = 1024; - if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) + ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data); + var->DataSize = size; + if (ret) return -EIO; memcpy(buf, var->Data, var->DataSize); @@ -263,6 +272,9 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) u8 *data; int err; + if (!entry || !buf) + return -EINVAL; + if (is_compat()) { struct compat_efi_variable *compat; @@ -314,14 +326,16 @@ efivar_show_raw(struct efivar_entry *entry, char *buf) { struct efi_variable *var = &entry->var; struct compat_efi_variable *compat; + unsigned long datasize = sizeof(var->Data); size_t size; + int ret; if (!entry || !buf) return 0; - var->DataSize = 1024; - if (efivar_entry_get(entry, &entry->var.Attributes, - &entry->var.DataSize, entry->var.Data)) + ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data); + var->DataSize = datasize; + if (ret) return -EIO; if (is_compat()) { diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 6544a16ab02e9b94f836d03e84757bc85a3ca711..7541bd327e6c5b332f12c84f5f74e737a76cd9ee 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -259,17 +259,16 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, lirq->irq = irq; uirq = &priv->uirqs[lirq->index]; if (uirq->refcnt == 0) { + spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, dev_name(priv->dev), priv); if (ret) { dev_err(priv->dev, "Could not request underlying irq %d\n", uirq->uirq); - - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); - return ret; } + spin_lock_irqsave(&priv->gc.bgpio_lock, flags); } uirq->refcnt++; @@ -315,8 +314,11 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) if (index >= 0) { uirq = &priv->uirqs[lirq->index]; uirq->refcnt--; - if (uirq->refcnt == 0) + if (uirq->refcnt == 0) { + spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); free_irq(uirq->uirq, priv); + return; + } } spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c7b9125c8ec229e7b9871c63665751177fd54bdc..7c06f4541c5d057ff9873a066e923a95b7591cb9 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -24,18 +24,21 @@ #include "gpiolib.h" -#define QUIRK_NO_EDGE_EVENTS_ON_BOOT 0x01l -#define QUIRK_NO_WAKEUP 0x02l - static int run_edge_events_on_boot = -1; module_param(run_edge_events_on_boot, int, 0444); MODULE_PARM_DESC(run_edge_events_on_boot, "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto"); -static int honor_wakeup = -1; -module_param(honor_wakeup, int, 0444); -MODULE_PARM_DESC(honor_wakeup, - "Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto"); +static char *ignore_wake; +module_param(ignore_wake, charp, 0444); +MODULE_PARM_DESC(ignore_wake, + "controller@pin combos on which to ignore the ACPI wake flag " + "ignore_wake=controller@pin[,controller@pin[,...]]"); + +struct acpi_gpiolib_dmi_quirk { + bool no_edge_events_on_boot; + char *ignore_wake; +}; /** * struct acpi_gpio_event - ACPI GPIO event handler data @@ -262,6 +265,57 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio) acpi_gpiochip_request_irq(acpi_gpio, event); } +static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in) +{ + const char *controller, *pin_str; + int len, pin; + char *endp; + + controller = ignore_wake; + while (controller) { + pin_str = strchr(controller, '@'); + if (!pin_str) + goto err; + + len = pin_str - controller; + if (len == strlen(controller_in) && + strncmp(controller, controller_in, len) == 0) { + pin = simple_strtoul(pin_str + 1, &endp, 10); + if (*endp != 0 && *endp != ',') + goto err; + + if (pin == pin_in) + return true; + } + + controller = strchr(controller, ','); + if (controller) + controller++; + } + + return false; +err: + pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n", + ignore_wake); + return false; +} + +static bool acpi_gpio_irq_is_wake(struct device *parent, + struct acpi_resource_gpio *agpio) +{ + int pin = agpio->pin_table[0]; + + if (agpio->wake_capable != ACPI_WAKE_CAPABLE) + return false; + + if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) { + dev_info(parent, "Ignoring wakeup on pin %d\n", pin); + return false; + } + + return true; +} + static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, void *context) { @@ -347,7 +401,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, event->handle = evt_handle; event->handler = handler; event->irq = irq; - event->irq_is_wake = honor_wakeup && agpio->wake_capable == ACPI_WAKE_CAPABLE; + event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio); event->pin = pin; event->desc = desc; @@ -1331,7 +1385,9 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "MINIX"), DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), }, - .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .no_edge_events_on_boot = true, + }, }, { /* @@ -1344,16 +1400,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"), DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"), }, - .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .no_edge_events_on_boot = true, + }, }, { /* - * Various HP X2 10 Cherry Trail models use an external - * embedded-controller connected via I2C + an ACPI GPIO - * event handler. The embedded controller generates various - * spurious wakeup events when suspended. So disable wakeup - * for its handler (it uses the only ACPI GPIO event handler). - * This breaks wakeup when opening the lid, the user needs + * HP X2 10 models with Cherry Trail SoC + TI PMIC use an + * external embedded-controller connected via I2C + an ACPI GPIO + * event handler on INT33FF:01 pin 0, causing spurious wakeups. + * When suspending by closing the LID, the power to the USB + * keyboard is turned off, causing INT0002 ACPI events to + * trigger once the XHCI controller notices the keyboard is + * gone. So INT0002 events cause spurious wakeups too. Ignoring + * EC wakes breaks wakeup when opening the lid, the user needs * to press the power-button to wakeup the system. The * alternative is suspend simply not working, which is worse. */ @@ -1361,33 +1421,61 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"), }, - .driver_data = (void *)QUIRK_NO_WAKEUP, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "INT33FF:01@0,INT0002:00@2", + }, + }, + { + /* + * HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an + * external embedded-controller connected via I2C + an ACPI GPIO + * event handler on INT33FC:02 pin 28, causing spurious wakeups. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + DMI_MATCH(DMI_BOARD_NAME, "815D"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "INT33FC:02@28", + }, + }, + { + /* + * HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an + * external embedded-controller connected via I2C + an ACPI GPIO + * event handler on INT33FF:01 pin 0, causing spurious wakeups. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + DMI_MATCH(DMI_BOARD_NAME, "813E"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "INT33FF:01@0", + }, }, {} /* Terminating entry */ }; static int acpi_gpio_setup_params(void) { + const struct acpi_gpiolib_dmi_quirk *quirk = NULL; const struct dmi_system_id *id; - long quirks = 0; id = dmi_first_match(gpiolib_acpi_quirks); if (id) - quirks = (long)id->driver_data; + quirk = id->driver_data; if (run_edge_events_on_boot < 0) { - if (quirks & QUIRK_NO_EDGE_EVENTS_ON_BOOT) + if (quirk && quirk->no_edge_events_on_boot) run_edge_events_on_boot = 0; else run_edge_events_on_boot = 1; } - if (honor_wakeup < 0) { - if (quirks & QUIRK_NO_WAKEUP) - honor_wakeup = 0; - else - honor_wakeup = 1; - } + if (ignore_wake == NULL && quirk && quirk->ignore_wake) + ignore_wake = quirk->ignore_wake; return 0; } diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index f4ebf7783ffc0d7927a629c9adda06f9ec4eb685..3c9f24d7b2ef982b50d1cf3319aa15525d42a21f 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_TEGRA_HOST1X) += host1x/ obj-y += drm/ vga/ obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ obj-$(CONFIG_QCOM_KGSL) += msm/ +obj-$(CONFIG_TRACE_GPU_MEM) += trace/ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index cc4e18dcd8b6f96abf3eade8a91cbe43ae4660c4..2153f19e59ccced533dd3da19c480054a70e557c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -336,17 +336,9 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device * path_size += le16_to_cpu(path->usSize); if (device_support & le16_to_cpu(path->usDeviceTag)) { - uint8_t con_obj_id, con_obj_num, con_obj_type; - - con_obj_id = + uint8_t con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - con_obj_num = - (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) - >> ENUM_ID_SHIFT; - con_obj_type = - (le16_to_cpu(path->usConnObjectId) & - OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; /* Skip TV/CV support */ if ((le16_to_cpu(path->usDeviceTag) == @@ -371,15 +363,7 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device * router.ddc_valid = false; router.cd_valid = false; for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { - uint8_t grph_obj_id, grph_obj_num, grph_obj_type; - - grph_obj_id = - (le16_to_cpu(path->usGraphicObjIds[j]) & - OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - grph_obj_num = - (le16_to_cpu(path->usGraphicObjIds[j]) & - ENUM_ID_MASK) >> ENUM_ID_SHIFT; - grph_obj_type = + uint8_t grph_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index ff7d4827385e4d96ff3fca35161d77c40bfb86ff..7a2366bd1fbaf1f03d74ca5c89201296cb82b856 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -279,7 +279,12 @@ static void soc15_init_golden_registers(struct amdgpu_device *adev) } static u32 soc15_get_xclk(struct amdgpu_device *adev) { - return adev->clock.spll.reference_freq; + u32 reference_clock = adev->clock.spll.reference_freq; + + if (adev->asic_type == CHIP_RAVEN) + return reference_clock / 4; + + return reference_clock; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 61fff25b4ce7dadbb789b00fca8b09d40835baa4..ecd4eba221c0a0da36f188bb7fce14b8d1116460 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -550,9 +550,9 @@ int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size, return 0; kfd_gtt_no_free_chunk: - pr_debug("Allocation failed with mem_obj = %p\n", mem_obj); + pr_debug("Allocation failed with mem_obj = %p\n", *mem_obj); mutex_unlock(&kfd->gtt_sa_lock); - kfree(mem_obj); + kfree(*mem_obj); return -ENOMEM; } diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index d73281095facabbaf7b54d6f309123f8b044821d..976109c20d493ccf5dd5a26542e93ec13b57b55b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -79,7 +79,11 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) struct videomode vm; unsigned long prate; unsigned int cfg; - int div; + int div, ret; + + ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk); + if (ret) + return; vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; @@ -138,6 +142,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK, cfg); + + clk_disable_unprepare(crtc->dc->hlcdc->sys_clk); } static enum drm_mode_status diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c index a39b0343c197dc8a6aea00aa244b80dae1fde232..401c218567af9538f3f5416f9daa1850e7e202d6 100644 --- a/drivers/gpu/drm/bochs/bochs_hw.c +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -97,10 +97,8 @@ int bochs_hw_init(struct drm_device *dev, uint32_t flags) size = min(size, mem); } - if (pci_request_region(pdev, 0, "bochs-drm") != 0) { - DRM_ERROR("Cannot request framebuffer\n"); - return -EBUSY; - } + if (pci_request_region(pdev, 0, "bochs-drm") != 0) + DRM_WARN("Cannot request framebuffer, boot fb still active?\n"); bochs->fb_map = ioremap(addr, size); if (bochs->fb_map == NULL) { diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index cc1094f9012553ccc6ad281a0958b2a09e22a0ca..96cf64d0ee82480dfe35f4056f23c36f63c4d7e4 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1348,28 +1348,34 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) frame.colorspace = HDMI_COLORSPACE_RGB; /* Set up colorimetry */ - switch (hdmi->hdmi_data.enc_out_encoding) { - case V4L2_YCBCR_ENC_601: - if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601) - frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; - else + if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { + switch (hdmi->hdmi_data.enc_out_encoding) { + case V4L2_YCBCR_ENC_601: + if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601) + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; + else + frame.colorimetry = HDMI_COLORIMETRY_ITU_601; + frame.extended_colorimetry = + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; + case V4L2_YCBCR_ENC_709: + if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709) + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; + else + frame.colorimetry = HDMI_COLORIMETRY_ITU_709; + frame.extended_colorimetry = + HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; + break; + default: /* Carries no data */ frame.colorimetry = HDMI_COLORIMETRY_ITU_601; + frame.extended_colorimetry = + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; + } + } else { + frame.colorimetry = HDMI_COLORIMETRY_NONE; frame.extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - break; - case V4L2_YCBCR_ENC_709: - if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709) - frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; - else - frame.colorimetry = HDMI_COLORIMETRY_ITU_709; - frame.extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; - break; - default: /* Carries no data */ - frame.colorimetry = HDMI_COLORIMETRY_ITU_601; - frame.extended_colorimetry = - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - break; + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; } frame.scan_mode = HDMI_SCAN_MODE_NONE; diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 2901b7944068de4fd169122a236cc94da420e95c..6858c80d2eb503db25664159994a08645659520e 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -101,8 +101,8 @@ static ssize_t crc_control_write(struct file *file, const char __user *ubuf, if (IS_ERR(source)) return PTR_ERR(source); - if (source[len] == '\n') - source[len] = '\0'; + if (source[len - 1] == '\n') + source[len - 1] = '\0'; spin_lock_irq(&crc->lock); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index c635e13e92b92f699da3458ba3a6e897da91c986..fe59b05bbe7ba36ebfb564759fdb4088d5241e5f 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1019,20 +1019,9 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_ static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { struct drm_dp_mst_port *rport = NULL; - mutex_lock(&mgr->lock); - /* - * Port may or may not be 'valid' but we don't care about that when - * destroying the port and we are guaranteed that the port pointer - * will be valid until we've finished - */ - if (current_work() == &mgr->destroy_connector_work) { - kref_get(&port->kref); - rport = port; - } else if (mgr->mst_primary) { - rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, - port); - } + if (mgr->mst_primary) + rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port); mutex_unlock(&mgr->lock); return rport; } @@ -2173,6 +2162,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms u8 buf; u32 offset = DP_DPCD_REV; + mutex_lock(&mgr->payload_lock); mutex_lock(&mgr->lock); if (mst_state == mgr->mst_state) goto out_unlock; @@ -2244,7 +2234,10 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms /* this can fail if the device is gone */ drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0); ret = 0; - memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload)); + memset(mgr->payloads, 0, + mgr->max_payloads * sizeof(mgr->payloads[0])); + memset(mgr->proposed_vcpis, 0, + mgr->max_payloads * sizeof(mgr->proposed_vcpis[0])); mgr->payload_mask = 0; set_bit(0, &mgr->payload_mask); mgr->vcpi_mask = 0; @@ -2252,6 +2245,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms out_unlock: mutex_unlock(&mgr->lock); + mutex_unlock(&mgr->payload_lock); if (mstb) drm_dp_put_mst_branch_device(mstb); return ret; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 252e21c7d3eb924e08b4a13abcfa5adeb7debb82..df5fe163cfec8d0000391b2c85beaecaebb33fbc 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4774,7 +4774,7 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d struct drm_display_mode *mode; unsigned pixel_clock = (timings->pixel_clock[0] | (timings->pixel_clock[1] << 8) | - (timings->pixel_clock[2] << 16)); + (timings->pixel_clock[2] << 16)) + 1; unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1; unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1; unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 1235c9877d6f1cebb50cf5c478c2f086d9da42a0..2078d7706a67bf54183cd930b1bc5c27cbc6c967 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -46,8 +46,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align) { drm_dma_handle_t *dmah; - unsigned long addr; - size_t sz; /* pci_alloc_consistent only guarantees alignment to the smallest * PAGE_SIZE order which is greater than or equal to the requested size. @@ -61,22 +59,13 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali return NULL; dmah->size = size; - dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); + dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL); if (dmah->vaddr == NULL) { kfree(dmah); return NULL; } - memset(dmah->vaddr, 0, size); - - /* XXX - Is virt_to_page() legal for consistent mem? */ - /* Reserve */ - for (addr = (unsigned long)dmah->vaddr, sz = size; - sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - SetPageReserved(virt_to_page((void *)addr)); - } - return dmah; } @@ -89,19 +78,9 @@ EXPORT_SYMBOL(drm_pci_alloc); */ void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) { - unsigned long addr; - size_t sz; - - if (dmah->vaddr) { - /* XXX - Is virt_to_page() legal for consistent mem? */ - /* Unreserve */ - for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; - sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - ClearPageReserved(virt_to_page((void *)addr)); - } + if (dmah->vaddr) dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, dmah->busaddr); - } } /** diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index ed9588f36bc9b4a6214eca1e2954f520a0ce8ef4..5fc1b41cb6c53fd62c7edfbc2be8cb7401720121 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -258,6 +258,8 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, unsigned int waitlink_offset = buffer->user_size - 16; u32 return_target, return_dwords; u32 link_target, link_dwords; + unsigned int new_flush_seq = READ_ONCE(gpu->mmu->flush_seq); + bool need_flush = gpu->flush_seq != new_flush_seq; if (drm_debug & DRM_UT_DRIVER) etnaviv_buffer_dump(gpu, buffer, 0, 0x50); @@ -270,14 +272,14 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, * need to append a mmu flush load state, followed by a new * link to this buffer - a total of four additional words. */ - if (gpu->mmu->need_flush || gpu->switch_context) { + if (need_flush || gpu->switch_context) { u32 target, extra_dwords; /* link command */ extra_dwords = 1; /* flush command */ - if (gpu->mmu->need_flush) { + if (need_flush) { if (gpu->mmu->version == ETNAVIV_IOMMU_V1) extra_dwords += 1; else @@ -290,7 +292,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, target = etnaviv_buffer_reserve(gpu, buffer, extra_dwords); - if (gpu->mmu->need_flush) { + if (need_flush) { /* Add the MMU flush */ if (gpu->mmu->version == ETNAVIV_IOMMU_V1) { CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU, @@ -310,7 +312,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, SYNC_RECIPIENT_PE); } - gpu->mmu->need_flush = false; + gpu->flush_seq = new_flush_seq; } if (gpu->switch_context) { diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index a1562f89c3d7c4e9f0933872460ed8006783f363..1f8c8e4328e45e4e35f59a45576014e3e1dd77d4 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1353,7 +1353,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, gpu->active_fence = submit->fence->seqno; if (gpu->lastctx != cmdbuf->ctx) { - gpu->mmu->need_flush = true; + gpu->mmu->flush_seq++; gpu->switch_context = true; gpu->lastctx = cmdbuf->ctx; } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 689cb8f3680c97bcd62836bfd90885f134862650..62b2877d090bb519c0351c1cd7405a191d133d1d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -138,6 +138,7 @@ struct etnaviv_gpu { struct etnaviv_iommu *mmu; struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc; + unsigned int flush_seq; /* Power Control: */ struct clk *clk_bus; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index f103e787de94379e127947ad1707af1f54913d67..0e23a0542f0a9170c4ed93afbf7dc4fe4648d54f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -132,7 +132,7 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, */ if (mmu->last_iova) { mmu->last_iova = 0; - mmu->need_flush = true; + mmu->flush_seq++; continue; } @@ -246,7 +246,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, } list_add_tail(&mapping->mmu_node, &mmu->mappings); - mmu->need_flush = true; + mmu->flush_seq++; mutex_unlock(&mmu->lock); return ret; @@ -264,7 +264,7 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu, etnaviv_iommu_remove_mapping(mmu, mapping); list_del(&mapping->mmu_node); - mmu->need_flush = true; + mmu->flush_seq++; mutex_unlock(&mmu->lock); } @@ -346,7 +346,7 @@ int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr, return ret; } mmu->last_iova = vram_node->start + size; - gpu->mmu->need_flush = true; + mmu->flush_seq++; mutex_unlock(&mmu->lock); *iova = (u32)vram_node->start; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h index 54be289e5981c65a9fc2e5a0c11e49071918a21a..ccb6ad3582b82ba4fd55359e9973a3606dc94501 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h @@ -44,7 +44,7 @@ struct etnaviv_iommu { struct list_head mappings; struct drm_mm mm; u32 last_iova; - bool need_flush; + unsigned int flush_seq; }; struct etnaviv_gem_object; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 7904ffa9abfb95ca17bf3f938b83e19c67a0c897..366c975cde5b7041bbfc2f78de6088062c7c7308 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1739,8 +1739,9 @@ static int exynos_dsi_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies), dsi->supplies); if (ret) { - dev_info(dev, "failed to get regulators: %d\n", ret); - return -EPROBE_DEFER; + if (ret != -EPROBE_DEFER) + dev_info(dev, "failed to get regulators: %d\n", ret); + return ret; } dsi->clks = devm_kzalloc(dev, @@ -1753,9 +1754,10 @@ static int exynos_dsi_probe(struct platform_device *pdev) dsi->clks[i] = devm_clk_get(dev, clk_names[i]); if (IS_ERR(dsi->clks[i])) { if (strcmp(clk_names[i], "sclk_mipi") == 0) { - strcpy(clk_names[i], OLD_SCLK_MIPI_CLK_NAME); - i--; - continue; + dsi->clks[i] = devm_clk_get(dev, + OLD_SCLK_MIPI_CLK_NAME); + if (!IS_ERR(dsi->clks[i])) + continue; } dev_info(dev, "failed to get the clock: %s\n", diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 2570c7f647a637f3ea5eabf4030e77888116a33b..883fc45870dd9e992f2a8d964729cd0eb676dc50 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -486,6 +486,7 @@ static int psbfb_probe(struct drm_fb_helper *helper, container_of(helper, struct psb_fbdev, psb_fb_helper); struct drm_device *dev = psb_fbdev->psb_fb_helper.dev; struct drm_psb_private *dev_priv = dev->dev_private; + unsigned int fb_size; int bytespp; bytespp = sizes->surface_bpp / 8; @@ -495,8 +496,11 @@ static int psbfb_probe(struct drm_fb_helper *helper, /* If the mode will not fit in 32bit then switch to 16bit to get a console on full resolution. The X mode setting server will allocate its own 32bit GEM framebuffer */ - if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height > - dev_priv->vram_stolen_size) { + fb_size = ALIGN(sizes->surface_width * bytespp, 64) * + sizes->surface_height; + fb_size = ALIGN(fb_size, PAGE_SIZE); + + if (fb_size > dev_priv->vram_stolen_size) { sizes->surface_bpp = 16; sizes->surface_depth = 16; } diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 02c61a1ad56a213146f808eb506ac00dccc257d3..e9f9063dbf6339b2c68ab4e46623d3b25d0b6b1b 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -513,9 +513,9 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, intel_vgpu_reset_mmio(vgpu, dmlr); populate_pvinfo_page(vgpu); - intel_vgpu_reset_display(vgpu); if (dmlr) { + intel_vgpu_reset_display(vgpu); intel_vgpu_reset_cfg_space(vgpu); /* only reset the failsafe mode when dmlr reset */ vgpu->failsafe = false; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 658b8dd45b834fb463cab8424e5067dc82258e39..3ea311d32fa9eba50d1e8c19b989b1067131b1e1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -307,6 +307,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) { struct drm_device *drm = mtk_crtc->base.dev; + struct drm_crtc *crtc = &mtk_crtc->base; int i; DRM_DEBUG_DRIVER("%s\n", __func__); @@ -328,6 +329,13 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) mtk_disp_mutex_unprepare(mtk_crtc->mutex); pm_runtime_put(drm->dev); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irq(&crtc->dev->event_lock); + } } static void mtk_crtc_ddp_config(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 855248132b2bd2d0a24c878b0066074e412f83ca..9fbfa9f94e6ce6aa951acc489b791bc6cef5d708 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -400,7 +400,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) return num; } -static int dsi_mgr_connector_mode_valid(struct drm_connector *connector, +static enum drm_mode_status dsi_mgr_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { int id = dsi_mgr_connector_get_id(connector); @@ -543,6 +543,7 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1); struct mipi_dsi_host *host = msm_dsi->host; struct drm_panel *panel = msm_dsi->panel; + struct msm_dsi_pll *src_pll; bool is_dual_dsi = IS_DUAL_DSI(); int ret; @@ -583,6 +584,10 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) id, ret); } + /* Save PLL status if it is a clock source */ + src_pll = msm_dsi_phy_get_pll(msm_dsi->phy); + msm_dsi_pll_save_state(src_pll); + ret = msm_dsi_host_power_off(host); if (ret) pr_err("%s: host %d power off failed,%d\n", __func__, id, ret); diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 7c9bf91bc22b6dd20615cb9181bec1446e3f72be..c0a7fa56d9a74bfd3d85ebaaae4daac6f06234d6 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -613,10 +613,6 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy) if (!phy || !phy->cfg->ops.disable) return; - /* Save PLL status if it is a clock source */ - if (phy->usecase != MSM_DSI_PHY_SLAVE) - msm_dsi_pll_save_state(phy->pll); - phy->cfg->ops.disable(phy); dsi_phy_regulator_disable(phy); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 44097767700124df63f8a325969ea44b494256d7..99d356b6e915159a224041c8333a4231e8574b1c 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -1004,8 +1004,8 @@ static void mdp5_crtc_wait_for_pp_done(struct drm_crtc *crtc) ret = wait_for_completion_timeout(&mdp5_crtc->pp_completion, msecs_to_jiffies(50)); if (ret == 0) - dev_warn(dev->dev, "pp done time out, lm=%d\n", - mdp5_cstate->pipeline.mixer->lm); + dev_warn_ratelimited(dev->dev, "pp done time out, lm=%d\n", + mdp5_cstate->pipeline.mixer->lm); } static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9a8ce342e040efd4918a4a8f9606002abe3d4aa4..ec037cd5e2346447ad347670353e662389152ad7 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -562,6 +562,14 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) if (ret) goto fail; + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + switch (get_mdp_ver(pdev)) { case KMS_MDP4: kms = mdp4_kms_init(ddev); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 6f48fc1cd1d1f08c3d3d4815f05716cbcf45d15b..ec263f2b31e9a8da10acecda0abdb34da53de6e3 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -44,6 +44,46 @@ static bool use_pages(struct drm_gem_object *obj) return !msm_obj->vram_node; } +/* + * Cache sync.. this is a bit over-complicated, to fit dma-mapping + * API. Really GPU cache is out of scope here (handled on cmdstream) + * and all we need to do is invalidate newly allocated pages before + * mapping to CPU as uncached/writecombine. + * + * On top of this, we have the added headache, that depending on + * display generation, the display's iommu may be wired up to either + * the toplevel drm device (mdss), or to the mdp sub-node, meaning + * that here we either have dma-direct or iommu ops. + * + * Let this be a cautionary tail of abstraction gone wrong. + */ + +static void sync_for_device(struct msm_gem_object *msm_obj) +{ + struct device *dev = msm_obj->base.dev->dev; + + if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) { + dma_sync_sg_for_device(dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + } else { + dma_map_sg(dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + } +} + +static void sync_for_cpu(struct msm_gem_object *msm_obj) +{ + struct device *dev = msm_obj->base.dev->dev; + + if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) { + dma_sync_sg_for_cpu(dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + } else { + dma_unmap_sg(dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + } +} + /* allocate pages from VRAM carveout, used when no IOMMU: */ static struct page **get_pages_vram(struct drm_gem_object *obj, int npages) { @@ -112,8 +152,7 @@ static struct page **get_pages(struct drm_gem_object *obj) * so we don't get ourselves into trouble with a dirty cache */ if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) - dma_sync_sg_for_device(dev->dev, msm_obj->sgt->sgl, - msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + sync_for_device(msm_obj); } return msm_obj->pages; @@ -136,9 +175,17 @@ static void put_pages(struct drm_gem_object *obj) struct msm_gem_object *msm_obj = to_msm_bo(obj); if (msm_obj->pages) { - if (msm_obj->sgt) + if (msm_obj->sgt) { + /* For non-cached buffers, ensure the new + * pages are clean because display controller, + * GPU, etc. are not coherent: + */ + if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) + sync_for_cpu(msm_obj); + sg_free_table(msm_obj->sgt); - kfree(msm_obj->sgt); + kfree(msm_obj->sgt); + } if (use_pages(obj)) drm_gem_put_pages(obj, msm_obj->pages, true, false); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 99e14e3e0fe4d44f1a6c51e1225db7e1af21a1bb..72532539369fb84f7ee79c4182d1100222337dd0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -158,7 +158,7 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) fence = list_entry(fctx->pending.next, typeof(*fence), head); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); - if (nouveau_fence_update(fence->channel, fctx)) + if (nouveau_fence_update(chan, fctx)) ret = NVIF_NOTIFY_DROP; } spin_unlock_irqrestore(&fctx->lock, flags); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index 0c0310498afdb99e59459b5e70873bc7ad6a5f55..cd9666583d4bd0ad8362bb86c0d79d791a888f51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -73,6 +73,8 @@ nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug) if (debug > subdev->debug) return; + if (!mthd) + return; for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) { u32 base = chan->head * mthd->addr; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index de8b806b88fd9dfd8cc1e1b864a3974db04ffbf7..7618b2eb4fdfde85e0b92e946c1754a57ec1418f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -143,23 +143,24 @@ gk20a_gr_av_to_method(struct gf100_gr *gr, const char *fw_name, nent = (fuc.size / sizeof(struct gk20a_fw_av)); - pack = vzalloc((sizeof(*pack) * max_classes) + - (sizeof(*init) * (nent + 1))); + pack = vzalloc((sizeof(*pack) * (max_classes + 1)) + + (sizeof(*init) * (nent + max_classes + 1))); if (!pack) { ret = -ENOMEM; goto end; } - init = (void *)(pack + max_classes); + init = (void *)(pack + max_classes + 1); - for (i = 0; i < nent; i++) { - struct gf100_gr_init *ent = &init[i]; + for (i = 0; i < nent; i++, init++) { struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc.data)[i]; u32 class = av->addr & 0xffff; u32 addr = (av->addr & 0xffff0000) >> 14; if (prevclass != class) { - pack[classidx].init = ent; + if (prevclass) /* Add terminator to the method list. */ + init++; + pack[classidx].init = init; pack[classidx].type = class; prevclass = class; if (++classidx >= max_classes) { @@ -169,10 +170,10 @@ gk20a_gr_av_to_method(struct gf100_gr *gr, const char *fw_name, } } - ent->addr = addr; - ent->data = av->data; - ent->count = 1; - ent->pitch = 1; + init->addr = addr; + init->data = av->data; + init->count = 1; + init->pitch = 1; } *ppack = pack; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c index 30491d132d59c08cf6defd83c0169c1b83b227c7..fbd10a67c6c6a8d234e12ce9bde3e57fdedb464e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c @@ -108,6 +108,7 @@ gm20b_secboot_new(struct nvkm_device *device, int index, struct gm200_secboot *gsb; struct nvkm_acr *acr; + *psb = NULL; acr = acr_r352_new(BIT(NVKM_SECBOOT_FALCON_FECS) | BIT(NVKM_SECBOOT_FALCON_PMU)); if (IS_ERR(acr)) @@ -116,10 +117,8 @@ gm20b_secboot_new(struct nvkm_device *device, int index, acr->optional_falcons = BIT(NVKM_SECBOOT_FALCON_PMU); gsb = kzalloc(sizeof(*gsb), GFP_KERNEL); - if (!gsb) { - psb = NULL; + if (!gsb) return -ENOMEM; - } *psb = &gsb->base; ret = nvkm_secboot_ctor(&gm20b_secboot, acr, device, index, &gsb->base); diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 3eb92085114173554c3b9d28e72bd9c68dc1fb34..8334afa70b94ffe90803037c1f33b6f0a087eb9c 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -504,9 +504,10 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev, return ret; ret = qxl_release_reserve_list(release, true); - if (ret) + if (ret) { + qxl_release_free(qdev, release); return ret; - + } cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release); cmd->type = QXL_SURFACE_CMD_CREATE; cmd->flags = QXL_SURF_FLAG_KEEP_DATA; @@ -532,8 +533,8 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev, /* no need to add a release to the fence for this surface bo, since it is only released when we ask to destroy the surface and it would never signal otherwise */ - qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); qxl_release_fence_buffer_objects(release); + qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); surf->hw_surf_alloc = true; spin_lock(&qdev->surf_id_idr_lock); @@ -575,9 +576,8 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev, cmd->surface_id = id; qxl_release_unmap(qdev, release, &cmd->release_info); - qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); - qxl_release_fence_buffer_objects(release); + qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 573bab2221230d723852ab19f7d86f95f1050fd9..b209a25e307d57d206958b2e22010a072f982614 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -533,8 +533,8 @@ static int qxl_primary_apply_cursor(struct drm_plane *plane) cmd->u.set.visible = 1; qxl_release_unmap(qdev, release, &cmd->release_info); - qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); qxl_release_fence_buffer_objects(release); + qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); return ret; @@ -701,8 +701,8 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane, cmd->u.position.y = plane->state->crtc_y + fb->hot_y; qxl_release_unmap(qdev, release, &cmd->release_info); - qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); qxl_release_fence_buffer_objects(release); + qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); if (old_cursor_bo) qxl_bo_unref(&old_cursor_bo); @@ -747,8 +747,8 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane, cmd->type = QXL_CURSOR_HIDE; qxl_release_unmap(qdev, release, &cmd->release_info); - qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); qxl_release_fence_buffer_objects(release); + qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); } static int qxl_plane_prepare_fb(struct drm_plane *plane, diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c index 4d8681e84e684f58fa5aec6e1da3c44818befb0e..d009f2bc28e93d2efd4a77770b623ab99cf58d82 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -241,8 +241,8 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image, qxl_bo_physical_address(qdev, dimage->bo, 0); qxl_release_unmap(qdev, release, &drawable->release_info); - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); qxl_release_fence_buffer_objects(release); + qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); out_free_palette: if (palette_bo) @@ -348,9 +348,10 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, goto out_release_backoff; rects = drawable_set_clipping(qdev, num_clips, clips_bo); - if (!rects) + if (!rects) { + ret = -EINVAL; goto out_release_backoff; - + } drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); drawable->clip.type = SPICE_CLIP_TYPE_RECTS; @@ -381,8 +382,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, } qxl_bo_kunmap(clips_bo); - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); qxl_release_fence_buffer_objects(release); + qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); out_release_backoff: if (ret) @@ -432,8 +433,8 @@ void qxl_draw_copyarea(struct qxl_device *qdev, drawable->u.copy_bits.src_pos.y = sy; qxl_release_unmap(qdev, release, &drawable->release_info); - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); qxl_release_fence_buffer_objects(release); + qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); out_free_release: if (ret) @@ -476,8 +477,8 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec) qxl_release_unmap(qdev, release, &drawable->release_info); - qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); qxl_release_fence_buffer_objects(release); + qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); out_free_release: if (ret) diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 31effed4a3c823d8509af4338258d76c6ab65764..cede17585525fd93385b0748c5a55d27b091db67 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -257,11 +257,8 @@ static int qxl_process_single_command(struct qxl_device *qdev, apply_surf_reloc(qdev, &reloc_info[i]); } + qxl_release_fence_buffer_objects(release); ret = qxl_push_command_ring_release(qdev, release, cmd->type, true); - if (ret) - qxl_release_backoff_reserve_list(release); - else - qxl_release_fence_buffer_objects(release); out_free_bos: out_free_release: diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 4f94b78cb46472bba2d60116139bc2aeea0a8f2b..d86110cdf085254e7d65d89c85b165a0c5057eb1 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -119,6 +119,8 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc) DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id); + msleep(10); + WREG32(NI_INPUT_CSC_CONTROL + radeon_crtc->crtc_offset, (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) | NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS))); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 68eed684dff52077b3a3dd471f610dd7486d518f..1669af08fafa075e5c7e36e1523212b4b1f990d4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -245,15 +245,23 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) if (zero_alloc) page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; case ttm_bo_type_kernel: - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags, glob->dummy_read_page); + if (bdev->driver->ttm_tt_create2) + bo->ttm = bdev->driver->ttm_tt_create2(bo, page_flags, + glob->dummy_read_page); + else + bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags, glob->dummy_read_page); if (unlikely(bo->ttm == NULL)) ret = -ENOMEM; break; case ttm_bo_type_sg: - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags | TTM_PAGE_FLAG_SG, - glob->dummy_read_page); + if (bdev->driver->ttm_tt_create2) + bo->ttm = bdev->driver->ttm_tt_create2(bo, page_flags | TTM_PAGE_FLAG_SG, + glob->dummy_read_page); + else + bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags | TTM_PAGE_FLAG_SG, + glob->dummy_read_page); if (unlikely(bo->ttm == NULL)) { ret = -ENOMEM; break; diff --git a/drivers/gpu/drm/virtio/Kconfig b/drivers/gpu/drm/virtio/Kconfig index 0c384d9a2b75e3e47b5c064ef76ee64f6afbaaeb..46010fc78f52d0e9510a63a8b5268bf1d650cec6 100644 --- a/drivers/gpu/drm/virtio/Kconfig +++ b/drivers/gpu/drm/virtio/Kconfig @@ -1,6 +1,6 @@ config DRM_VIRTIO_GPU tristate "Virtio GPU driver" - depends on DRM && VIRTIO && MMU + depends on DRM && VIRTIO && MMU && PCI select DRM_KMS_HELPER select DRM_TTM help diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index 11e25e9a4c45380200fcfa0815933751e3939c0a..42949a17ff701ec10853a23e98e165e4869b704a 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile @@ -3,7 +3,7 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_drm_bus.o virtgpu_gem.o \ +virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o \ virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o diff --git a/drivers/gpu/drm/virtio/virtgpu_debugfs.c b/drivers/gpu/drm/virtio/virtgpu_debugfs.c index ed0fcda713c3688ed3d2d209f04bd552c43d175a..0e29f1ce3f690a1764ed7e181d9bf67743733977 100644 --- a/drivers/gpu/drm/virtio/virtgpu_debugfs.c +++ b/drivers/gpu/drm/virtio/virtgpu_debugfs.c @@ -47,6 +47,8 @@ static int virtio_gpu_features(struct seq_file *m, void *data) virtio_add_bool(m, "virgl", vgdev->has_virgl_3d); virtio_add_bool(m, "edid", vgdev->has_edid); + virtio_add_bool(m, "resource blob", vgdev->has_resource_blob); + virtio_add_bool(m, "host visible", vgdev->has_host_visible); virtio_add_int(m, "cap sets", vgdev->num_capsets); virtio_add_int(m, "scanouts", vgdev->num_scanouts); return 0; diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 443cf4c9307471e71218f3907da3d560710b74f7..3922de4a4f713577a22491bccb6e97376570eb90 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -356,7 +356,7 @@ static const struct drm_mode_config_funcs virtio_gpu_mode_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) +void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) { int i; @@ -374,7 +374,6 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) vgdev_output_init(vgdev, i); drm_mode_config_reset(vgdev->ddev); - return 0; } void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev) diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c deleted file mode 100644 index fe3b752cf6cdc3a8ed4785be13d4ce51afceb81d..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2015 Red Hat, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "virtgpu_drv.h" - -static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev) -{ - struct apertures_struct *ap; - bool primary; - - ap = alloc_apertures(1); - if (!ap) - return; - - ap->ranges[0].base = pci_resource_start(pci_dev, 0); - ap->ranges[0].size = pci_resource_len(pci_dev, 0); - - primary = pci_dev->resource[PCI_ROM_RESOURCE].flags - & IORESOURCE_ROM_SHADOW; - - drm_fb_helper_remove_conflicting_framebuffers(ap, "virtiodrmfb", primary); - - kfree(ap); -} - -int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) -{ - struct drm_device *dev; - int ret; - - dev = drm_dev_alloc(driver, &vdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); - vdev->priv = dev; - - if (strcmp(vdev->dev.parent->bus->name, "pci") == 0) { - struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); - const char *pname = dev_name(&pdev->dev); - bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; - char unique[20]; - - DRM_INFO("pci: %s detected at %s\n", - vga ? "virtio-vga" : "virtio-gpu-pci", - pname); - dev->pdev = pdev; - if (vga) - virtio_pci_kick_out_firmware_fb(pdev); - - /* - * Normally the drm_dev_set_unique() call is done by core DRM. - * The following comment covers, why virtio cannot rely on it. - * - * Unlike the other virtual GPU drivers, virtio abstracts the - * underlying bus type by using struct virtio_device. - * - * Hence the dev_is_pci() check, used in core DRM, will fail - * and the unique returned will be the virtio_device "virtio0", - * while a "pci:..." one is required. - * - * A few other ideas were considered: - * - Extend the dev_is_pci() check [in drm_set_busid] to - * consider virtio. - * Seems like a bigger hack than what we have already. - * - * - Point drm_device::dev to the parent of the virtio_device - * Semantic changes: - * * Using the wrong device for i2c, framebuffer_alloc and - * prime import. - * Visual changes: - * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, - * will print the wrong information. - * - * We could address the latter issues, by introducing - * drm_device::bus_dev, ... which would be used solely for this. - * - * So for the moment keep things as-is, with a bulky comment - * for the next person who feels like removing this - * drm_dev_set_unique() quirk. - */ - snprintf(unique, sizeof(unique), "pci:%s", pname); - ret = drm_dev_set_unique(dev, unique); - if (ret) - goto err_free; - - } - - ret = drm_dev_register(dev, 0); - if (ret) - goto err_free; - - return 0; - -err_free: - drm_dev_unref(dev); - return ret; -} diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 9f592f9353a69f0313f0815aa79b1cc03c3567b3..a58e9d52c07e111c7f36dadf95a75aa34dd93c94 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -40,21 +40,118 @@ static int virtio_gpu_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, virtio_gpu_modeset, int, 0400); +static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev) +{ + struct apertures_struct *ap; + bool primary; + + ap = alloc_apertures(1); + if (!ap) + return; + + ap->ranges[0].base = pci_resource_start(pci_dev, 0); + ap->ranges[0].size = pci_resource_len(pci_dev, 0); + + primary = pci_dev->resource[PCI_ROM_RESOURCE].flags + & IORESOURCE_ROM_SHADOW; + + drm_fb_helper_remove_conflicting_framebuffers(ap, "virtiodrmfb", primary); + + kfree(ap); +} + +static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vdev) +{ + struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); + const char *pname = dev_name(&pdev->dev); + bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; + char unique[20]; + + DRM_INFO("pci: %s detected at %s\n", + vga ? "virtio-vga" : "virtio-gpu-pci", + pname); + dev->pdev = pdev; + if (vga) + virtio_pci_kick_out_firmware_fb(pdev); + + /* + * Normally the drm_dev_set_unique() call is done by core DRM. + * The following comment covers, why virtio cannot rely on it. + * + * Unlike the other virtual GPU drivers, virtio abstracts the + * underlying bus type by using struct virtio_device. + * + * Hence the dev_is_pci() check, used in core DRM, will fail + * and the unique returned will be the virtio_device "virtio0", + * while a "pci:..." one is required. + * + * A few other ideas were considered: + * - Extend the dev_is_pci() check [in drm_set_busid] to + * consider virtio. + * Seems like a bigger hack than what we have already. + * + * - Point drm_device::dev to the parent of the virtio_device + * Semantic changes: + * * Using the wrong device for i2c, framebuffer_alloc and + * prime import. + * Visual changes: + * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, + * will print the wrong information. + * + * We could address the latter issues, by introducing + * drm_device::bus_dev, ... which would be used solely for this. + * + * So for the moment keep things as-is, with a bulky comment + * for the next person who feels like removing this + * drm_dev_set_unique() quirk. + */ + snprintf(unique, sizeof(unique), "pci:%s", pname); + return drm_dev_set_unique(dev, unique); +} + static int virtio_gpu_probe(struct virtio_device *vdev) { + struct drm_device *dev; + int ret; + if (vgacon_text_force() && virtio_gpu_modeset == -1) return -EINVAL; if (virtio_gpu_modeset == 0) return -EINVAL; - return drm_virtio_init(&driver, vdev); + dev = drm_dev_alloc(&driver, &vdev->dev); + if (IS_ERR(dev)) + return PTR_ERR(dev); + vdev->priv = dev; + + if (!strcmp(vdev->dev.parent->bus->name, "pci")) { + ret = virtio_gpu_pci_quirk(dev, vdev); + if (ret) + goto err_free; + } + + ret = virtio_gpu_init(dev); + if (ret) + goto err_free; + + ret = drm_dev_register(dev, 0); + if (ret) + goto err_free; + + return 0; + +err_free: + drm_dev_unref(dev); + return ret; } static void virtio_gpu_remove(struct virtio_device *vdev) { struct drm_device *dev = vdev->priv; + drm_dev_unregister(dev); + virtio_gpu_deinit(dev); drm_put_dev(dev); } @@ -81,6 +178,8 @@ static unsigned int features[] = { VIRTIO_GPU_F_VIRGL, #endif VIRTIO_GPU_F_EDID, + VIRTIO_GPU_F_RESOURCE_BLOB, + VIRTIO_GPU_F_HOST_VISIBLE, }; static struct virtio_driver virtio_gpu_driver = { .feature_table = features, @@ -116,8 +215,6 @@ static const struct file_operations virtio_gpu_driver_fops = { static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, - .load = virtio_gpu_driver_load, - .unload = virtio_gpu_driver_unload, .open = virtio_gpu_driver_open, .postclose = virtio_gpu_driver_postclose, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 05936432632b66ae893b2a85ce0d578c1cd8706c..9db4d6381bf1a10b4fbf563977ebbbb610f58045 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -50,9 +50,6 @@ #define DRIVER_MINOR 1 #define DRIVER_PATCHLEVEL 0 -/* virtgpu_drm_bus.c */ -int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev); - struct virtio_gpu_object_params { uint32_t format; uint32_t width; @@ -61,6 +58,8 @@ struct virtio_gpu_object_params { bool dumb; /* 3d */ bool virgl; + bool blob; + uint32_t blob_mem; uint32_t target; uint32_t bind; uint32_t depth; @@ -74,15 +73,24 @@ struct virtio_gpu_object { struct drm_gem_object gem_base; uint32_t hw_res_handle; + bool create_callback_done; + /* These variables are only valid if create_callback_done is true */ + uint32_t num_planes; + uint64_t format_modifier; + uint32_t strides[4]; + uint32_t offsets[4]; + struct sg_table *pages; uint32_t mapped; void *vmap; bool dumb; + bool blob; struct ttm_place placement_code; struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; bool created; + uint32_t blob_mem; }; #define gem_to_virtio_gpu_obj(gobj) \ container_of((gobj), struct virtio_gpu_object, gem_base) @@ -224,12 +232,22 @@ struct virtio_gpu_device { bool has_virgl_3d; bool has_edid; + bool has_resource_blob; + bool has_host_visible; struct work_struct config_changed_work; struct virtio_gpu_drv_capset *capsets; uint32_t num_capsets; struct list_head cap_cache; + + /* coherent memory */ + int cbar; + unsigned long caddr; + unsigned long csize; + + struct idr request_idr; + spinlock_t request_idr_lock; }; struct virtio_gpu_fpriv { @@ -237,15 +255,15 @@ struct virtio_gpu_fpriv { }; /* virtio_ioctl.c */ -#define DRM_VIRTIO_NUM_IOCTLS 10 +#define DRM_VIRTIO_NUM_IOCTLS 13 extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; int virtio_gpu_object_list_validate(struct ww_acquire_ctx *ticket, struct list_head *head); void virtio_gpu_unref_list(struct list_head *head); /* virtio_kms.c */ -int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags); -void virtio_gpu_driver_unload(struct drm_device *dev); +int virtio_gpu_init(struct drm_device *dev); +void virtio_gpu_deinit(struct drm_device *dev); int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file); void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file); @@ -342,11 +360,28 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, uint64_t offset, uint32_t level, struct virtio_gpu_box *box, struct virtio_gpu_fence *fence); -void +int virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, struct virtio_gpu_object_params *params, struct virtio_gpu_fence *fence); + +void +virtio_gpu_cmd_resource_create_blob(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object *bo, + uint32_t ctx_id, uint32_t blob_mem, + uint32_t blob_flags, uint64_t blob_id, + uint64_t size, uint32_t nents, + struct virtio_gpu_mem_entry *ents); + +void virtio_gpu_cmd_map(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object *bo, + uint64_t offset, + struct virtio_gpu_fence *fence); + +void virtio_gpu_cmd_unmap(struct virtio_gpu_device *vgdev, + uint32_t resource_id); + void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); void virtio_gpu_fence_ack(struct virtqueue *vq); @@ -359,7 +394,7 @@ int virtio_gpu_framebuffer_init(struct drm_device *dev, struct virtio_gpu_framebuffer *vgfb, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); -int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); +void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); /* virtio_gpu_plane.c */ diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 402d01ed255e9a6729e531e84dfc5b96cec6b986..4235e142ff84c10e9bc097c70ecd51239f265464 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -25,10 +25,13 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include +#include + #include #include #include -#include #include "virtgpu_drv.h" @@ -258,6 +261,12 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, case VIRTGPU_PARAM_CAPSET_QUERY_FIX: value = 1; break; + case VIRTGPU_PARAM_RESOURCE_BLOB: + value = vgdev->has_resource_blob == true ? 1 : 0; + break; + case VIRTGPU_PARAM_HOST_VISIBLE: + value = vgdev->has_host_visible == true ? 1 : 0; + break; default: return -EINVAL; } @@ -334,9 +343,11 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, static int virtio_gpu_resource_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct virtio_gpu_device *vgdev = dev->dev_private; struct drm_virtgpu_resource_info *ri = data; struct drm_gem_object *gobj = NULL; struct virtio_gpu_object *qobj = NULL; + int ret = 0; gobj = drm_gem_object_lookup(file_priv, ri->bo_handle); if (gobj == NULL) @@ -344,10 +355,30 @@ static int virtio_gpu_resource_info_ioctl(struct drm_device *dev, void *data, qobj = gem_to_virtio_gpu_obj(gobj); - ri->size = qobj->gem_base.size; ri->res_handle = qobj->hw_res_handle; + ri->size = qobj->gem_base.size; + + if (!qobj->create_callback_done) { + ret = wait_event_interruptible(vgdev->resp_wq, + qobj->create_callback_done); + if (ret) + goto out; + } + + if (qobj->num_planes) { + int i; + + ri->num_planes = qobj->num_planes; + for (i = 0; i < qobj->num_planes; i++) { + ri->strides[i] = qobj->strides[i]; + ri->offsets[i] = qobj->offsets[i]; + } + } + + ri->format_modifier = qobj->format_modifier; +out: drm_gem_object_put_unlocked(gobj); - return 0; + return ret; } static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev, @@ -550,6 +581,134 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, return 0; } +static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file) +{ + uint32_t device_blob_mem = 0; + int ret, si, nents; + uint32_t handle = 0; + struct scatterlist *sg; + struct virtio_gpu_object *obj; + struct virtio_gpu_fence *fence; + struct virtio_gpu_mem_entry *ents; + struct drm_virtgpu_resource_create_blob *rc_blob = data; + struct virtio_gpu_object_params params = { 0 }; + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev); + bool mappable = rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_MAPPABLE; + bool has_guest = (rc_blob->blob_mem == VIRTGPU_BLOB_MEM_GUEST || + rc_blob->blob_mem == VIRTGPU_BLOB_MEM_HOST_GUEST); + + params.size = rc_blob->size; + params.blob_mem = rc_blob->blob_mem; + params.blob = true; + + if (rc_blob->blob_mem == VIRTGPU_BLOB_MEM_GUEST) + device_blob_mem = VIRTIO_GPU_BLOB_MEM_GUEST; + + if (vgdev->has_virgl_3d) { + if (rc_blob->blob_mem == VIRTGPU_BLOB_MEM_HOST) + device_blob_mem = VIRTIO_GPU_BLOB_MEM_HOST3D; + else if (rc_blob->blob_mem == VIRTGPU_BLOB_MEM_HOST_GUEST) + device_blob_mem = VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST; + } else { + if (rc_blob->blob_mem == VIRTGPU_BLOB_MEM_HOST) + device_blob_mem = VIRTIO_GPU_BLOB_MEM_HOSTSYS; + else if (rc_blob->blob_mem == VIRTGPU_BLOB_MEM_HOST_GUEST) + device_blob_mem = VIRTIO_GPU_BLOB_MEM_HOSTSYS_GUEST; + } + + if (rc_blob->cmd_size) { + void *buf; + void __user *cmd = u64_to_user_ptr(rc_blob->cmd); + + buf = kzalloc(rc_blob->cmd_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, cmd, rc_blob->cmd_size)) { + kfree(buf); + return -EFAULT; + } + + virtio_gpu_cmd_submit(vgdev, buf, rc_blob->cmd_size, + vfpriv->ctx_id, NULL); + } + + obj = virtio_gpu_alloc_object(dev, ¶ms, NULL); + if (IS_ERR(obj)) + return PTR_ERR(obj); + + if (!obj->pages) { + ret = virtio_gpu_object_get_sg_table(vgdev, obj); + if (ret) + goto err_free_obj; + } + + if (!has_guest) { + nents = 0; + } else if (use_dma_api) { + obj->mapped = dma_map_sg(vgdev->vdev->dev.parent, + obj->pages->sgl, obj->pages->nents, + DMA_TO_DEVICE); + nents = obj->mapped; + } else { + nents = obj->pages->nents; + } + + ents = kzalloc(nents * sizeof(struct virtio_gpu_mem_entry), GFP_KERNEL); + if (has_guest) { + for_each_sg(obj->pages->sgl, sg, nents, si) { + ents[si].addr = cpu_to_le64(use_dma_api + ? sg_dma_address(sg) + : sg_phys(sg)); + ents[si].length = cpu_to_le32(sg->length); + ents[si].padding = 0; + } + } + + fence = virtio_gpu_fence_alloc(vgdev); + if (!fence) { + ret = -ENOMEM; + goto err_free_obj; + } + + virtio_gpu_cmd_resource_create_blob(vgdev, obj, vfpriv->ctx_id, + device_blob_mem, + rc_blob->blob_flags, + rc_blob->blob_id, + rc_blob->size, + nents, ents); + + ret = drm_gem_handle_create(file, &obj->gem_base, &handle); + if (ret) + goto err_fence_put; + + if (!has_guest && mappable) + virtio_gpu_cmd_map(vgdev, obj, obj->tbo.offset, fence); + + /* + * No need to call virtio_gpu_object_reserve since the buffer is not + * being used for ttm validation and no other processes can access + * the reservation object at this point. + */ + reservation_object_add_excl_fence(obj->tbo.resv, &fence->f); + + dma_fence_put(&fence->f); + drm_gem_object_put_unlocked(&obj->gem_base); + + rc_blob->res_handle = obj->hw_res_handle; + rc_blob->bo_handle = handle; + return 0; + +err_fence_put: + dma_fence_put(&fence->f); +err_free_obj: + drm_gem_object_release(&obj->gem_base); + return ret; +} + struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), @@ -582,4 +741,8 @@ struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE_BLOB, + virtio_gpu_resource_create_blob_ioctl, + DRM_RENDER_ALLOW) }; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index d0f54b81eabaaa149c79b67d113d90b58b801185..b96a19005fb54a9c1198ff4307b32f5edb8b80dc 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -23,6 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -127,7 +128,7 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, vgdev->num_capsets = num_capsets; } -int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) +int virtio_gpu_init(struct drm_device *dev) { static vq_callback_t *callbacks[] = { virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack @@ -157,6 +158,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) idr_init(&vgdev->ctx_id_idr); spin_lock_init(&vgdev->resource_idr_lock); idr_init(&vgdev->resource_idr); + spin_lock_init(&vgdev->request_idr_lock); + idr_init(&vgdev->request_idr); init_waitqueue_head(&vgdev->resp_wq); virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func); virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func); @@ -181,6 +184,32 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) DRM_INFO("EDID support available.\n"); } + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_BLOB)) { + vgdev->cbar = 4; + vgdev->caddr = pci_resource_start(dev->pdev, vgdev->cbar); + vgdev->csize = pci_resource_len(dev->pdev, vgdev->cbar); + ret = pci_request_region( + dev->pdev, + vgdev->cbar, + "virtio-gpu-coherent"); + if (ret != 0) { + DRM_WARN("Cannot request coherent memory bar\n"); + } else { + DRM_INFO("coherent host resources enabled\n"); + DRM_INFO( + "using %s bar %d, at 0x%lx, size %ld MB\n", + dev_name(&dev->pdev->dev), + vgdev->cbar, + vgdev->caddr, + vgdev->csize >> 20); + vgdev->has_host_visible = true; + } + + vgdev->has_resource_blob = true; + DRM_INFO("resource_v2: %u, host visible %u\n", + vgdev->has_resource_blob, vgdev->has_host_visible); + } + ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); if (ret) { DRM_ERROR("failed to find virt queues\n"); @@ -216,9 +245,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) num_capsets, &num_capsets); DRM_INFO("number of cap sets: %d\n", num_capsets); - ret = virtio_gpu_modeset_init(vgdev); - if (ret) - goto err_modeset; + virtio_gpu_modeset_init(vgdev); virtio_device_ready(vgdev->vdev); vgdev->vqs_ready = true; @@ -235,7 +262,6 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) return 0; -err_modeset: err_scanouts: virtio_gpu_ttm_fini(vgdev); err_ttm: @@ -257,7 +283,7 @@ static void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev) } } -void virtio_gpu_driver_unload(struct drm_device *dev) +void virtio_gpu_deinit(struct drm_device *dev) { struct virtio_gpu_device *vgdev = dev->dev_private; diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index e88c00367782e509c035962f1aff775c62b769f6..e442928d2848b3e829c95d1fc6bc8381631d8928 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -23,33 +23,56 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include + #include #include "virtgpu_drv.h" +#include + +static int virtio_gpu_virglrenderer_workaround = 1; +module_param_named(virglhack, virtio_gpu_virglrenderer_workaround, int, 0400); static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev, uint32_t *resid) { - int handle; + if (virtio_gpu_virglrenderer_workaround) { + /* + * Hack to avoid re-using resource IDs. + * + * virglrenderer versions up to (and including) 0.7.0 + * can't deal with that. virglrenderer commit + * "f91a9dd35715 Fix unlinking resources from hash + * table." (Feb 2019) fixes the bug. + */ + static atomic_t seqno = ATOMIC_INIT(0); + int handle = atomic_inc_return(&seqno); + *resid = handle; + } else { + int handle; - idr_preload(GFP_KERNEL); - spin_lock(&vgdev->resource_idr_lock); - handle = idr_alloc(&vgdev->resource_idr, NULL, 1, 0, GFP_NOWAIT); - spin_unlock(&vgdev->resource_idr_lock); - idr_preload_end(); + idr_preload(GFP_KERNEL); + spin_lock(&vgdev->resource_idr_lock); + handle = idr_alloc(&vgdev->resource_idr, NULL, 1, 0, + GFP_NOWAIT); + spin_unlock(&vgdev->resource_idr_lock); + idr_preload_end(); - if (handle < 0) - return handle; + if (handle < 0) + return handle; - *resid = handle; + *resid = handle; + } return 0; } static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id) { - spin_lock(&vgdev->resource_idr_lock); - idr_remove(&vgdev->resource_idr, id); - spin_unlock(&vgdev->resource_idr_lock); + if (!virtio_gpu_virglrenderer_workaround) { + spin_lock(&vgdev->resource_idr_lock); + idr_remove(&vgdev->resource_idr, id); + spin_unlock(&vgdev->resource_idr_lock); + } } static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) @@ -71,17 +94,49 @@ static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) kfree(bo); } +// define internally for testing purposes +#define VIRTGPU_BLOB_MEM_CACHE_MASK 0xf000 +#define VIRTGPU_BLOB_MEM_CACHE_CACHED 0x1000 +#define VIRTGPU_BLOB_MEM_CACHE_UNCACHED 0x2000 +#define VIRTGPU_BLOB_MEM_CACHE_WC 0x3000 + static void virtio_gpu_init_ttm_placement(struct virtio_gpu_object *vgbo) { u32 c = 1; + u32 ttm_caching_flags = 0; + + u32 cache_type = (vgbo->blob_mem & VIRTGPU_BLOB_MEM_CACHE_MASK); + bool has_guest = (vgbo->blob_mem == VIRTGPU_BLOB_MEM_GUEST || + vgbo->blob_mem == VIRTGPU_BLOB_MEM_HOST_GUEST); vgbo->placement.placement = &vgbo->placement_code; vgbo->placement.busy_placement = &vgbo->placement_code; vgbo->placement_code.fpfn = 0; vgbo->placement_code.lpfn = 0; - vgbo->placement_code.flags = - TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT | - TTM_PL_FLAG_NO_EVICT; + + switch (cache_type) { + case VIRTGPU_BLOB_MEM_CACHE_CACHED: + ttm_caching_flags = TTM_PL_FLAG_CACHED; + break; + case VIRTGPU_BLOB_MEM_CACHE_WC: + ttm_caching_flags = TTM_PL_FLAG_WC; + break; + case VIRTGPU_BLOB_MEM_CACHE_UNCACHED: + ttm_caching_flags = TTM_PL_FLAG_UNCACHED; + break; + default: + ttm_caching_flags = TTM_PL_MASK_CACHING; + } + + if (!has_guest && vgbo->blob) { + vgbo->placement_code.flags = + ttm_caching_flags | TTM_PL_FLAG_VRAM | + TTM_PL_FLAG_NO_EVICT; + } else { + vgbo->placement_code.flags = + TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT | + TTM_PL_FLAG_NO_EVICT; + } vgbo->placement.num_placement = c; vgbo->placement.num_busy_placement = c; @@ -117,10 +172,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, return ret; } bo->dumb = params->dumb; + bo->blob = params->blob; + bo->blob_mem = params->blob_mem; if (params->virgl) { virtio_gpu_cmd_resource_create_3d(vgdev, bo, params, fence); - } else { + } else if (params->dumb) { virtio_gpu_cmd_create_resource(vgdev, bo, params, fence); } diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index aff33b9b47dab2b3eaa14600e38595bbe24daf14..6c1f02b4f17c5504d1cc9ca7b0756a3ef20ebc89 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -185,6 +185,12 @@ static int virtio_gpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_CACHED; break; + case TTM_PL_VRAM: + man->func = &ttm_bo_manager_func; + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + break; default: DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); return -EINVAL; @@ -216,6 +222,7 @@ static int virtio_gpu_verify_access(struct ttm_buffer_object *bo, static int virtio_gpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { + struct virtio_gpu_device *vgdev = virtio_gpu_get_vgdev(bdev); struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; mem->bus.addr = NULL; @@ -229,8 +236,18 @@ static int virtio_gpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, case TTM_PL_SYSTEM: case TTM_PL_TT: /* system memory */ + mem->bus.offset = 0; + mem->bus.base = 0; + mem->bus.is_iomem = false; + return 0; + case TTM_PL_VRAM: + /* coherent memory (pci bar) */ + mem->bus.offset = mem->start << PAGE_SHIFT; + mem->bus.base = vgdev->caddr; + mem->bus.is_iomem = true; return 0; default: + DRM_ERROR("Unsupported memory type %u\n", mem->mem_type); return -EINVAL; } return 0; @@ -246,33 +263,54 @@ static void virtio_gpu_ttm_io_mem_free(struct ttm_bo_device *bdev, */ struct virtio_gpu_ttm_tt { struct ttm_dma_tt ttm; - struct virtio_gpu_device *vgdev; - u64 offset; + struct virtio_gpu_object *obj; }; +static int virtio_gpu_ttm_vram_bind(struct ttm_tt *ttm, + struct ttm_mem_reg *bo_mem) +{ + return 0; +} + +static int virtio_gpu_ttm_vram_unbind(struct ttm_tt *ttm) +{ + struct virtio_gpu_ttm_tt *gtt = + container_of(ttm, struct virtio_gpu_ttm_tt, ttm.ttm); + struct virtio_gpu_device *vgdev = + virtio_gpu_get_vgdev(gtt->obj->tbo.bdev); + struct virtio_gpu_object *obj = gtt->obj; + + virtio_gpu_cmd_unmap(vgdev, obj->hw_res_handle); + return 0; +} + static int virtio_gpu_ttm_backend_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) { - struct virtio_gpu_ttm_tt *gtt = (void *)ttm; - - gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); - if (!ttm->num_pages) - WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", - ttm->num_pages, bo_mem, ttm); + struct virtio_gpu_ttm_tt *gtt = + container_of(ttm, struct virtio_gpu_ttm_tt, ttm.ttm); + struct virtio_gpu_device *vgdev = + virtio_gpu_get_vgdev(gtt->obj->tbo.bdev); - /* Not implemented */ + virtio_gpu_object_attach(vgdev, gtt->obj, NULL); return 0; } static int virtio_gpu_ttm_backend_unbind(struct ttm_tt *ttm) { - /* Not implemented */ + struct virtio_gpu_ttm_tt *gtt = + container_of(ttm, struct virtio_gpu_ttm_tt, ttm.ttm); + struct virtio_gpu_device *vgdev = + virtio_gpu_get_vgdev(gtt->obj->tbo.bdev); + + virtio_gpu_object_detach(vgdev, gtt->obj); return 0; } -static void virtio_gpu_ttm_backend_destroy(struct ttm_tt *ttm) +static void virtio_gpu_ttm_tt_destroy(struct ttm_tt *ttm) { - struct virtio_gpu_ttm_tt *gtt = (void *)ttm; + struct virtio_gpu_ttm_tt *gtt = + container_of(ttm, struct virtio_gpu_ttm_tt, ttm.ttm); ttm_dma_tt_fini(>t->ttm); kfree(gtt); @@ -281,7 +319,13 @@ static void virtio_gpu_ttm_backend_destroy(struct ttm_tt *ttm) static struct ttm_backend_func virtio_gpu_backend_func = { .bind = &virtio_gpu_ttm_backend_bind, .unbind = &virtio_gpu_ttm_backend_unbind, - .destroy = &virtio_gpu_ttm_backend_destroy, + .destroy = &virtio_gpu_ttm_tt_destroy, +}; + +static struct ttm_backend_func virtio_gpu_vram_func = { + .bind = &virtio_gpu_ttm_vram_bind, + .unbind = &virtio_gpu_ttm_vram_unbind, + .destroy = &virtio_gpu_ttm_tt_destroy, }; static int virtio_gpu_ttm_tt_populate(struct ttm_tt *ttm) @@ -297,72 +341,43 @@ static void virtio_gpu_ttm_tt_unpopulate(struct ttm_tt *ttm) ttm_pool_unpopulate(ttm); } -static struct ttm_tt *virtio_gpu_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, - uint32_t page_flags, - struct page *dummy_read_page) +static struct ttm_tt *virtio_gpu_ttm_tt_create2(struct ttm_buffer_object *bo, + uint32_t page_flags, + struct page *dummy_read_page) { + unsigned long size = bo->num_pages << PAGE_SHIFT; struct virtio_gpu_device *vgdev; + struct virtio_gpu_object *obj; struct virtio_gpu_ttm_tt *gtt; + uint32_t has_guest; + + vgdev = virtio_gpu_get_vgdev(bo->bdev); + obj = container_of(bo, struct virtio_gpu_object, tbo); - vgdev = virtio_gpu_get_vgdev(bdev); gtt = kzalloc(sizeof(struct virtio_gpu_ttm_tt), GFP_KERNEL); if (gtt == NULL) return NULL; - gtt->ttm.ttm.func = &virtio_gpu_backend_func; - gtt->vgdev = vgdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags, - dummy_read_page)) { - kfree(gtt); - return NULL; - } - return >t->ttm.ttm; -} - -static void virtio_gpu_move_null(struct ttm_buffer_object *bo, - struct ttm_mem_reg *new_mem) -{ - struct ttm_mem_reg *old_mem = &bo->mem; - - BUG_ON(old_mem->mm_node != NULL); - *old_mem = *new_mem; - new_mem->mm_node = NULL; -} - -static int virtio_gpu_bo_move(struct ttm_buffer_object *bo, - bool evict, bool interruptible, - bool no_wait_gpu, - struct ttm_mem_reg *new_mem) -{ - int ret; - - ret = ttm_bo_wait(bo, interruptible, no_wait_gpu); - if (ret) - return ret; - - virtio_gpu_move_null(bo, new_mem); - return 0; -} - -static void virtio_gpu_bo_move_notify(struct ttm_buffer_object *tbo, - bool evict, - struct ttm_mem_reg *new_mem) -{ - struct virtio_gpu_object *bo; - struct virtio_gpu_device *vgdev; - - bo = container_of(tbo, struct virtio_gpu_object, tbo); - vgdev = (struct virtio_gpu_device *)bo->gem_base.dev->dev_private; - - if (!new_mem || (new_mem->placement & TTM_PL_FLAG_SYSTEM)) { - if (bo->hw_res_handle) - virtio_gpu_object_detach(vgdev, bo); - - } else if (new_mem->placement & TTM_PL_FLAG_TT) { - if (bo->hw_res_handle) { - virtio_gpu_object_attach(vgdev, bo, NULL); + gtt->obj = obj; + has_guest = (obj->blob_mem == VIRTGPU_BLOB_MEM_GUEST || + obj->blob_mem == VIRTGPU_BLOB_MEM_HOST_GUEST); + + if (!has_guest && obj->blob) { + gtt->ttm.ttm.func = &virtio_gpu_vram_func; + if (ttm_tt_init(>t->ttm.ttm, bo->bdev, size, page_flags, + dummy_read_page)) { + kfree(gtt); + return NULL; + } + } else { + gtt->ttm.ttm.func = &virtio_gpu_backend_func; + if (ttm_dma_tt_init(>t->ttm, bo->bdev, size, page_flags, + dummy_read_page)) { + kfree(gtt); + return NULL; } } + + return >t->ttm.ttm; } static void virtio_gpu_bo_swap_notify(struct ttm_buffer_object *tbo) @@ -376,19 +391,17 @@ static void virtio_gpu_bo_swap_notify(struct ttm_buffer_object *tbo) } static struct ttm_bo_driver virtio_gpu_bo_driver = { - .ttm_tt_create = &virtio_gpu_ttm_tt_create, + .ttm_tt_create2 = &virtio_gpu_ttm_tt_create2, .ttm_tt_populate = &virtio_gpu_ttm_tt_populate, .ttm_tt_unpopulate = &virtio_gpu_ttm_tt_unpopulate, .invalidate_caches = &virtio_gpu_invalidate_caches, .init_mem_type = &virtio_gpu_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = &virtio_gpu_evict_flags, - .move = &virtio_gpu_bo_move, .verify_access = &virtio_gpu_verify_access, .io_mem_reserve = &virtio_gpu_ttm_io_mem_reserve, .io_mem_free = &virtio_gpu_ttm_io_mem_free, .io_mem_pfn = ttm_bo_default_io_mem_pfn, - .move_notify = &virtio_gpu_bo_move_notify, .swap_notify = &virtio_gpu_bo_swap_notify, }; @@ -415,6 +428,15 @@ int virtio_gpu_ttm_init(struct virtio_gpu_device *vgdev) DRM_ERROR("Failed initializing GTT heap.\n"); goto err_mm_init; } + + if (vgdev->has_host_visible) { + r = ttm_bo_init_mm(&vgdev->mman.bdev, TTM_PL_VRAM, + vgdev->csize >> PAGE_SHIFT); + if (r) { + DRM_ERROR("Failed initializing VRAM heap.\n"); + goto err_mm_init; + } + } return 0; err_mm_init: diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index feddc29b3f2c163c8132e6f7e219ef1f9676ed7e..420db70018dc89346ecdb12b48bac0ee4bdb46f7 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -856,7 +856,45 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev, virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); } -void +static void virtio_gpu_cmd_resource_create_cb(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + struct virtio_gpu_resp_resource_plane_info *resp = + (struct virtio_gpu_resp_resource_plane_info *)vbuf->resp_buf; + struct virtio_gpu_object *obj = + (struct virtio_gpu_object *)vbuf->data_buf; + uint32_t resp_type = le32_to_cpu(resp->hdr.type); + int i; + + /* + * Keeps the data_buf, which points to this virtio_gpu_object, from + * getting kfree'd after this cb returns. + */ + vbuf->data_buf = NULL; + + switch (resp_type) { + case VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO: + case VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO_LEGACY: + break; + default: + goto finish_pending; + } + + obj->num_planes = le32_to_cpu(resp->num_planes); + obj->format_modifier = le64_to_cpu(resp->format_modifier); + + for (i = 0; i < obj->num_planes; i++) { + obj->strides[i] = le32_to_cpu(resp->strides[i]); + obj->offsets[i] = le32_to_cpu(resp->offsets[i]); + } + +finish_pending: + obj->create_callback_done = true; + drm_gem_object_put_unlocked(&obj->gem_base); + wake_up_all(&vgdev->resp_wq); +} + +int virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, struct virtio_gpu_object_params *params, @@ -864,8 +902,15 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, { struct virtio_gpu_resource_create_3d *cmd_p; struct virtio_gpu_vbuffer *vbuf; + struct virtio_gpu_resp_resource_plane_info *resp_buf; - cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + resp_buf = kzalloc(sizeof(*resp_buf), GFP_KERNEL); + if (!resp_buf) + return -ENOMEM; + + cmd_p = virtio_gpu_alloc_cmd_resp(vgdev, + virtio_gpu_cmd_resource_create_cb, &vbuf, sizeof(*cmd_p), + sizeof(struct virtio_gpu_resp_resource_plane_info), resp_buf); memset(cmd_p, 0, sizeof(*cmd_p)); cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_3D); @@ -882,8 +927,15 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, cmd_p->nr_samples = cpu_to_le32(params->nr_samples); cmd_p->flags = cpu_to_le32(params->flags); + /* Reuse the data_buf pointer for the object pointer. */ + vbuf->data_buf = bo; + bo->create_callback_done = false; + drm_gem_object_get(&bo->gem_base); + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); bo->created = true; + + return 0; } void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, @@ -966,6 +1018,9 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, struct scatterlist *sg; int si, nents; + if (obj->blob) + return 0; + if (WARN_ON_ONCE(!obj->created)) return -EINVAL; @@ -1041,3 +1096,83 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, memcpy(cur_p, &output->cursor, sizeof(output->cursor)); virtio_gpu_queue_cursor(vgdev, vbuf); } + +static void virtio_gpu_cmd_resource_map_cb(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + /* + * No-op for v5.4. + */ +} + +void virtio_gpu_cmd_map(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object *bo, + uint64_t offset, + struct virtio_gpu_fence *fence) +{ + struct virtio_gpu_resource_map *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + struct virtio_gpu_resp_map_info *resp_buf; + + resp_buf = kzalloc(sizeof(*resp_buf), GFP_KERNEL); + if (!resp_buf) { + DRM_ERROR("allocation failure\n"); + return; + } + + cmd_p = virtio_gpu_alloc_cmd_resp(vgdev, + virtio_gpu_cmd_resource_map_cb, &vbuf, sizeof(*cmd_p), + sizeof(struct virtio_gpu_resp_map_info), resp_buf); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_MAP); + cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle); + cmd_p->offset = offset; + + virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); +} + +void virtio_gpu_cmd_unmap(struct virtio_gpu_device *vgdev, + uint32_t resource_id) +{ + struct virtio_gpu_resource_unmap *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_UNMAP); + cmd_p->resource_id = cpu_to_le32(resource_id); + + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +} + +void +virtio_gpu_cmd_resource_create_blob(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object *bo, + uint32_t ctx_id, uint32_t blob_mem, + uint32_t blob_flags, uint64_t blob_id, + uint64_t size, uint32_t nents, + struct virtio_gpu_mem_entry *ents) +{ + struct virtio_gpu_resource_create_blob *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB); + cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id); + cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle); + cmd_p->blob_mem = cpu_to_le32(blob_mem); + cmd_p->blob_flags = cpu_to_le32(blob_flags); + cmd_p->blob_id = cpu_to_le64(blob_id); + cmd_p->size = cpu_to_le64(size); + cmd_p->nr_entries = cpu_to_le32(nents); + + vbuf->data_buf = ents; + vbuf->data_size = sizeof(*ents) * nents; + + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + bo->created = true; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 36c7b6c839c0dd230752cba96c348b40e2c65c65..738ad2fc79a258a3719fb972b92cedeedda7cd0b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -210,8 +210,10 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, cres->hash.key = user_key | (res_type << 24); ret = drm_ht_insert_item(&man->resources, &cres->hash); - if (unlikely(ret != 0)) + if (unlikely(ret != 0)) { + kfree(cres); goto out_invalid_key; + } cres->state = VMW_CMDBUF_RES_ADD; cres->res = vmw_resource_reference(res); diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index 19b97a5572249efc7505849bf211ba292889c085..d0751f2987757efc9728badc47002baa1a2b05f5 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -1076,6 +1076,7 @@ /* GPUCC registers */ #define A6XX_GPU_CC_GX_GDSCR 0x24403 #define A6XX_GPU_CC_GX_DOMAIN_MISC 0x24542 +#define A6XX_GPU_CC_CX_GDSCR 0x2441B /* GPU RSC sequencer registers */ #define A6XX_RSCC_PDC_SEQ_START_ADDR 0x23408 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index e3fd8f3acdbbb222b39807f28c0d4ea08e47938e..c1ed012860a600029becf34a30a816c26d9bbc1b 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1814,10 +1814,10 @@ static void _set_secvid(struct kgsl_device *device) adreno_writereg64(adreno_dev, ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE, ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI, - KGSL_IOMMU_SECURE_BASE(&device->mmu)); + device->mmu.secure_base); adreno_writereg(adreno_dev, ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE, - KGSL_IOMMU_SECURE_SIZE); + device->mmu.secure_size); if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_SECVID_SET_ONCE)) set = true; } @@ -4178,6 +4178,19 @@ static int adreno_resume_device(struct kgsl_device *device, return 0; } +u32 adreno_get_ucode_version(const u32 *data) +{ + u32 version; + + version = data[1]; + + if ((version & 0xf) != 0xa) + return version; + + version &= ~0xfff; + return version | ((data[3] & 0xfff000) >> 12); +} + static const struct kgsl_functable adreno_functable = { /* Mandatory functions */ .regread = adreno_regread, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 905dd4009a7e723c87007bfbab278fbc886d7e77..1cc4fc05fac5c1facfdea0ef4980d3c2cd19a0db 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -289,8 +289,8 @@ enum adreno_preempt_states { /** * struct adreno_preemption * @state: The current state of preemption - * @counters: Memory descriptor for the memory where the GPU writes the - * preemption counters on switch + * @scratch: Memory descriptor for the memory where the GPU writes the + * current ctxt record address and preemption counters on switch * @timer: A timer to make sure preemption doesn't stall * @work: A work struct for the preemption worker (for 5XX) * @token_submit: Indicates if a preempt token has been submitted in @@ -302,7 +302,7 @@ enum adreno_preempt_states { */ struct adreno_preemption { atomic_t state; - struct kgsl_memdesc counters; + struct kgsl_memdesc scratch; struct timer_list timer; struct work_struct work; bool token_submit; @@ -1209,6 +1209,7 @@ void adreno_cx_misc_regwrite(struct adreno_device *adreno_dev, void adreno_cx_misc_regrmw(struct adreno_device *adreno_dev, unsigned int offsetwords, unsigned int mask, unsigned int bits); +u32 adreno_get_ucode_version(const u32 *data); #define ADRENO_TARGET(_name, _id) \ diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index ba46bd46d450af996c48d23a8c165d8dd20b21d9..d122332ec827c2f8d420b395822ee95aa92062d9 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2154,12 +2154,15 @@ static int a5xx_post_start(struct adreno_device *adreno_dev) *cmds++ = 0xF; } - if (adreno_is_preemption_enabled(adreno_dev)) + if (adreno_is_preemption_enabled(adreno_dev)) { cmds += _preemption_init(adreno_dev, rb, cmds, NULL); + rb->_wptr = rb->_wptr - (42 - (cmds - start)); + ret = adreno_ringbuffer_submit_spin_nosync(rb, NULL, 2000); + } else { + rb->_wptr = rb->_wptr - (42 - (cmds - start)); + ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); + } - rb->_wptr = rb->_wptr - (42 - (cmds - start)); - - ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); if (ret) adreno_spin_idle_debug(adreno_dev, "hw initialization failed to idle\n"); @@ -2497,7 +2500,7 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, memcpy(firmware->memdesc.hostptr, &fw->data[4], fw->size - 4); firmware->size = (fw->size - 4) / sizeof(uint32_t); - firmware->version = *(unsigned int *)&fw->data[4]; + firmware->version = adreno_get_ucode_version((u32 *)fw->data); done: release_firmware(fw); @@ -3315,11 +3318,11 @@ static void a5xx_gpmu_int_callback(struct adreno_device *adreno_dev, int bit) } /* - * a5x_gpc_err_int_callback() - Isr for GPC error interrupts + * a5xx_gpc_err_int_callback() - Isr for GPC error interrupts * @adreno_dev: Pointer to device * @bit: Interrupt bit */ -void a5x_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) +static void a5xx_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -3329,7 +3332,7 @@ void a5x_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) * with help of register dump. */ - KGSL_DRV_CRIT(device, "RBBM: GPC error\n"); + KGSL_DRV_CRIT_RATELIMIT(device, "RBBM: GPC error\n"); adreno_irqctrl(adreno_dev, 0); /* Trigger a fault in the dispatcher - this will effect a restart */ @@ -3367,7 +3370,7 @@ static struct adreno_irq_funcs a5xx_irq_funcs[32] = { ADRENO_IRQ_CALLBACK(a5xx_err_callback), /* 6 - RBBM_ATB_ASYNC_OVERFLOW */ ADRENO_IRQ_CALLBACK(a5xx_err_callback), - ADRENO_IRQ_CALLBACK(a5x_gpc_err_int_callback), /* 7 - GPC_ERR */ + ADRENO_IRQ_CALLBACK(a5xx_gpc_err_int_callback), /* 7 - GPC_ERR */ ADRENO_IRQ_CALLBACK(a5xx_preempt_callback),/* 8 - CP_SW */ ADRENO_IRQ_CALLBACK(a5xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */ /* 10 - CP_CCU_FLUSH_DEPTH_TS */ diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h index 08f56d6701f28ea0cb941e2a191b246303375f61..71e9e69895f08a1a1db16f5dc75392ae82af7532 100644 --- a/drivers/gpu/msm/adreno_a5xx.h +++ b/drivers/gpu/msm/adreno_a5xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017,2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017,2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -112,7 +112,7 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev); void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); -#define A5XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \ +#define A5XX_CP_RB_CNTL_DEFAULT ((1 << 27) | ((ilog2(4) << 8) & 0x1F00) | \ (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F)) /* GPMU interrupt multiplexor */ #define FW_INTR_INFO (0) diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index cb7a65f92135255032029f41746ef080741bd63f..39283db8f1003b871bf328e249bdacd1522648c5 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017,2019 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017,2019-2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -575,7 +575,7 @@ static void _preemption_close(struct adreno_device *adreno_dev) unsigned int i; del_timer(&preempt->timer); - kgsl_free_global(device, &preempt->counters); + kgsl_free_global(device, &preempt->scratch); a5xx_preemption_iommu_close(adreno_dev); FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { @@ -611,14 +611,14 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) (unsigned long) adreno_dev); /* Allocate mem for storing preemption counters */ - ret = kgsl_allocate_global(device, &preempt->counters, + ret = kgsl_allocate_global(device, &preempt->scratch, adreno_dev->num_ringbuffers * A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, "preemption_counters"); if (ret) goto err; - addr = preempt->counters.gpuaddr; + addr = preempt->scratch.gpuaddr; /* Allocate mem for storing preemption switch record */ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index a780c1bb1600c9102917cbddca0d7152154e6604..0c9f9e7398110b6ae57ca07d08a5a8b96f8b3d8c 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1211,7 +1211,7 @@ static int a6xx_post_start(struct adreno_device *adreno_dev) rb->_wptr = rb->_wptr - (42 - (cmds - start)); - ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); + ret = adreno_ringbuffer_submit_spin_nosync(rb, NULL, 2000); if (ret) adreno_spin_idle_debug(adreno_dev, "hw preemption initialization failed to idle\n"); @@ -1357,7 +1357,7 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, if (!ret) { memcpy(firmware->memdesc.hostptr, &fw->data[4], fw->size - 4); firmware->size = (fw->size - 4) / sizeof(uint32_t); - firmware->version = *(unsigned int *)&fw->data[4]; + firmware->version = adreno_get_ucode_version((u32 *)fw->data); } release_firmware(fw); @@ -1762,6 +1762,29 @@ static void a6xx_cp_callback(struct adreno_device *adreno_dev, int bit) adreno_dispatcher_schedule(device); } +/* + * a6xx_gpc_err_int_callback() - Isr for GPC error interrupts + * @adreno_dev: Pointer to device + * @bit: Interrupt bit + */ +static void a6xx_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + /* + * GPC error is typically the result of mistake SW programming. + * Force GPU fault for this interrupt so that we can debug it + * with help of register dump. + */ + + KGSL_DRV_CRIT_RATELIMIT(device, "RBBM: GPC error\n"); + adreno_irqctrl(adreno_dev, 0); + + /* Trigger a fault in the dispatcher - this will effect a restart */ + adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT); + adreno_dispatcher_schedule(device); +} + #define A6XX_INT_MASK \ ((1 << A6XX_INT_CP_AHB_ERROR) | \ (1 << A6XX_INT_ATB_ASYNCFIFO_OVERFLOW) | \ @@ -1787,7 +1810,7 @@ static struct adreno_irq_funcs a6xx_irq_funcs[32] = { ADRENO_IRQ_CALLBACK(NULL), /* 5 - UNUSED */ /* 6 - RBBM_ATB_ASYNC_OVERFLOW */ ADRENO_IRQ_CALLBACK(a6xx_err_callback), - ADRENO_IRQ_CALLBACK(NULL), /* 7 - GPC_ERR */ + ADRENO_IRQ_CALLBACK(a6xx_gpc_err_int_callback), /* 7 - GPC_ERR */ ADRENO_IRQ_CALLBACK(a6xx_preemption_callback),/* 8 - CP_SW */ ADRENO_IRQ_CALLBACK(a6xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */ ADRENO_IRQ_CALLBACK(NULL), /* 10 - CP_CCU_FLUSH_DEPTH_TS */ diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 49085651f208112742f36081a544b95f9277352f..5127f18d2c5452b56a593483c270fdb3a7b030d0 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -101,7 +101,7 @@ struct cpu_gpu_lock { /* Size of the performance counter save/restore block (in bytes) */ #define A6XX_CP_PERFCOUNTER_SAVE_RESTORE_SIZE (4 * 1024) -#define A6XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \ +#define A6XX_CP_RB_CNTL_DEFAULT ((1 << 27) | ((ilog2(4) << 8) & 0x1F00) | \ (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F)) /* diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index a4639068403b5be6f9d82743d2c6ef0343f59d50..fdcf0e9e263f824e939119d9dfa82d267e52dc8b 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -351,6 +351,8 @@ static int a6xx_gmu_start(struct kgsl_device *device) /* Bring GMU out of reset */ gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); + /* Make sure the request completes before continuing */ + wmb(); if (timed_poll_check(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0xBABEFACE, @@ -829,6 +831,21 @@ static bool a6xx_gmu_gx_is_on(struct adreno_device *adreno_dev) return is_on(val); } +/* + * a6xx_gmu_cx_is_on() - Check if CX is on using GPUCC register + * @device - Pointer to KGSL device struct + */ +static bool a6xx_gmu_cx_is_on(struct kgsl_device *device) +{ + unsigned int val; + + if (ADRENO_QUIRK(ADRENO_DEVICE(device), ADRENO_QUIRK_CX_GDSC)) + return regulator_is_enabled(KGSL_GMU_DEVICE(device)->cx_gdsc); + + gmu_core_regread(device, A6XX_GPU_CC_CX_GDSCR, &val); + return (val & BIT(31)); +} + /* * a6xx_gmu_sptprac_is_on() - Check if SPTP is on using pwr status register * @adreno_dev - Pointer to adreno_device @@ -1042,6 +1059,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, gmu_core_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0, GMU_FENCE_RANGE_MASK); + /* + * Make sure that CM3 state is at reset value. Snapshot is changing + * NMI bit and if we boot up GMU with NMI bit set.GMU will boot straight + * in to NMI handler without executing __main code + */ + gmu_core_regwrite(device, A6XX_GMU_CM3_CFG, 0x4052); + /* Pass chipid to GMU FW, must happen before starting GMU */ /* Keep Core and Major bitfields unchanged */ @@ -1183,6 +1207,8 @@ static int a6xx_gmu_suspend(struct kgsl_device *device) /* Check no outstanding RPMh voting */ a6xx_complete_rpmh_votes(device); + gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); + /* * This is based on the assumption that GMU is the only one controlling * the GX HS. This code path is the only client voting for GX through @@ -1669,6 +1695,7 @@ struct gmu_dev_ops adreno_a6xx_gmudev = { .enable_lm = a6xx_gmu_enable_lm, .rpmh_gpu_pwrctrl = a6xx_gmu_rpmh_gpu_pwrctrl, .gx_is_on = a6xx_gmu_gx_is_on, + .cx_is_on = a6xx_gmu_cx_is_on, .wait_for_lowest_idle = a6xx_gmu_wait_for_lowest_idle, .wait_for_gmu_idle = a6xx_gmu_wait_for_idle, .ifpc_store = a6xx_gmu_ifpc_store, diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 760cef5891af79e16aac51b423975d1c0cd69659..ac928a65514d392b83428933fa3fbe038d2ebfc8 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -324,8 +324,8 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) kgsl_sharedmem_writel(device, &iommu->smmu_info, PREEMPT_SMMU_RECORD(context_idr), contextidr); - kgsl_sharedmem_readq(&device->scratch, &gpuaddr, - SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(next->id)); + kgsl_sharedmem_readq(&preempt->scratch, &gpuaddr, + next->id * sizeof(u64)); /* * Set a keepalive bit before the first preemption register write. @@ -546,12 +546,10 @@ unsigned int a6xx_preemption_pre_ibsubmit( rb->perfcounter_save_restore_desc.gpuaddr); if (context) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_context *drawctxt = ADRENO_CONTEXT(context); struct adreno_ringbuffer *rb = drawctxt->rb; - uint64_t dest = - SCRATCH_PREEMPTION_CTXT_RESTORE_GPU_ADDR(device, - rb->id); + uint64_t dest = adreno_dev->preempt.scratch.gpuaddr + + sizeof(u64) * rb->id; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 2); cmds += cp_gpuaddr(adreno_dev, cmds, dest); @@ -569,9 +567,8 @@ unsigned int a6xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb = adreno_dev->cur_rb; if (rb) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - uint64_t dest = SCRATCH_PREEMPTION_CTXT_RESTORE_GPU_ADDR(device, - rb->id); + uint64_t dest = adreno_dev->preempt.scratch.gpuaddr + + sizeof(u64) * rb->id; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 2); cmds += cp_gpuaddr(adreno_dev, cmds, dest); @@ -732,7 +729,7 @@ static void _preemption_close(struct adreno_device *adreno_dev) unsigned int i; del_timer(&preempt->timer); - kgsl_free_global(device, &preempt->counters); + kgsl_free_global(device, &preempt->scratch); a6xx_preemption_iommu_close(adreno_dev); FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { @@ -771,15 +768,19 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) setup_timer(&preempt->timer, _a6xx_preemption_timer, (unsigned long) adreno_dev); - /* Allocate mem for storing preemption counters */ - ret = kgsl_allocate_global(device, &preempt->counters, - adreno_dev->num_ringbuffers * - A6XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, - "preemption_counters"); + /* + * Allocate a scratch buffer to keep the below table: + * Offset: What + * 0x0: Context Record address + * 0x10: Preemption Counters + */ + ret = kgsl_allocate_global(device, &preempt->scratch, PAGE_SIZE, 0, 0, + "preemption_scratch"); if (ret) goto err; - addr = preempt->counters.gpuaddr; + addr = preempt->scratch.gpuaddr + + KGSL_PRIORITY_MAX_RB_LEVELS * sizeof(u64); /* Allocate mem for storing preemption switch record */ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index df8e8acecb4c95c90776913520bc3f7b0ab8c1d8..aa945a4bd3026b1350cd88a4539f0e21a44859b9 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -487,11 +487,12 @@ void adreno_drawctxt_detach(struct kgsl_context *context) drawctxt = ADRENO_CONTEXT(context); rb = drawctxt->rb; + spin_lock(&drawctxt->lock); + spin_lock(&adreno_dev->active_list_lock); list_del_init(&drawctxt->active_node); spin_unlock(&adreno_dev->active_list_lock); - spin_lock(&drawctxt->lock); count = drawctxt_detach_drawobjs(drawctxt, list); spin_unlock(&drawctxt->lock); diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index 82629c6fcf235f85d40dde88e1122c60214d41f8..d18aa19ad56301a1766c09b168084f57d62d9368 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -168,7 +168,7 @@ static long adreno_ioctl_preemption_counters_query( levels_to_copy = gpudev->num_prio_levels; if (copy_to_user((void __user *) (uintptr_t) read->counters, - adreno_dev->preempt.counters.hostptr, + adreno_dev->preempt.scratch.hostptr, levels_to_copy * size_level)) return -EFAULT; diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h index 2a330b4474aa6cd56b375b2a68e79c3b5607a87f..543496399044f793cbd791350c1f4718cf1e1f5e 100644 --- a/drivers/gpu/msm/adreno_pm4types.h +++ b/drivers/gpu/msm/adreno_pm4types.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -103,6 +103,8 @@ /* A5XX Enable yield in RB only */ #define CP_YIELD_ENABLE 0x1C +#define CP_WHERE_AM_I 0x62 + /* Enable/Disable/Defer A5x global preemption model */ #define CP_PREEMPT_ENABLE_GLOBAL 0x69 diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 2ee57e9a5ce6d0574d716ab1c2474f2c1e4d79f4..e325622968095b7304237b2e39384829d711b106 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -204,7 +204,7 @@ void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, adreno_ringbuffer_wptr(adreno_dev, rb); } -int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, +int adreno_ringbuffer_submit_spin_nosync(struct adreno_ringbuffer *rb, struct adreno_submit_time *time, unsigned int timeout) { struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); @@ -213,6 +213,38 @@ int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, return adreno_spin_idle(adreno_dev, timeout); } +/* + * adreno_ringbuffer_submit_spin() - Submit the cmds and wait until GPU is idle + * @rb: Pointer to ringbuffer + * @time: Pointer to adreno_submit_time + * @timeout: timeout value in ms + * + * Add commands to the ringbuffer and wait until GPU goes to idle. This routine + * inserts a WHERE_AM_I packet to trigger a shadow rptr update. So, use + * adreno_ringbuffer_submit_spin_nosync() if the previous cmd in the RB is a + * CSY packet because CSY followed by WHERE_AM_I is not legal. + */ +int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, + struct adreno_submit_time *time, unsigned int timeout) +{ + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int *cmds; + + if (adreno_is_a3xx(adreno_dev)) + return adreno_ringbuffer_submit_spin_nosync(rb, time, timeout); + + cmds = adreno_ringbuffer_allocspace(rb, 3); + if (IS_ERR(cmds)) + return PTR_ERR(cmds); + + *cmds++ = cp_packet(adreno_dev, CP_WHERE_AM_I, 2); + cmds += cp_gpuaddr(adreno_dev, cmds, + SCRATCH_RPTR_GPU_ADDR(device, rb->id)); + + return adreno_ringbuffer_submit_spin_nosync(rb, time, timeout); +} + unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, unsigned int dwords) { @@ -337,12 +369,13 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + unsigned int priv = KGSL_MEMDESC_RANDOM | KGSL_MEMDESC_PRIVILEGED; int i, r = 0; int status = -ENOMEM; if (!adreno_is_a3xx(adreno_dev)) { status = kgsl_allocate_global(device, &device->scratch, - PAGE_SIZE, 0, KGSL_MEMDESC_RANDOM, "scratch"); + PAGE_SIZE, 0, priv, "scratch"); if (status != 0) return status; } @@ -564,6 +597,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (gpudev->preemption_post_ibsubmit && adreno_is_preemption_enabled(adreno_dev)) total_sizedwords += 10; + else if (!adreno_is_a3xx(adreno_dev)) + total_sizedwords += 3; /* * a5xx uses 64 bit memory address. pm4 commands that involve read/write @@ -775,6 +810,11 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, adreno_is_preemption_enabled(adreno_dev)) ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev, ringcmds); + else if (!adreno_is_a3xx(adreno_dev)) { + *ringcmds++ = cp_packet(adreno_dev, CP_WHERE_AM_I, 2); + ringcmds += cp_gpuaddr(adreno_dev, ringcmds, + SCRATCH_RPTR_GPU_ADDR(device, rb->id)); + } /* * If we have more ringbuffer commands than space reserved diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index 9eb0c92213f34b5921dc0d08b54b8bcbcf6173eb..14b4ecc2e192a9b603eb3ec6574c61b396907774 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -178,6 +178,9 @@ int adreno_ringbuffer_issue_internal_cmds(struct adreno_ringbuffer *rb, void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, struct adreno_submit_time *time); +int adreno_ringbuffer_submit_spin_nosync(struct adreno_ringbuffer *rb, + struct adreno_submit_time *time, unsigned int timeout); + int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, struct adreno_submit_time *time, unsigned int timeout); diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 5ddf8cd3774b4e7d1dd549f64869509e8ec5ab26..0efbbdb407094e7fb3d7c3d274a1c15153a884ca 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2683,7 +2683,7 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, return 0; unmap: - if (param->type == KGSL_USER_MEM_TYPE_DMABUF) { + if (kgsl_memdesc_usermem_type(&entry->memdesc) == KGSL_MEM_ENTRY_ION) { kgsl_destroy_ion(entry->priv_data); entry->memdesc.sgt = NULL; } @@ -2997,7 +2997,7 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, return result; error_attach: - switch (memtype) { + switch (kgsl_memdesc_usermem_type(&entry->memdesc)) { case KGSL_MEM_ENTRY_ION: kgsl_destroy_ion(entry->priv_data); entry->memdesc.sgt = NULL; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 3c877f722f2356d459e7d88de85cc98f49bf0955..1091205e6aa34ae4dac6a65ea33966d70aaa8a0a 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -71,13 +71,11 @@ /* * SCRATCH MEMORY: The scratch memory is one page worth of data that * is mapped into the GPU. This allows for some 'shared' data between - * the GPU and CPU. For example, it will be used by the GPU to write - * each updated RPTR for each RB. + * the GPU and CPU. * * Used Data: * Offset: Length(bytes): What * 0x0: 4 * KGSL_PRIORITY_MAX_RB_LEVELS: RB0 RPTR - * 0x10: 8 * KGSL_PRIORITY_MAX_RB_LEVELS: RB0 CTXT RESTORE ADDR */ /* Shadow global helpers */ @@ -85,13 +83,6 @@ #define SCRATCH_RPTR_GPU_ADDR(dev, id) \ ((dev)->scratch.gpuaddr + SCRATCH_RPTR_OFFSET(id)) -#define SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(id) \ - (SCRATCH_RPTR_OFFSET(KGSL_PRIORITY_MAX_RB_LEVELS) + \ - ((id) * sizeof(uint64_t))) -#define SCRATCH_PREEMPTION_CTXT_RESTORE_GPU_ADDR(dev, id) \ - ((dev)->scratch.gpuaddr + \ - SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(id)) - /* Timestamp window used to detect rollovers (half of integer range) */ #define KGSL_TIMESTAMP_WINDOW 0x80000000 diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index cf993e7ebbf1047c5235917d8f7794cce74e882e..770ac448df1ba59360acc29a1b80623e60170946 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -964,6 +964,8 @@ static int gmu_rpmh_init(struct kgsl_device *device, static void send_nmi_to_gmu(struct adreno_device *adreno_dev) { + u32 val; + /* Mask so there's no interrupt caused by NMI */ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); @@ -972,9 +974,10 @@ static void send_nmi_to_gmu(struct adreno_device *adreno_dev) wmb(); adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0); - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_CM3_CFG, - (1 << GMU_CM3_CFG_NONMASKINTR_SHIFT)); + + adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_CM3_CFG, &val); + val |= 1 << GMU_CM3_CFG_NONMASKINTR_SHIFT; + adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_CM3_CFG, val); /* Make sure the NMI is invoked before we proceed*/ wmb(); @@ -1538,8 +1541,9 @@ static int gmu_enable_gdsc(struct gmu_device *gmu) } #define CX_GDSC_TIMEOUT 5000 /* ms */ -static int gmu_disable_gdsc(struct gmu_device *gmu) +static int gmu_disable_gdsc(struct kgsl_device *device) { + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); int ret; unsigned long t; @@ -1561,13 +1565,13 @@ static int gmu_disable_gdsc(struct gmu_device *gmu) */ t = jiffies + msecs_to_jiffies(CX_GDSC_TIMEOUT); do { - if (!regulator_is_enabled(gmu->cx_gdsc)) + if (!gmu_core_dev_cx_is_on(device)) return 0; usleep_range(10, 100); } while (!(time_after(jiffies, t))); - if (!regulator_is_enabled(gmu->cx_gdsc)) + if (!gmu_core_dev_cx_is_on(device)) return 0; dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout"); @@ -1595,7 +1599,7 @@ static int gmu_suspend(struct kgsl_device *device) if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_IDLE); - gmu_disable_gdsc(gmu); + gmu_disable_gdsc(device); if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); @@ -1752,7 +1756,7 @@ static void gmu_stop(struct kgsl_device *device) gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0); gmu_disable_clks(device); - gmu_disable_gdsc(gmu); + gmu_disable_gdsc(device); msm_bus_scale_client_update_request(gmu->pcl, 0); return; @@ -1862,7 +1866,7 @@ static bool gmu_is_initialized(struct kgsl_device *device) ret = gmu_dev_ops->is_initialized(adreno_dev); gmu_disable_clks(device); - gmu_disable_gdsc(gmu); + gmu_disable_gdsc(device); return ret; } diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 1116b6b7dadafefc1a54566f60a762c3f4784387..140baea8efdcdb7be1d5e593f5fb33c5d3a2aef7 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -275,6 +275,16 @@ void gmu_core_regrmw(struct kgsl_device *device, gmu_core_regwrite(device, offsetwords, val | bits); } +bool gmu_core_dev_cx_is_on(struct kgsl_device *device) +{ + struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device); + + if (ops && ops->cx_is_on) + return ops->cx_is_on(device); + + return true; +} + bool gmu_core_is_initialized(struct kgsl_device *device) { struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 3dff7fafbe12b46367dae98351a56966a0fde305..e2f956cc9dc7671c53970d39eebe846780a40a71 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -164,6 +164,7 @@ struct gmu_dev_ops { unsigned int val); unsigned int (*ifpc_show)(struct adreno_device *adreno_dev); void (*snapshot)(struct adreno_device *, struct kgsl_snapshot *); + bool (*cx_is_on)(struct kgsl_device *device); void (*halt_execution)(struct kgsl_device *device); int (*wait_for_active_transition)(struct adreno_device *adreno_dev); bool (*is_initialized)(struct adreno_device *adreno_dev); @@ -231,6 +232,7 @@ void gmu_core_blkwrite(struct kgsl_device *device, unsigned int offsetwords, void gmu_core_regrmw(struct kgsl_device *device, unsigned int offsetwords, unsigned int mask, unsigned int bits); const char *gmu_core_oob_type_str(enum oob_request req); +bool gmu_core_dev_cx_is_on(struct kgsl_device *device); bool gmu_core_is_initialized(struct kgsl_device *device); u64 gmu_core_dev_read_ao_counter(struct kgsl_device *device); #endif /* __KGSL_GMU_CORE_H */ diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index b338a1568476866ecfd348e74baef5ff0705a169..a493c4fbe8d8871868f774d80e129b605cfb1a06 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -189,7 +189,7 @@ int kgsl_iommu_map_global_secure_pt_entry(struct kgsl_device *device, struct kgsl_pagetable *pagetable = device->mmu.securepagetable; entry->pagetable = pagetable; - entry->gpuaddr = KGSL_IOMMU_SECURE_BASE(&device->mmu) + + entry->gpuaddr = device->mmu.secure_base + secure_global_size; ret = kgsl_mmu_map(pagetable, entry); @@ -1097,13 +1097,13 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, struct kgsl_iommu_pt *pt) { if (mmu->secured && pagetable->name == KGSL_MMU_SECURE_PT) { - pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu); + pt->compat_va_start = mmu->secure_base; pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu); - pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu); + pt->va_start = mmu->secure_base; pt->va_end = KGSL_IOMMU_SECURE_END(mmu); } else { pt->compat_va_start = mmu->svm_base32; - pt->compat_va_end = KGSL_IOMMU_SECURE_BASE(mmu); + pt->compat_va_end = mmu->secure_base; pt->va_start = KGSL_IOMMU_VA_BASE64; pt->va_end = KGSL_IOMMU_VA_END64; } @@ -1112,7 +1112,7 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, pagetable->name != KGSL_MMU_SECURE_PT) { if (kgsl_is_compat_task()) { pt->svm_start = mmu->svm_base32; - pt->svm_end = KGSL_IOMMU_SECURE_BASE(mmu); + pt->svm_end = mmu->secure_base; } else { pt->svm_start = KGSL_IOMMU_SVM_BASE64; pt->svm_end = KGSL_IOMMU_SVM_END64; @@ -1126,13 +1126,13 @@ static void setup_32bit_pagetable(struct kgsl_mmu *mmu, { if (mmu->secured) { if (pagetable->name == KGSL_MMU_SECURE_PT) { - pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu); + pt->compat_va_start = mmu->secure_base; pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu); - pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu); + pt->va_start = mmu->secure_base; pt->va_end = KGSL_IOMMU_SECURE_END(mmu); } else { pt->va_start = mmu->svm_base32; - pt->va_end = KGSL_IOMMU_SECURE_BASE(mmu); + pt->va_end = mmu->secure_base; pt->compat_va_start = pt->va_start; pt->compat_va_end = pt->va_end; } @@ -2502,6 +2502,22 @@ static uint64_t kgsl_iommu_find_svm_region(struct kgsl_pagetable *pagetable, return addr; } +static bool iommu_addr_in_svm_ranges(struct kgsl_iommu_pt *pt, + u64 gpuaddr, u64 size) +{ + if ((gpuaddr >= pt->compat_va_start && gpuaddr < pt->compat_va_end) && + ((gpuaddr + size) > pt->compat_va_start && + (gpuaddr + size) <= pt->compat_va_end)) + return true; + + if ((gpuaddr >= pt->svm_start && gpuaddr < pt->svm_end) && + ((gpuaddr + size) > pt->svm_start && + (gpuaddr + size) <= pt->svm_end)) + return true; + + return false; +} + static int kgsl_iommu_set_svm_region(struct kgsl_pagetable *pagetable, uint64_t gpuaddr, uint64_t size) { @@ -2509,9 +2525,8 @@ static int kgsl_iommu_set_svm_region(struct kgsl_pagetable *pagetable, struct kgsl_iommu_pt *pt = pagetable->priv; struct rb_node *node; - /* Make sure the requested address doesn't fall in the global range */ - if (ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr) || - ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr + size)) + /* Make sure the requested address doesn't fall out of SVM range */ + if (!iommu_addr_in_svm_ranges(pt, gpuaddr, size)) return -ENOMEM; spin_lock(&pagetable->lock); @@ -2725,6 +2740,7 @@ static int _kgsl_iommu_probe(struct kgsl_device *device, u32 reg_val[2]; int i = 0; struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); + struct kgsl_mmu *mmu = &device->mmu; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct device_node *child; struct platform_device *pdev = of_find_device_by_node(node); @@ -2769,7 +2785,7 @@ static int _kgsl_iommu_probe(struct kgsl_device *device, for (i = 0; i < ARRAY_SIZE(kgsl_iommu_features); i++) { if (of_property_read_bool(node, kgsl_iommu_features[i].feature)) - device->mmu.features |= kgsl_iommu_features[i].bit; + mmu->features |= kgsl_iommu_features[i].bit; } /* @@ -2790,8 +2806,16 @@ static int _kgsl_iommu_probe(struct kgsl_device *device, iommu->micro_mmu_ctrl = UINT_MAX; if (of_property_read_u32(node, "qcom,secure_align_mask", - &device->mmu.secure_align_mask)) - device->mmu.secure_align_mask = 0xfff; + &mmu->secure_align_mask)) + mmu->secure_align_mask = 0xfff; + + if (of_property_read_u32(node, "qcom,secure-size", &mmu->secure_size)) + mmu->secure_size = KGSL_IOMMU_SECURE_SIZE; + else if (mmu->secure_size > + (KGSL_IOMMU_SECURE_END(mmu) - mmu->svm_base32)) + mmu->secure_size = KGSL_IOMMU_SECURE_SIZE; + + mmu->secure_base = KGSL_IOMMU_SECURE_END(mmu) - mmu->secure_size; /* Fill out the rest of the devices in the node */ of_platform_populate(node, NULL, NULL, &pdev->dev); diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index 79eee71a0cd70f1960985ca7546a84ff40c2cf59..4660717b99b1fae1fe857f8397522a0badb01646 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,8 +33,6 @@ #define KGSL_IOMMU_SECURE_SIZE SZ_256M #define KGSL_IOMMU_SECURE_END(_mmu) KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) -#define KGSL_IOMMU_SECURE_BASE(_mmu) \ - (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) - KGSL_IOMMU_SECURE_SIZE) #define KGSL_IOMMU_SVM_BASE32 0x300000 #define KGSL_IOMMU_SVM_END32 (0xC0000000 - SZ_16M) diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 06d0ae387f1cfabb64eebe108e5a56e280fb3cce..b10d079448f8565fd38fdbfe2ffa4549b121666f 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -170,6 +170,8 @@ struct kgsl_mmu { unsigned int secure_align_mask; uint64_t va_padding; unsigned int svm_base32; + unsigned int secure_base; + unsigned int secure_size; union { struct kgsl_iommu iommu; } priv; diff --git a/drivers/gpu/trace/Kconfig b/drivers/gpu/trace/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..c24e9edd022e68c73e1a9ddc1ff600ef54646dbc --- /dev/null +++ b/drivers/gpu/trace/Kconfig @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config TRACE_GPU_MEM + bool diff --git a/drivers/gpu/trace/Makefile b/drivers/gpu/trace/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b70fbdc5847f002a70df7a57d9d0da9c518bb86e --- /dev/null +++ b/drivers/gpu/trace/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_TRACE_GPU_MEM) += trace_gpu_mem.o diff --git a/drivers/gpu/trace/trace_gpu_mem.c b/drivers/gpu/trace/trace_gpu_mem.c new file mode 100644 index 0000000000000000000000000000000000000000..01e855897b6d093d4cd84cc1df13194121baec4d --- /dev/null +++ b/drivers/gpu/trace/trace_gpu_mem.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPU memory trace points + * + * Copyright (C) 2020 Google, Inc. + */ + +#include + +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL(gpu_mem_total); diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d9d2a7d5b9cf2222dc31348105848328ac18bf1f..0c262188a927c372ff7870487fb2e200afaca79e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -609,6 +609,17 @@ config HID_MULTITOUCH To compile this driver as a module, choose M here: the module will be called hid-multitouch. +config HID_NINTENDO + tristate "Nintendo Joy-Con and Pro Controller support" + depends on HID + help + Adds support for the Nintendo Switch Joy-Cons and Pro Controller. + All controllers support bluetooth, and the Pro Controller also supports + its USB mode. + + To compile this driver as a module, choose M here: the + module will be called hid-nintendo. + config HID_NTI tristate "NTI keyboard adapters" ---help--- diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1b0e8c1f7aeb09e67ef2d96c2ac982afab6c79cb..4158a4a2337f79bd7a2e24738c617f60f01cad74 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o +obj-$(CONFIG_HID_NINTENDO) += hid-nintendo.o obj-$(CONFIG_HID_NTI) += hid-nti.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index d0a81a03ddbdd5cb206db6760a2954feaff0de41..8ab8f2350bbcdc7f28cccfc15d195807c503c32f 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -343,7 +343,8 @@ static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, unsigned long **bit, int *max) { if (usage->hid == (HID_UP_CUSTOM | 0x0003) || - usage->hid == (HID_UP_MSVENDOR | 0x0003)) { + usage->hid == (HID_UP_MSVENDOR | 0x0003) || + usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) { /* The fn key on Apple USB keyboards */ set_bit(EV_REP, hi->input->evbit); hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 36f2e25f50cb1bf7f2ec536b9871a2f9d38897ec..1f2e9c9279e86d85710b35130c6ee4fcf5270ddc 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1567,7 +1567,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, rsize = ((report->size - 1) >> 3) + 1; - if (rsize > HID_MAX_BUFFER_SIZE) + if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE) + rsize = HID_MAX_BUFFER_SIZE - 1; + else if (rsize > HID_MAX_BUFFER_SIZE) rsize = HID_MAX_BUFFER_SIZE; if (csize < rsize) { @@ -2259,6 +2261,16 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, #endif +#if IS_ENABLED(CONFIG_HID_NINTENDO) + { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_PROCON) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_PROCON) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_JOYCONL) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_JOYCONR) }, +#endif #if IS_ENABLED(CONFIG_HID_NTI) { HID_USB_DEVICE(USB_VENDOR_ID_NTI, USB_DEVICE_ID_USB_SUN) }, #endif diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e25a5e2c2ecac8e6abf7e8ed8972231728abd162..a3e5c4400091fb2dd0f3033295051244eeb32738 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -816,6 +816,9 @@ #define USB_VENDOR_ID_NINTENDO 0x057e #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 #define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330 +#define USB_DEVICE_ID_NINTENDO_JOYCONL 0x2006 +#define USB_DEVICE_ID_NINTENDO_JOYCONR 0x2007 +#define USB_DEVICE_ID_NINTENDO_PROCON 0x2009 #define USB_VENDOR_ID_NOVATEK 0x0603 #define USB_DEVICE_ID_NOVATEK_PCT 0x0600 diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 2ce1eb0c9212531814055177e6820fcdc18eb947..f2e23f81601e7472fe2a3d8f2e26cc7432b50dbe 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -44,8 +44,9 @@ static const struct hid_device_id ite_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) }, { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) }, /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */ - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, - USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) }, + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_SYNAPTICS, + USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) }, { } }; MODULE_DEVICE_TABLE(hid, ite_devices); diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c new file mode 100644 index 0000000000000000000000000000000000000000..3695b96694bd4c9510e6e402d67fd9103071a78a --- /dev/null +++ b/drivers/hid/hid-nintendo.c @@ -0,0 +1,820 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID driver for Nintendo Switch Joy-Cons and Pro Controllers + * + * Copyright (c) 2019 Daniel J. Ogorchock + * + * The following resources/projects were referenced for this driver: + * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering + * https://gitlab.com/pjranki/joycon-linux-kernel (Peter Rankin) + * https://github.com/FrotBot/SwitchProConLinuxUSB + * https://github.com/MTCKC/ProconXInput + * hid-wiimote kernel hid driver + * hid-logitech-hidpp driver + * + * This driver supports the Nintendo Switch Joy-Cons and Pro Controllers. The + * Pro Controllers can either be used over USB or Bluetooth. + * + * The driver will retrieve the factory calibration info from the controllers, + * so little to no user calibration should be required. + * + */ + +#include "hid-ids.h" +#include +#include +#include +#include +#include +#include + +/* + * Reference the url below for the following HID report defines: + * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering + */ + +/* Output Reports */ +static const u8 JC_OUTPUT_RUMBLE_AND_SUBCMD = 0x01; +static const u8 JC_OUTPUT_FW_UPDATE_PKT = 0x03; +static const u8 JC_OUTPUT_RUMBLE_ONLY = 0x10; +static const u8 JC_OUTPUT_MCU_DATA = 0x11; +static const u8 JC_OUTPUT_USB_CMD = 0x80; + +/* Subcommand IDs */ +static const u8 JC_SUBCMD_STATE /*= 0x00*/; +static const u8 JC_SUBCMD_MANUAL_BT_PAIRING = 0x01; +static const u8 JC_SUBCMD_REQ_DEV_INFO = 0x02; +static const u8 JC_SUBCMD_SET_REPORT_MODE = 0x03; +static const u8 JC_SUBCMD_TRIGGERS_ELAPSED = 0x04; +static const u8 JC_SUBCMD_GET_PAGE_LIST_STATE = 0x05; +static const u8 JC_SUBCMD_SET_HCI_STATE = 0x06; +static const u8 JC_SUBCMD_RESET_PAIRING_INFO = 0x07; +static const u8 JC_SUBCMD_LOW_POWER_MODE = 0x08; +static const u8 JC_SUBCMD_SPI_FLASH_READ = 0x10; +static const u8 JC_SUBCMD_SPI_FLASH_WRITE = 0x11; +static const u8 JC_SUBCMD_RESET_MCU = 0x20; +static const u8 JC_SUBCMD_SET_MCU_CONFIG = 0x21; +static const u8 JC_SUBCMD_SET_MCU_STATE = 0x22; +static const u8 JC_SUBCMD_SET_PLAYER_LIGHTS = 0x30; +static const u8 JC_SUBCMD_GET_PLAYER_LIGHTS = 0x31; +static const u8 JC_SUBCMD_SET_HOME_LIGHT = 0x38; +static const u8 JC_SUBCMD_ENABLE_IMU = 0x40; +static const u8 JC_SUBCMD_SET_IMU_SENSITIVITY = 0x41; +static const u8 JC_SUBCMD_WRITE_IMU_REG = 0x42; +static const u8 JC_SUBCMD_READ_IMU_REG = 0x43; +static const u8 JC_SUBCMD_ENABLE_VIBRATION = 0x48; +static const u8 JC_SUBCMD_GET_REGULATED_VOLTAGE = 0x50; + +/* Input Reports */ +static const u8 JC_INPUT_BUTTON_EVENT = 0x3F; +static const u8 JC_INPUT_SUBCMD_REPLY = 0x21; +static const u8 JC_INPUT_IMU_DATA = 0x30; +static const u8 JC_INPUT_MCU_DATA = 0x31; +static const u8 JC_INPUT_USB_RESPONSE = 0x81; + +/* Feature Reports */ +static const u8 JC_FEATURE_LAST_SUBCMD = 0x02; +static const u8 JC_FEATURE_OTA_FW_UPGRADE = 0x70; +static const u8 JC_FEATURE_SETUP_MEM_READ = 0x71; +static const u8 JC_FEATURE_MEM_READ = 0x72; +static const u8 JC_FEATURE_ERASE_MEM_SECTOR = 0x73; +static const u8 JC_FEATURE_MEM_WRITE = 0x74; +static const u8 JC_FEATURE_LAUNCH = 0x75; + +/* USB Commands */ +static const u8 JC_USB_CMD_CONN_STATUS = 0x01; +static const u8 JC_USB_CMD_HANDSHAKE = 0x02; +static const u8 JC_USB_CMD_BAUDRATE_3M = 0x03; +static const u8 JC_USB_CMD_NO_TIMEOUT = 0x04; +static const u8 JC_USB_CMD_EN_TIMEOUT = 0x05; +static const u8 JC_USB_RESET = 0x06; +static const u8 JC_USB_PRE_HANDSHAKE = 0x91; +static const u8 JC_USB_SEND_UART = 0x92; + +/* SPI storage addresses of factory calibration data */ +static const u16 JC_CAL_DATA_START = 0x603d; +static const u16 JC_CAL_DATA_END = 0x604e; +#define JC_CAL_DATA_SIZE (JC_CAL_DATA_END - JC_CAL_DATA_START + 1) + + +/* The raw analog joystick values will be mapped in terms of this magnitude */ +static const u16 JC_MAX_STICK_MAG = 32767; +static const u16 JC_STICK_FUZZ = 250; +static const u16 JC_STICK_FLAT = 500; + +/* States for controller state machine */ +enum joycon_ctlr_state { + JOYCON_CTLR_STATE_INIT, + JOYCON_CTLR_STATE_READ, +}; + +struct joycon_stick_cal { + s32 max; + s32 min; + s32 center; +}; + +/* + * All the controller's button values are stored in a u32. + * They can be accessed with bitwise ANDs. + */ +static const u32 JC_BTN_Y = BIT(0); +static const u32 JC_BTN_X = BIT(1); +static const u32 JC_BTN_B = BIT(2); +static const u32 JC_BTN_A = BIT(3); +static const u32 JC_BTN_SR_R = BIT(4); +static const u32 JC_BTN_SL_R = BIT(5); +static const u32 JC_BTN_R = BIT(6); +static const u32 JC_BTN_ZR = BIT(7); +static const u32 JC_BTN_MINUS = BIT(8); +static const u32 JC_BTN_PLUS = BIT(9); +static const u32 JC_BTN_RSTICK = BIT(10); +static const u32 JC_BTN_LSTICK = BIT(11); +static const u32 JC_BTN_HOME = BIT(12); +static const u32 JC_BTN_CAP = BIT(13); /* capture button */ +static const u32 JC_BTN_DOWN = BIT(16); +static const u32 JC_BTN_UP = BIT(17); +static const u32 JC_BTN_RIGHT = BIT(18); +static const u32 JC_BTN_LEFT = BIT(19); +static const u32 JC_BTN_SR_L = BIT(20); +static const u32 JC_BTN_SL_L = BIT(21); +static const u32 JC_BTN_L = BIT(22); +static const u32 JC_BTN_ZL = BIT(23); + +enum joycon_msg_type { + JOYCON_MSG_TYPE_NONE, + JOYCON_MSG_TYPE_USB, + JOYCON_MSG_TYPE_SUBCMD, +}; + +struct joycon_subcmd_request { + u8 output_id; /* must be 0x01 for subcommand, 0x10 for rumble only */ + u8 packet_num; /* incremented every send */ + u8 rumble_data[8]; + u8 subcmd_id; + u8 data[0]; /* length depends on the subcommand */ +} __packed; + +struct joycon_subcmd_reply { + u8 ack; /* MSB 1 for ACK, 0 for NACK */ + u8 id; /* id of requested subcmd */ + u8 data[0]; /* will be at most 35 bytes */ +} __packed; + +struct joycon_input_report { + u8 id; + u8 timer; + u8 bat_con; /* battery and connection info */ + u8 button_status[3]; + u8 left_stick[3]; + u8 right_stick[3]; + u8 vibrator_report; + + /* + * If support for firmware updates, gyroscope data, and/or NFC/IR + * are added in the future, this can be swapped for a union. + */ + struct joycon_subcmd_reply reply; +} __packed; + +#define JC_MAX_RESP_SIZE (sizeof(struct joycon_input_report) + 35) + +/* Each physical controller is associated with a joycon_ctlr struct */ +struct joycon_ctlr { + struct hid_device *hdev; + struct input_dev *input; + enum joycon_ctlr_state ctlr_state; + + /* The following members are used for synchronous sends/receives */ + enum joycon_msg_type msg_type; + u8 subcmd_num; + struct mutex output_mutex; + u8 input_buf[JC_MAX_RESP_SIZE]; + wait_queue_head_t wait; + bool received_resp; + u8 usb_ack_match; + u8 subcmd_ack_match; + + /* factory calibration data */ + struct joycon_stick_cal left_stick_cal_x; + struct joycon_stick_cal left_stick_cal_y; + struct joycon_stick_cal right_stick_cal_x; + struct joycon_stick_cal right_stick_cal_y; + +}; + +static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len) +{ + u8 *buf; + int ret; + + buf = kmemdup(data, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = hid_hw_output_report(hdev, buf, len); + kfree(buf); + if (ret < 0) + hid_dbg(hdev, "Failed to send output report ret=%d\n", ret); + return ret; +} + +static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len) +{ + int ret; + + ret = __joycon_hid_send(ctlr->hdev, data, len); + if (ret < 0) { + memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE); + return ret; + } + + if (!wait_event_timeout(ctlr->wait, ctlr->received_resp, HZ)) { + hid_dbg(ctlr->hdev, "synchronous send/receive timed out\n"); + memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE); + return -ETIMEDOUT; + } + + ctlr->received_resp = false; + return 0; +} + +static int joycon_send_usb(struct joycon_ctlr *ctlr, u8 cmd) +{ + int ret; + u8 buf[2] = {JC_OUTPUT_USB_CMD}; + + buf[1] = cmd; + ctlr->usb_ack_match = cmd; + ctlr->msg_type = JOYCON_MSG_TYPE_USB; + ret = joycon_hid_send_sync(ctlr, buf, sizeof(buf)); + if (ret) + hid_dbg(ctlr->hdev, "send usb command failed; ret=%d\n", ret); + return ret; +} + +static int joycon_send_subcmd(struct joycon_ctlr *ctlr, + struct joycon_subcmd_request *subcmd, + size_t data_len) +{ + int ret; + + subcmd->output_id = JC_OUTPUT_RUMBLE_AND_SUBCMD; + subcmd->packet_num = ctlr->subcmd_num; + if (++ctlr->subcmd_num > 0xF) + ctlr->subcmd_num = 0; + ctlr->subcmd_ack_match = subcmd->subcmd_id; + ctlr->msg_type = JOYCON_MSG_TYPE_SUBCMD; + + ret = joycon_hid_send_sync(ctlr, (u8 *)subcmd, + sizeof(*subcmd) + data_len); + if (ret < 0) + hid_dbg(ctlr->hdev, "send subcommand failed; ret=%d\n", ret); + else + ret = 0; + return ret; +} + +/* Supply nibbles for flash and on. Ones correspond to active */ +static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on) +{ + struct joycon_subcmd_request *req; + u8 buffer[sizeof(*req) + 1] = { 0 }; + + req = (struct joycon_subcmd_request *)buffer; + req->subcmd_id = JC_SUBCMD_SET_PLAYER_LIGHTS; + req->data[0] = (flash << 4) | on; + + hid_dbg(ctlr->hdev, "setting player leds\n"); + return joycon_send_subcmd(ctlr, req, 1); +} + +static const u16 DFLT_STICK_CAL_CEN = 2000; +static const u16 DFLT_STICK_CAL_MAX = 3500; +static const u16 DFLT_STICK_CAL_MIN = 500; +static int joycon_request_calibration(struct joycon_ctlr *ctlr) +{ + struct joycon_subcmd_request *req; + u8 buffer[sizeof(*req) + 5] = { 0 }; + struct joycon_input_report *report; + struct joycon_stick_cal *cal_x; + struct joycon_stick_cal *cal_y; + s32 x_max_above; + s32 x_min_below; + s32 y_max_above; + s32 y_min_below; + u8 *data; + u8 *raw_cal; + int ret; + + req = (struct joycon_subcmd_request *)buffer; + req->subcmd_id = JC_SUBCMD_SPI_FLASH_READ; + data = req->data; + data[0] = 0xFF & JC_CAL_DATA_START; + data[1] = 0xFF & (JC_CAL_DATA_START >> 8); + data[2] = 0xFF & (JC_CAL_DATA_START >> 16); + data[3] = 0xFF & (JC_CAL_DATA_START >> 24); + data[4] = JC_CAL_DATA_SIZE; + + hid_dbg(ctlr->hdev, "requesting cal data\n"); + ret = joycon_send_subcmd(ctlr, req, 5); + if (ret) { + hid_warn(ctlr->hdev, + "Failed to read stick cal, using defaults; ret=%d\n", + ret); + + ctlr->left_stick_cal_x.center = DFLT_STICK_CAL_CEN; + ctlr->left_stick_cal_x.max = DFLT_STICK_CAL_MAX; + ctlr->left_stick_cal_x.min = DFLT_STICK_CAL_MIN; + + ctlr->left_stick_cal_y.center = DFLT_STICK_CAL_CEN; + ctlr->left_stick_cal_y.max = DFLT_STICK_CAL_MAX; + ctlr->left_stick_cal_y.min = DFLT_STICK_CAL_MIN; + + ctlr->right_stick_cal_x.center = DFLT_STICK_CAL_CEN; + ctlr->right_stick_cal_x.max = DFLT_STICK_CAL_MAX; + ctlr->right_stick_cal_x.min = DFLT_STICK_CAL_MIN; + + ctlr->right_stick_cal_y.center = DFLT_STICK_CAL_CEN; + ctlr->right_stick_cal_y.max = DFLT_STICK_CAL_MAX; + ctlr->right_stick_cal_y.min = DFLT_STICK_CAL_MIN; + + return ret; + } + + report = (struct joycon_input_report *)ctlr->input_buf; + raw_cal = &report->reply.data[5]; + + /* left stick calibration parsing */ + cal_x = &ctlr->left_stick_cal_x; + cal_y = &ctlr->left_stick_cal_y; + + x_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 0), 0, 12); + y_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 1), 4, 12); + cal_x->center = hid_field_extract(ctlr->hdev, (raw_cal + 3), 0, 12); + cal_y->center = hid_field_extract(ctlr->hdev, (raw_cal + 4), 4, 12); + x_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 6), 0, 12); + y_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 7), 4, 12); + cal_x->max = cal_x->center + x_max_above; + cal_x->min = cal_x->center - x_min_below; + cal_y->max = cal_y->center + y_max_above; + cal_y->min = cal_y->center - y_min_below; + + /* right stick calibration parsing */ + raw_cal += 9; + cal_x = &ctlr->right_stick_cal_x; + cal_y = &ctlr->right_stick_cal_y; + + cal_x->center = hid_field_extract(ctlr->hdev, (raw_cal + 0), 0, 12); + cal_y->center = hid_field_extract(ctlr->hdev, (raw_cal + 1), 4, 12); + x_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 3), 0, 12); + y_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 4), 4, 12); + x_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 6), 0, 12); + y_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 7), 4, 12); + cal_x->max = cal_x->center + x_max_above; + cal_x->min = cal_x->center - x_min_below; + cal_y->max = cal_y->center + y_max_above; + cal_y->min = cal_y->center - y_min_below; + + hid_dbg(ctlr->hdev, "calibration:\n" + "l_x_c=%d l_x_max=%d l_x_min=%d\n" + "l_y_c=%d l_y_max=%d l_y_min=%d\n" + "r_x_c=%d r_x_max=%d r_x_min=%d\n" + "r_y_c=%d r_y_max=%d r_y_min=%d\n", + ctlr->left_stick_cal_x.center, + ctlr->left_stick_cal_x.max, + ctlr->left_stick_cal_x.min, + ctlr->left_stick_cal_y.center, + ctlr->left_stick_cal_y.max, + ctlr->left_stick_cal_y.min, + ctlr->right_stick_cal_x.center, + ctlr->right_stick_cal_x.max, + ctlr->right_stick_cal_x.min, + ctlr->right_stick_cal_y.center, + ctlr->right_stick_cal_y.max, + ctlr->right_stick_cal_y.min); + + return 0; +} + +static int joycon_set_report_mode(struct joycon_ctlr *ctlr) +{ + struct joycon_subcmd_request *req; + u8 buffer[sizeof(*req) + 1] = { 0 }; + + req = (struct joycon_subcmd_request *)buffer; + req->subcmd_id = JC_SUBCMD_SET_REPORT_MODE; + req->data[0] = 0x30; /* standard, full report mode */ + + hid_dbg(ctlr->hdev, "setting controller report mode\n"); + return joycon_send_subcmd(ctlr, req, 1); +} + +static s32 joycon_map_stick_val(struct joycon_stick_cal *cal, s32 val) +{ + s32 center = cal->center; + s32 min = cal->min; + s32 max = cal->max; + s32 new_val; + + if (val > center) { + new_val = (val - center) * JC_MAX_STICK_MAG; + new_val /= (max - center); + } else { + new_val = (center - val) * -JC_MAX_STICK_MAG; + new_val /= (center - min); + } + new_val = clamp(new_val, (s32)-JC_MAX_STICK_MAG, (s32)JC_MAX_STICK_MAG); + return new_val; +} + +static void joycon_parse_report(struct joycon_ctlr *ctlr, + struct joycon_input_report *rep) +{ + struct input_dev *dev = ctlr->input; + u32 btns; + u32 id = ctlr->hdev->product; + + btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24); + + if (id != USB_DEVICE_ID_NINTENDO_JOYCONR) { + u16 raw_x; + u16 raw_y; + s32 x; + s32 y; + + /* get raw stick values */ + raw_x = hid_field_extract(ctlr->hdev, rep->left_stick, 0, 12); + raw_y = hid_field_extract(ctlr->hdev, + rep->left_stick + 1, 4, 12); + /* map the stick values */ + x = joycon_map_stick_val(&ctlr->left_stick_cal_x, raw_x); + y = -joycon_map_stick_val(&ctlr->left_stick_cal_y, raw_y); + /* report sticks */ + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + + /* report buttons */ + input_report_key(dev, BTN_TL, btns & JC_BTN_L); + input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL); + if (id != USB_DEVICE_ID_NINTENDO_PROCON) { + /* Report the S buttons as the non-existent triggers */ + input_report_key(dev, BTN_TR, btns & JC_BTN_SL_L); + input_report_key(dev, BTN_TR2, btns & JC_BTN_SR_L); + } + input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS); + input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK); + input_report_key(dev, BTN_Z, btns & JC_BTN_CAP); + input_report_key(dev, BTN_DPAD_DOWN, btns & JC_BTN_DOWN); + input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP); + input_report_key(dev, BTN_DPAD_RIGHT, btns & JC_BTN_RIGHT); + input_report_key(dev, BTN_DPAD_LEFT, btns & JC_BTN_LEFT); + } + if (id != USB_DEVICE_ID_NINTENDO_JOYCONL) { + u16 raw_x; + u16 raw_y; + s32 x; + s32 y; + + /* get raw stick values */ + raw_x = hid_field_extract(ctlr->hdev, rep->right_stick, 0, 12); + raw_y = hid_field_extract(ctlr->hdev, + rep->right_stick + 1, 4, 12); + /* map stick values */ + x = joycon_map_stick_val(&ctlr->right_stick_cal_x, raw_x); + y = -joycon_map_stick_val(&ctlr->right_stick_cal_y, raw_y); + /* report sticks */ + input_report_abs(dev, ABS_RX, x); + input_report_abs(dev, ABS_RY, y); + + /* report buttons */ + input_report_key(dev, BTN_TR, btns & JC_BTN_R); + input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR); + if (id != USB_DEVICE_ID_NINTENDO_PROCON) { + /* Report the S buttons as the non-existent triggers */ + input_report_key(dev, BTN_TL, btns & JC_BTN_SL_R); + input_report_key(dev, BTN_TL2, btns & JC_BTN_SR_R); + } + input_report_key(dev, BTN_START, btns & JC_BTN_PLUS); + input_report_key(dev, BTN_THUMBR, btns & JC_BTN_RSTICK); + input_report_key(dev, BTN_MODE, btns & JC_BTN_HOME); + input_report_key(dev, BTN_WEST, btns & JC_BTN_Y); + input_report_key(dev, BTN_NORTH, btns & JC_BTN_X); + input_report_key(dev, BTN_EAST, btns & JC_BTN_A); + input_report_key(dev, BTN_SOUTH, btns & JC_BTN_B); + } + + input_sync(dev); +} + + +static const unsigned int joycon_button_inputs_l[] = { + BTN_SELECT, BTN_Z, BTN_THUMBL, + BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, + BTN_TL, BTN_TL2, + 0 /* 0 signals end of array */ +}; + +static const unsigned int joycon_button_inputs_r[] = { + BTN_START, BTN_MODE, BTN_THUMBR, + BTN_SOUTH, BTN_EAST, BTN_NORTH, BTN_WEST, + BTN_TR, BTN_TR2, + 0 /* 0 signals end of array */ +}; + +static DEFINE_MUTEX(joycon_input_num_mutex); +static int joycon_input_create(struct joycon_ctlr *ctlr) +{ + struct hid_device *hdev; + static int input_num = 1; + const char *name; + int ret; + int i; + + hdev = ctlr->hdev; + + switch (hdev->product) { + case USB_DEVICE_ID_NINTENDO_PROCON: + name = "Nintendo Switch Pro Controller"; + break; + case USB_DEVICE_ID_NINTENDO_JOYCONL: + name = "Nintendo Switch Left Joy-Con"; + break; + case USB_DEVICE_ID_NINTENDO_JOYCONR: + name = "Nintendo Switch Right Joy-Con"; + break; + default: /* Should be impossible */ + hid_err(hdev, "Invalid hid product\n"); + return -EINVAL; + } + + ctlr->input = devm_input_allocate_device(&hdev->dev); + if (!ctlr->input) + return -ENOMEM; + ctlr->input->id.bustype = hdev->bus; + ctlr->input->id.vendor = hdev->vendor; + ctlr->input->id.product = hdev->product; + ctlr->input->id.version = hdev->version; + ctlr->input->name = name; + input_set_drvdata(ctlr->input, ctlr); + + + /* set up sticks */ + if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONR) { + input_set_abs_params(ctlr->input, ABS_X, + -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, + JC_STICK_FUZZ, JC_STICK_FLAT); + input_set_abs_params(ctlr->input, ABS_Y, + -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, + JC_STICK_FUZZ, JC_STICK_FLAT); + } + if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONL) { + input_set_abs_params(ctlr->input, ABS_RX, + -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, + JC_STICK_FUZZ, JC_STICK_FLAT); + input_set_abs_params(ctlr->input, ABS_RY, + -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, + JC_STICK_FUZZ, JC_STICK_FLAT); + } + + /* set up buttons */ + if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONR) { + for (i = 0; joycon_button_inputs_l[i] > 0; i++) + input_set_capability(ctlr->input, EV_KEY, + joycon_button_inputs_l[i]); + } + if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONL) { + for (i = 0; joycon_button_inputs_r[i] > 0; i++) + input_set_capability(ctlr->input, EV_KEY, + joycon_button_inputs_r[i]); + } + + ret = input_register_device(ctlr->input); + if (ret) + return ret; + + /* Set the default controller player leds based on controller number */ + mutex_lock(&joycon_input_num_mutex); + mutex_lock(&ctlr->output_mutex); + ret = joycon_set_player_leds(ctlr, 0, 0xF >> (4 - input_num)); + if (ret) + hid_warn(ctlr->hdev, "Failed to set leds; ret=%d\n", ret); + mutex_unlock(&ctlr->output_mutex); + if (++input_num > 4) + input_num = 1; + mutex_unlock(&joycon_input_num_mutex); + + return 0; +} + +/* Common handler for parsing inputs */ +static int joycon_ctlr_read_handler(struct joycon_ctlr *ctlr, u8 *data, + int size) +{ + int ret = 0; + + if (data[0] == JC_INPUT_SUBCMD_REPLY || data[0] == JC_INPUT_IMU_DATA || + data[0] == JC_INPUT_MCU_DATA) { + if (size >= 12) /* make sure it contains the input report */ + joycon_parse_report(ctlr, + (struct joycon_input_report *)data); + } + + return ret; +} + +static int joycon_ctlr_handle_event(struct joycon_ctlr *ctlr, u8 *data, + int size) +{ + int ret = 0; + bool match = false; + struct joycon_input_report *report; + + if (unlikely(mutex_is_locked(&ctlr->output_mutex)) && + ctlr->msg_type != JOYCON_MSG_TYPE_NONE) { + switch (ctlr->msg_type) { + case JOYCON_MSG_TYPE_USB: + if (size < 2) + break; + if (data[0] == JC_INPUT_USB_RESPONSE && + data[1] == ctlr->usb_ack_match) + match = true; + break; + case JOYCON_MSG_TYPE_SUBCMD: + if (size < sizeof(struct joycon_input_report) || + data[0] != JC_INPUT_SUBCMD_REPLY) + break; + report = (struct joycon_input_report *)data; + if (report->reply.id == ctlr->subcmd_ack_match) + match = true; + break; + default: + break; + } + + if (match) { + memcpy(ctlr->input_buf, data, + min(size, (int)JC_MAX_RESP_SIZE)); + ctlr->msg_type = JOYCON_MSG_TYPE_NONE; + ctlr->received_resp = true; + wake_up(&ctlr->wait); + + /* This message has been handled */ + return 1; + } + } + + if (ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) + ret = joycon_ctlr_read_handler(ctlr, data, size); + + return ret; +} + +static int nintendo_hid_event(struct hid_device *hdev, + struct hid_report *report, u8 *raw_data, int size) +{ + struct joycon_ctlr *ctlr = hid_get_drvdata(hdev); + + if (size < 1) + return -EINVAL; + + return joycon_ctlr_handle_event(ctlr, raw_data, size); +} + +static int nintendo_hid_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + struct joycon_ctlr *ctlr; + + hid_dbg(hdev, "probe - start\n"); + + ctlr = devm_kzalloc(&hdev->dev, sizeof(*ctlr), GFP_KERNEL); + if (!ctlr) { + ret = -ENOMEM; + goto err; + } + + ctlr->hdev = hdev; + ctlr->ctlr_state = JOYCON_CTLR_STATE_INIT; + hid_set_drvdata(hdev, ctlr); + mutex_init(&ctlr->output_mutex); + init_waitqueue_head(&ctlr->wait); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "HID parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "HW start failed\n"); + goto err; + } + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "cannot start hardware I/O\n"); + goto err_stop; + } + + hid_device_io_start(hdev); + + /* Initialize the controller */ + mutex_lock(&ctlr->output_mutex); + /* if handshake command fails, assume ble pro controller */ + if (hdev->product == USB_DEVICE_ID_NINTENDO_PROCON && + !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE)) { + hid_dbg(hdev, "detected USB controller\n"); + /* set baudrate for improved latency */ + ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M); + if (ret) { + hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret); + goto err_mutex; + } + /* handshake */ + ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE); + if (ret) { + hid_err(hdev, "Failed handshake; ret=%d\n", ret); + goto err_mutex; + } + /* + * Set no timeout (to keep controller in USB mode). + * This doesn't send a response, so ignore the timeout. + */ + joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT); + } + + /* get controller calibration data, and parse it */ + ret = joycon_request_calibration(ctlr); + if (ret) { + /* + * We can function with default calibration, but it may be + * inaccurate. Provide a warning, and continue on. + */ + hid_warn(hdev, "Analog stick positions may be inaccurate\n"); + } + + /* Set the reporting mode to 0x30, which is the full report mode */ + ret = joycon_set_report_mode(ctlr); + if (ret) { + hid_err(hdev, "Failed to set report mode; ret=%d\n", ret); + goto err_mutex; + } + + mutex_unlock(&ctlr->output_mutex); + + ret = joycon_input_create(ctlr); + if (ret) { + hid_err(hdev, "Failed to create input device; ret=%d\n", ret); + goto err_close; + } + + ctlr->ctlr_state = JOYCON_CTLR_STATE_READ; + + hid_dbg(hdev, "probe - success\n"); + return 0; + +err_mutex: + mutex_unlock(&ctlr->output_mutex); +err_close: + hid_hw_close(hdev); +err_stop: + hid_hw_stop(hdev); +err: + hid_err(hdev, "probe - fail = %d\n", ret); + return ret; +} + +static void nintendo_hid_remove(struct hid_device *hdev) +{ + hid_dbg(hdev, "remove\n"); + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id nintendo_hid_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_PROCON) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_PROCON) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_JOYCONL) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_JOYCONR) }, + { } +}; +MODULE_DEVICE_TABLE(hid, nintendo_hid_devices); + +static struct hid_driver nintendo_hid_driver = { + .name = "nintendo", + .id_table = nintendo_hid_devices, + .probe = nintendo_hid_probe, + .remove = nintendo_hid_remove, + .raw_event = nintendo_hid_event, +}; +module_hid_driver(nintendo_hid_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel J. Ogorchock "); +MODULE_DESCRIPTION("Driver for Nintendo Switch Controllers"); diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c index 10af8585c820d253b71301f23efae5db3b40fc14..95052373a828240809c25581b944f1feb2587944 100644 --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -341,6 +341,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { }, .driver_data = (void *)&sipodev_desc }, + { + .ident = "Trekstor SURFBOOK E11B", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SURFBOOK E11B"), + }, + .driver_data = (void *)&sipodev_desc + }, { .ident = "Direkt-Tek DTLAPY116-2", .matches = { diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index bccd97cdc53f9fc5bb8052a978b73f7035717e1e..d9602f3a359e158e17f2a451a71057561156ec4f 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -954,9 +954,9 @@ void hiddev_disconnect(struct hid_device *hid) hiddev->exist = 0; if (hiddev->open) { - mutex_unlock(&hiddev->existancelock); hid_hw_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); + mutex_unlock(&hiddev->existancelock); } else { mutex_unlock(&hiddev->existancelock); kfree(hiddev); diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 0824405f93fbf7a3e1254136d050b8fe027f4e69..2d93c8f454bccad43096f8c046623fe413931132 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1170,10 +1170,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm, unsigned int i = 0; struct page *pg; - if (num_pages < alloc_unit) - return 0; - - for (i = 0; (i * alloc_unit) < num_pages; i++) { + for (i = 0; i < num_pages / alloc_unit; i++) { if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) > PAGE_SIZE) return i * alloc_unit; @@ -1207,7 +1204,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm, } - return num_pages; + return i * alloc_unit; } static void balloon_up(struct work_struct *dummy) @@ -1222,9 +1219,6 @@ static void balloon_up(struct work_struct *dummy) long avail_pages; unsigned long floor; - /* The host balloons pages in 2M granularity. */ - WARN_ON_ONCE(num_pages % PAGES_IN_2M != 0); - /* * We will attempt 2M allocations. However, if we fail to * allocate 2M chunks, we will go back to 4k allocations. @@ -1234,14 +1228,13 @@ static void balloon_up(struct work_struct *dummy) avail_pages = si_mem_available(); floor = compute_balloon_floor(); - /* Refuse to balloon below the floor, keep the 2M granularity. */ + /* Refuse to balloon below the floor. */ if (avail_pages < num_pages || avail_pages - num_pages < floor) { pr_warn("Balloon request will be partially fulfilled. %s\n", avail_pages < num_pages ? "Not enough memory." : "Balloon floor reached."); num_pages = avail_pages > floor ? (avail_pages - floor) : 0; - num_pages -= num_pages % PAGES_IN_2M; } while (!done) { diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 19f2a6d48bac99d7232851ba27c8d121ab4007e5..bdd7679fd29873c61f3118b4d6f91091927e50b5 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -426,7 +426,7 @@ static int ADT7462_REG_VOLT(struct adt7462_data *data, int which) return 0x95; break; } - return -ENODEV; + return 0; } /* Provide labels for sysfs */ diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index e5234f953a6d16213920df252ac8ef23d857f924..b6e5aaa54963d6b30e35f2db363cf376176f5483 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -527,7 +527,7 @@ static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) } data->config = config; - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + hwmon_dev = devm_hwmon_device_register_with_info(dev, "jc42", data, &jc42_chip_info, NULL); return PTR_ERR_OR_ZERO(hwmon_dev); diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 58b789c28b483f062b17822a32487be6bdba14ee..94eea2ac62519625024a5bb0f4340304f65fc8c9 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -89,8 +89,8 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC_POLL_TIMEOUT 100 /* in milli-seconds */ -#define LTC_NOT_BUSY BIT(5) -#define LTC_NOT_PENDING BIT(4) +#define LTC_NOT_BUSY BIT(6) +#define LTC_NOT_PENDING BIT(5) /* * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 486356e527a53c272aba7600506139ea66dd2e1b..4b67f35fd077cfba95509ea0f12f7bf1c5d6e1eb 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -63,6 +63,7 @@ do { \ #define ITTRIGOUTACK (0xEF0) #define ITCHIN (0xEF4) #define ITTRIGIN (0xEF8) +#define DEVID (0xFC8) #define CTI_MAX_TRIGGERS (32) #define CTI_MAX_CHANNELS (4) @@ -1360,6 +1361,57 @@ static ssize_t cti_store_disable_gate(struct device *dev, } static DEVICE_ATTR(disable_gate, 0200, NULL, cti_store_disable_gate); +struct cti_reg { + void __iomem *addr; + u32 data; +}; + +static void do_smp_cross_read(void *data) +{ + struct cti_reg *reg = data; + + reg->data = readl_relaxed(reg->addr); +} + +static u32 cti_devid_cross_read(const struct cti_drvdata *drvdata) +{ + struct cti_reg reg; + + reg.addr = drvdata->base + DEVID; + smp_call_function_single(drvdata->cpu, do_smp_cross_read, ®, 1); + return reg.data; +} + +static ssize_t show_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + unsigned int ctidevid, trig_num_max, chan_num_max; + + mutex_lock(&drvdata->mutex); + + pm_runtime_get_sync(drvdata->dev); + + if (drvdata->cpu == -ENODEV) + ctidevid = cti_readl(drvdata, DEVID); + else + ctidevid = cti_devid_cross_read(drvdata); + + pm_runtime_put_sync(drvdata->dev); + + trig_num_max = (ctidevid & GENMASK(15, 8)) >> 8; + chan_num_max = (ctidevid & GENMASK(21, 16)) >> 16; + + size = scnprintf(&buf[size], PAGE_SIZE, "%d %d\n", + trig_num_max, chan_num_max); + + mutex_unlock(&drvdata->mutex); + + return size; +} +static DEVICE_ATTR_RO(show_info); + static struct attribute *cti_attrs[] = { &dev_attr_show_trigin.attr, &dev_attr_show_trigout.attr, @@ -1376,6 +1428,7 @@ static struct attribute *cti_attrs[] = { &dev_attr_show_gate.attr, &dev_attr_enable_gate.attr, &dev_attr_disable_gate.attr, + &dev_attr_show_info.attr, NULL, }; @@ -1522,6 +1575,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) cpu_pm_register_notifier(&cti_cpu_pm_notifier); registered++; } + pm_runtime_put(&adev->dev); dev_dbg(dev, "CTI initialized\n"); return 0; diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 6ebf6a2edb3325bbee48bd0c6e4a29c83600514e..ca2717137ad22d0f6b9eb47dea5dc408d5024b22 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -499,7 +499,7 @@ static int msc_configure(struct msc *msc) lockdep_assert_held(&msc->buf_mutex); if (msc->mode > MSC_MODE_MULTI) - return -ENOTSUPP; + return -EINVAL; if (msc->mode == MSC_MODE_MULTI) msc_buffer_clear_hw_header(msc); @@ -950,7 +950,7 @@ static int msc_buffer_alloc(struct msc *msc, unsigned long *nr_pages, } else if (msc->mode == MSC_MODE_MULTI) { ret = msc_buffer_multi_alloc(msc, nr_pages, nr_wins); } else { - ret = -ENOTSUPP; + ret = -EINVAL; } if (!ret) { @@ -1173,7 +1173,7 @@ static ssize_t intel_th_msc_read(struct file *file, char __user *buf, if (ret >= 0) *ppos = iter->offset; } else { - ret = -ENOTSUPP; + ret = -EINVAL; } put_count: diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index fc371444407d43d537acda150501b4d597d4b0d5..b8cbd26b60e188b9db7ff7f81b6c527aaba4d360 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -218,6 +218,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4da6), .driver_data = (kernel_ulong_t)&intel_th_2x, }, + { + /* Elkhart Lake CPU */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4529), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, { /* Elkhart Lake */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4b26), diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c index f5e1941e65b5a2dd6cebfd8a2f60798e258b986b..8915ee30a5b44ee3dc7ad7019d7dc0c818c1daf1 100644 --- a/drivers/i2c/busses/i2c-altera.c +++ b/drivers/i2c/busses/i2c-altera.c @@ -182,7 +182,7 @@ static void altr_i2c_init(struct altr_i2c_dev *idev) /* SCL Low Time */ writel(t_low, idev->base + ALTR_I2C_SCL_LOW); /* SDA Hold Time, 300ns */ - writel(div_u64(300 * clk_mhz, 1000), idev->base + ALTR_I2C_SDA_HOLD); + writel(3 * clk_mhz / 10, idev->base + ALTR_I2C_SDA_HOLD); /* Mask all master interrupt bits */ altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false); @@ -395,7 +395,6 @@ static int altr_i2c_probe(struct platform_device *pdev) struct altr_i2c_dev *idev = NULL; struct resource *res; int irq, ret; - u32 val; idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); if (!idev) @@ -422,17 +421,17 @@ static int altr_i2c_probe(struct platform_device *pdev) init_completion(&idev->msg_complete); spin_lock_init(&idev->lock); - val = device_property_read_u32(idev->dev, "fifo-size", + ret = device_property_read_u32(idev->dev, "fifo-size", &idev->fifo_size); - if (val) { + if (ret) { dev_err(&pdev->dev, "FIFO size set to default of %d\n", ALTR_I2C_DFLT_FIFO_SZ); idev->fifo_size = ALTR_I2C_DFLT_FIFO_SZ; } - val = device_property_read_u32(idev->dev, "clock-frequency", + ret = device_property_read_u32(idev->dev, "clock-frequency", &idev->bus_clk_rate); - if (val) { + if (ret) { dev_err(&pdev->dev, "Default to 100kHz\n"); idev->bus_clk_rate = 100000; /* default clock rate */ } diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index bb68957d3da5e6846169ae1b26bfd37f9e6d1caa..aa5c55bd8b112ba1a852e5377153e736c33f6226 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -498,6 +498,7 @@ static int hix5hd2_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&priv->adap); pm_runtime_disable(priv->dev); pm_runtime_set_suspended(priv->dev); + clk_disable_unprepare(priv->clk); return 0; } diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 30132c3957cdc3d2d76e03a5a82511d9b0a27829..41ca9ff7b5da75a7b418f61c7a87f028c28403c6 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -82,25 +82,6 @@ #define JZ4780_I2C_STA_TFNF BIT(1) #define JZ4780_I2C_STA_ACT BIT(0) -static const char * const jz4780_i2c_abrt_src[] = { - "ABRT_7B_ADDR_NOACK", - "ABRT_10ADDR1_NOACK", - "ABRT_10ADDR2_NOACK", - "ABRT_XDATA_NOACK", - "ABRT_GCALL_NOACK", - "ABRT_GCALL_READ", - "ABRT_HS_ACKD", - "SBYTE_ACKDET", - "ABRT_HS_NORSTRT", - "SBYTE_NORSTRT", - "ABRT_10B_RD_NORSTRT", - "ABRT_MASTER_DIS", - "ARB_LOST", - "SLVFLUSH_TXFIFO", - "SLV_ARBLOST", - "SLVRD_INTX", -}; - #define JZ4780_I2C_INTST_IGC BIT(11) #define JZ4780_I2C_INTST_ISTT BIT(10) #define JZ4780_I2C_INTST_ISTP BIT(9) @@ -538,21 +519,8 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id) static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src) { - int i; - - dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src); - dev_err(&i2c->adap.dev, "device addr=%x\n", - jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)); - dev_err(&i2c->adap.dev, "send cmd count:%d %d\n", - i2c->cmd, i2c->cmd_buf[i2c->cmd]); - dev_err(&i2c->adap.dev, "receive data count:%d %d\n", - i2c->cmd, i2c->data_buf[i2c->cmd]); - - for (i = 0; i < 16; i++) { - if (src & BIT(i)) - dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n", - i, jz4780_i2c_abrt_src[i]); - } + dev_dbg(&i2c->adap.dev, "txabrt: 0x%08x, cmd: %d, send: %d, recv: %d\n", + src, i2c->cmd, i2c->cmd_buf[i2c->cmd], i2c->data_buf[i2c->cmd]); } static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 8eeea7f722612d5eeedb63d07618748559c63262..1984b22c1dfa1408c1496b5259aebc4125e2cd8b 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -395,6 +395,7 @@ static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str, case MSM_GPI_QUP_MAX_EVENT: /* fall through to stall impacted channel */ case MSM_GPI_QUP_CH_ERROR: + case MSM_GPI_QUP_FW_ERROR: case MSM_GPI_QUP_PENDING_EVENT: case MSM_GPI_QUP_EOT_DESC_MISMATCH: break; @@ -412,9 +413,9 @@ static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str, } if (cb_str->cb_event != MSM_GPI_QUP_NOTIFY) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI QN err:0x%x, status:0x%x, err:%d\n", - cb_str->error_log.error_code, - m_stat, cb_str->cb_event); + "GSI QN err:0x%x, status:0x%x, err:%d\n", + cb_str->error_log.error_code, m_stat, + cb_str->cb_event); } static void gi2c_gsi_cb_err(struct msm_gpi_dma_async_tx_cb_param *cb, @@ -538,6 +539,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], struct msm_gpi_tre *go_t = &gi2c->go_t; struct device *rx_dev = gi2c->wrapper_dev; struct device *tx_dev = gi2c->wrapper_dev; + reinit_completion(&gi2c->xfer); gi2c->cur = &msgs[i]; qcom_geni_i2c_calc_timeout(gi2c); @@ -708,7 +710,14 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; - reinit_completion(&gi2c->xfer); + + /* Client to respect system suspend */ + if (!pm_runtime_enabled(gi2c->dev)) { + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "%s: System suspended\n", __func__); + return -EACCES; + } + mutex_lock(&gi2c->i2c_ssr.ssr_lock); if (gi2c->i2c_ssr.is_ssr_down) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, @@ -716,12 +725,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return -EINVAL; } - /* Client to respect system suspend */ - if (!pm_runtime_enabled(gi2c->dev)) { - GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, - "%s: System suspended\n", __func__); - return -EACCES; - } ret = pm_runtime_get_sync(gi2c->dev); if (ret < 0) { @@ -856,6 +859,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, geni_abort_m_cmd(gi2c->base); } } + gi2c->cur_wr = 0; + gi2c->cur_rd = 0; gi2c->cur_wr = 0; gi2c->cur_rd = 0; @@ -889,8 +894,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); - gi2c->cur_wr = 0; - gi2c->cur_rd = 0; gi2c->cur = NULL; gi2c->err = 0; GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 9e62f893958aa0016c14e74564b9025f8159c99e..81158ae8bfe361f3416f541651cfc0f2b3287762 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -437,6 +437,7 @@ static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev) /** * st_i2c_rd_fill_tx_fifo() - Fill the Tx FIFO in read mode * @i2c_dev: Controller's private data + * @max: Maximum amount of data to fill into the Tx FIFO * * This functions fills the Tx FIFO with fixed pattern when * in read mode to trigger clock. diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index df9800aaeac71fc5778557d99121364dc6b61dbe..0d4d5dcf94f3901442a707aaa42a1725ca7b3456 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -352,10 +352,18 @@ static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) { struct device *dev; + struct i2c_client *client; dev = bus_find_device(&i2c_bus_type, NULL, adev, i2c_acpi_find_match_device); - return dev ? i2c_verify_client(dev) : NULL; + if (!dev) + return NULL; + + client = i2c_verify_client(dev); + if (!client) + put_device(dev); + + return client; } static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index b127ed60c73364f34a114a8a3033aa42c906b8ca..9dde8390da09bd95e91c2885d1253612c4b82ff4 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -65,6 +65,9 @@ static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) struct ide_timing t; u8 arttim = 0; + if (drive->dn >= ARRAY_SIZE(drwtim_regs)) + return; + ide_timing_compute(drive, mode, &t, T, 0); /* diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c index a97affca18abe153be1ba4b3285d25390171e69c..0f57d45484d1d97933ca6dba3fbedcf8cfcf081e 100644 --- a/drivers/ide/serverworks.c +++ b/drivers/ide/serverworks.c @@ -114,6 +114,9 @@ static void svwks_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) struct pci_dev *dev = to_pci_dev(hwif->dev); const u8 pio = drive->pio_mode - XFER_PIO_0; + if (drive->dn >= ARRAY_SIZE(drive_pci)) + return; + pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]); if (svwks_csb_check(dev)) { @@ -140,6 +143,9 @@ static void svwks_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; + if (drive->dn >= ARRAY_SIZE(drive_pci2)) + return; + pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing); pci_read_config_byte(dev, 0x54, &ultra_enable); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 07246a6037e319d863b4ed35853bc6098f50e0f7..f64781d03d5d3503f88f16ec32aee34e26bd8d5c 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -543,7 +543,7 @@ static const struct iio_info ad7797_info = { .read_raw = &ad7793_read_raw, .write_raw = &ad7793_write_raw, .write_raw_get_fmt = &ad7793_write_raw_get_fmt, - .attrs = &ad7793_attribute_group, + .attrs = &ad7797_attribute_group, .validate_trigger = ad_sd_validate_trigger, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index a70ef7fec95f05065295a41280d7b17632aac7c9..34639ee2d2ce69f3d13ef539e142c1ac195c7330 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -300,6 +300,27 @@ static const struct iio_chan_spec at91_adc_channels[] = { + AT91_SAMA5D2_DIFF_CHAN_CNT + 1), }; +static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan) +{ + int i; + + for (i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].scan_index == chan) + return i; + } + return -EINVAL; +} + +static inline struct iio_chan_spec const * +at91_adc_chan_get(struct iio_dev *indio_dev, int chan) +{ + int index = at91_adc_chan_xlate(indio_dev, chan); + + if (index < 0) + return NULL; + return indio_dev->channels + index; +} + static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) { struct iio_dev *indio = iio_trigger_get_drvdata(trig); @@ -317,7 +338,24 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) at91_adc_writel(st, AT91_SAMA5D2_TRGR, status); for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) { - struct iio_chan_spec const *chan = indio->channels + bit; + struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit); + u32 cor; + + if (!chan) + continue; + if (state) { + cor = at91_adc_readl(st, AT91_SAMA5D2_COR); + + if (chan->differential) + cor |= (BIT(chan->channel) | + BIT(chan->channel2)) << + AT91_SAMA5D2_COR_DIFF_OFFSET; + else + cor &= ~(BIT(chan->channel) << + AT91_SAMA5D2_COR_DIFF_OFFSET); + + at91_adc_writel(st, AT91_SAMA5D2_COR, cor); + } if (state) { at91_adc_writel(st, AT91_SAMA5D2_CHER, @@ -398,8 +436,11 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) u8 bit; for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) { - struct iio_chan_spec const *chan = indio->channels + bit; + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio, bit); + if (!chan) + continue; st->buffer[i] = at91_adc_readl(st, chan->address); i++; } diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c index 02dfbf86d6c214acecfccbf1726373709f7f08ce..20136383c66bc353ca41065b30284cabe9067542 100644 --- a/drivers/iio/adc/qcom-rradc.c +++ b/drivers/iio/adc/qcom-rradc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -199,6 +199,9 @@ #define FG_RR_TP_REV_VERSION2 29 #define FG_RR_TP_REV_VERSION3 32 +#define BATT_ID_SETTLE_SHIFT 5 +#define RRADC_BATT_ID_DELAY_MAX 8 + /* * The channel number is not a physical index in hardware, * rather it's a list of supported channels and an index to @@ -229,6 +232,7 @@ struct rradc_chip { struct mutex lock; struct regmap *regmap; u16 base; + int batt_id_delay; struct iio_chan_spec *iio_chans; unsigned int nchannels; struct rradc_chan_prop *chan_props; @@ -256,6 +260,8 @@ struct rradc_chan_prop { u16 adc_code, int *result); }; +static const int batt_id_delays[] = {0, 1, 4, 12, 20, 40, 60, 80}; + static int rradc_masked_write(struct rradc_chip *rr_adc, u16 offset, u8 mask, u8 val) { @@ -767,8 +773,7 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip, if (((prop->channel == RR_ADC_CHG_TEMP) || (prop->channel == RR_ADC_SKIN_TEMP) || - (prop->channel == RR_ADC_USBIN_I) || - (prop->channel == RR_ADC_DIE_TEMP)) && + (prop->channel == RR_ADC_USBIN_I)) && ((!rradc_is_usb_present(chip)))) { pr_debug("USB not present for %d\n", prop->channel); rc = -ENODATA; @@ -854,7 +859,7 @@ static int rradc_enable_batt_id_channel(struct rradc_chip *chip, bool enable) static int rradc_do_batt_id_conversion(struct rradc_chip *chip, struct rradc_chan_prop *prop, u16 *data, u8 *buf) { - int rc = 0, ret = 0; + int rc = 0, ret = 0, batt_id_delay; rc = rradc_enable_batt_id_channel(chip, true); if (rc < 0) { @@ -862,6 +867,14 @@ static int rradc_do_batt_id_conversion(struct rradc_chip *chip, return rc; } + if (chip->batt_id_delay != -EINVAL) { + batt_id_delay = chip->batt_id_delay << BATT_ID_SETTLE_SHIFT; + rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CFG, + batt_id_delay, batt_id_delay); + if (rc < 0) + pr_err("BATT_ID settling time config failed:%d\n", rc); + } + rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER, FG_ADC_RR_BATT_ID_TRIGGER_CTL, FG_ADC_RR_BATT_ID_TRIGGER_CTL); @@ -938,6 +951,30 @@ static int rradc_do_conversion(struct rradc_chip *chip, goto fail; } break; + case RR_ADC_DIE_TEMP: + /* Force conversion every cycle */ + rc = rradc_masked_write(chip, FG_ADC_RR_PMI_DIE_TEMP_TRIGGER, + FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK, + FG_ADC_RR_USB_IN_V_EVERY_CYCLE); + if (rc < 0) { + pr_err("Force every cycle update failed:%d\n", rc); + goto fail; + } + + rc = rradc_read_channel_with_continuous_mode(chip, prop, buf); + if (rc < 0) { + pr_err("Error reading in continuous mode:%d\n", rc); + goto fail; + } + + /* Restore aux_therm trigger */ + rc = rradc_masked_write(chip, FG_ADC_RR_PMI_DIE_TEMP_TRIGGER, + FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK, 0); + if (rc < 0) { + pr_err("Restore every cycle update failed:%d\n", rc); + goto fail; + } + break; case RR_ADC_CHG_HOT_TEMP: case RR_ADC_CHG_TOO_HOT_TEMP: case RR_ADC_SKIN_HOT_TEMP: @@ -1106,6 +1143,21 @@ static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node) return rc; } + chip->batt_id_delay = -EINVAL; + + rc = of_property_read_u32(node, "qcom,batt-id-delay-ms", + &chip->batt_id_delay); + if (!rc) { + for (i = 0; i < RRADC_BATT_ID_DELAY_MAX; i++) { + if (chip->batt_id_delay == batt_id_delays[i]) + break; + } + if (i == RRADC_BATT_ID_DELAY_MAX) + pr_err("Invalid batt_id_delay, rc=%d\n", rc); + else + chip->batt_id_delay = i; + } + chip->base = base; chip->revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0); if (chip->revid_dev_node) { diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index f34c2ac8490e81849d0fcbbb5999909a295a3d7b..4ba747ce108d550335a0cbf9a0519698efb1f0f0 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -796,6 +796,10 @@ static const struct adc_channels adc_chans_rev2[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_THERM_100K_PULLUP) [ANA_IN] = ADC_CHAN_TEMP("drax_temp", 1, SCALE_HW_CALIB_PMIC_THERM) + [ADC_AMUX_THM1] = ADC_CHAN_VOLT("amux_thm1", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_AMUX_THM3] = ADC_CHAN_VOLT("amux_thm3", 1, + SCALE_HW_CALIB_DEFAULT) }; static int adc_get_dt_channel_data(struct device *dev, diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 258a4712167a26ac0dc4cccb249bc8025d997f69..3cfb2d4b24412f63351f39ef931669600b72ca74 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1311,8 +1311,30 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) static void stm32_adc_dma_buffer_done(void *data) { struct iio_dev *indio_dev = data; + struct stm32_adc *adc = iio_priv(indio_dev); + int residue = stm32_adc_dma_residue(adc); + + /* + * In DMA mode the trigger services of IIO are not used + * (e.g. no call to iio_trigger_poll). + * Calling irq handler associated to the hardware trigger is not + * relevant as the conversions have already been done. Data + * transfers are performed directly in DMA callback instead. + * This implementation avoids to call trigger irq handler that + * may sleep, in an atomic context (DMA irq handler context). + */ + dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); - iio_trigger_poll_chained(indio_dev->trig); + while (residue >= indio_dev->scan_bytes) { + u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; + + iio_push_to_buffers(indio_dev, buffer); + + residue -= indio_dev->scan_bytes; + adc->bufi += indio_dev->scan_bytes; + if (adc->bufi >= adc->rx_buf_sz) + adc->bufi = 0; + } } static int stm32_adc_dma_start(struct iio_dev *indio_dev) @@ -1648,6 +1670,7 @@ static int stm32_adc_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; struct device *dev = &pdev->dev; + irqreturn_t (*handler)(int irq, void *p) = NULL; struct stm32_adc *adc; int ret; @@ -1730,9 +1753,11 @@ static int stm32_adc_probe(struct platform_device *pdev) if (ret < 0) goto err_clk_disable; + if (!adc->dma_chan) + handler = &stm32_adc_trigger_handler; + ret = iio_triggered_buffer_setup(indio_dev, - &iio_pollfunc_store_time, - &stm32_adc_trigger_handler, + &iio_pollfunc_store_time, handler, &stm32_adc_buffer_setup_ops); if (ret) { dev_err(&pdev->dev, "buffer setup failed\n"); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index e89711b30ae8f01b8fce33a8e8eb781fef238e3b..36db28b9099f5337ea76e45c1e655e0777f16303 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -660,7 +660,7 @@ static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state) spin_lock_irqsave(&xadc->lock, flags); xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); - xadc_write_reg(xadc, XADC_AXI_REG_IPISR, val & XADC_AXI_INT_EOS); + xadc_write_reg(xadc, XADC_AXI_REG_IPISR, XADC_AXI_INT_EOS); if (state) val |= XADC_AXI_INT_EOS; else @@ -709,13 +709,14 @@ static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode) { uint16_t val; + /* Powerdown the ADC-B when it is not needed. */ switch (seq_mode) { case XADC_CONF1_SEQ_SIMULTANEOUS: case XADC_CONF1_SEQ_INDEPENDENT: - val = XADC_CONF2_PD_ADC_B; + val = 0; break; default: - val = 0; + val = XADC_CONF2_PD_ADC_B; break; } @@ -784,6 +785,16 @@ static int xadc_preenable(struct iio_dev *indio_dev) if (ret) goto err; + /* + * In simultaneous mode the upper and lower aux channels are samples at + * the same time. In this mode the upper 8 bits in the sequencer + * register are don't care and the lower 8 bits control two channels + * each. As such we must set the bit if either the channel in the lower + * group or the upper group is enabled. + */ + if (seq_mode == XADC_CONF1_SEQ_SIMULTANEOUS) + scan_mask = ((scan_mask >> 8) | scan_mask) & 0xff0000; + ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16); if (ret) goto err; diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 0bff76e96950e685ed08e26988ba8057d2eec5cb..283ecd4ea800d5ab7bdea4ae69bf6eefd854c9e7 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -563,7 +563,7 @@ static int ak8974_read_raw(struct iio_dev *indio_dev, * We read all axes and discard all but one, for optimized * reading, use the triggered buffer. */ - *val = le16_to_cpu(hw_values[chan->address]); + *val = (s16)le16_to_cpu(hw_values[chan->address]); ret = IIO_VAL_INT; } diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index eb212f8c88793b2c1029f087b40733039b5d9f96..0e4da570f22f630d3b000a87681e7bee821703ad 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -161,7 +161,8 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, return 0; } -static void stm32_timer_stop(struct stm32_timer_trigger *priv) +static void stm32_timer_stop(struct stm32_timer_trigger *priv, + struct iio_trigger *trig) { u32 ccer, cr1; @@ -179,6 +180,12 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv) regmap_write(priv->regmap, TIM_PSC, 0); regmap_write(priv->regmap, TIM_ARR, 0); + /* Force disable master mode */ + if (stm32_timer_is_trgo2_name(trig->name)) + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + else + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0); + /* Make sure that registers are updated */ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); } @@ -197,7 +204,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev, return ret; if (freq == 0) { - stm32_timer_stop(priv); + stm32_timer_stop(priv, trig); } else { ret = stm32_timer_start(priv, trig, freq); if (ret) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index aadaa9e84eeea0fd7756efc70646f87e2fd5d307..c2bbe0df0931c70dea994caded347ab6dc7863a3 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -140,7 +140,7 @@ int ib_nl_handle_ip_res_resp(struct sk_buff *skb, if (ib_nl_is_good_ip_resp(nlh)) ib_nl_process_good_ip_rsep(nlh); - return skb->len; + return 0; } static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr, diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 2af79e4f3235934252506d4e51c2f6833f8a3f67..80a8eb7e5d6ec1df23b236e9317963f75a075203 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1143,6 +1143,7 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, /* Sharing an ib_cm_id with different handlers is not * supported */ spin_unlock_irqrestore(&cm.lock, flags); + ib_destroy_cm_id(cm_id); return ERR_PTR(-EINVAL); } atomic_inc(&cm_id_priv->refcount); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 1614f6f3677c0b50560d1be5b61d7d84e8f349a2..d901591db9c8eb62d9f5630d567d8437f3a33975 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2661,6 +2661,7 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) err2: kfree(route->path_rec); route->path_rec = NULL; + route->num_paths = 0; err1: kfree(work); return ret; diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 30d7277249b8abb63f03f5d78bca665b0682727f..16b0c10348e84194880d5fe1f936d714de980ac6 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -158,8 +158,10 @@ static void dealloc_work_entries(struct iwcm_id_private *cm_id_priv) { struct list_head *e, *tmp; - list_for_each_safe(e, tmp, &cm_id_priv->work_free_list) + list_for_each_safe(e, tmp, &cm_id_priv->work_free_list) { + list_del(e); kfree(list_entry(e, struct iwcm_work, free_list)); + } } static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 50068b0a91fa449917b7de4b3d8ed7ce582991f8..83dad5401c932206387cec497d9a3c15e7d3c99a 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -1078,7 +1078,7 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb, } settimeout_out: - return skb->len; + return 0; } static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh) @@ -1149,7 +1149,7 @@ int ib_nl_handle_resolve_resp(struct sk_buff *skb, } resp_out: - return skb->len; + return 0; } static void free_sm_ah(struct kref *kref) diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c index a3dd88c57be78295ee23bd538013ddc275cfbd1d..f4770601e6bfa72d1ccb5def067983454ceee217 100644 --- a/drivers/infiniband/core/security.c +++ b/drivers/infiniband/core/security.c @@ -338,27 +338,20 @@ static struct ib_ports_pkeys *get_new_pps(const struct ib_qp *qp, if (!new_pps) return NULL; - if (qp_attr_mask & (IB_QP_PKEY_INDEX | IB_QP_PORT)) { - if (!qp_pps) { - new_pps->main.port_num = qp_attr->port_num; - new_pps->main.pkey_index = qp_attr->pkey_index; - } else { - new_pps->main.port_num = (qp_attr_mask & IB_QP_PORT) ? - qp_attr->port_num : - qp_pps->main.port_num; - - new_pps->main.pkey_index = - (qp_attr_mask & IB_QP_PKEY_INDEX) ? - qp_attr->pkey_index : - qp_pps->main.pkey_index; - } - new_pps->main.state = IB_PORT_PKEY_VALID; - } else if (qp_pps) { + if (qp_attr_mask & IB_QP_PORT) + new_pps->main.port_num = qp_attr->port_num; + else if (qp_pps) new_pps->main.port_num = qp_pps->main.port_num; + + if (qp_attr_mask & IB_QP_PKEY_INDEX) + new_pps->main.pkey_index = qp_attr->pkey_index; + else if (qp_pps) new_pps->main.pkey_index = qp_pps->main.pkey_index; - if (qp_pps->main.state != IB_PORT_PKEY_NOT_VALID) - new_pps->main.state = IB_PORT_PKEY_VALID; - } + + if (((qp_attr_mask & IB_QP_PKEY_INDEX) && + (qp_attr_mask & IB_QP_PORT)) || + (qp_pps && qp_pps->main.state != IB_PORT_PKEY_NOT_VALID)) + new_pps->main.state = IB_PORT_PKEY_VALID; if (qp_attr_mask & IB_QP_ALT_PATH) { new_pps->alt.port_num = qp_attr->alt_port_num; diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 55e8f5ed8b3c69563033c50fc963446837284475..57b41125b1462e4c9e9542dbac06c0e937434ac0 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -637,7 +637,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, while (bcnt > 0) { const size_t gup_num_pages = min_t(size_t, - (bcnt + BIT(page_shift) - 1) >> page_shift, + ALIGN(bcnt, PAGE_SIZE) / PAGE_SIZE, PAGE_SIZE / sizeof(struct page *)); down_read(&owning_mm->mmap_sem); diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 4a0b7c00347718db316989f8c5331ff652e322d3..cb5785dda524e5c7aad967da86104870ed645aa3 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -1686,6 +1686,14 @@ static u64 access_sw_pio_drain(const struct cntr_entry *entry, return dd->verbs_dev.n_piodrain; } +static u64 access_sw_ctx0_seq_drop(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = context; + + return dd->ctx0_seq_drop; +} + static u64 access_sw_vtx_wait(const struct cntr_entry *entry, void *context, int vl, int mode, u64 data) { @@ -4246,6 +4254,8 @@ static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = { access_sw_cpu_intr), [C_SW_CPU_RCV_LIM] = CNTR_ELEM("RcvLimit", 0, 0, CNTR_NORMAL, access_sw_cpu_rcv_limit), +[C_SW_CTX0_SEQ_DROP] = CNTR_ELEM("SeqDrop0", 0, 0, CNTR_NORMAL, + access_sw_ctx0_seq_drop), [C_SW_VTX_WAIT] = CNTR_ELEM("vTxWait", 0, 0, CNTR_NORMAL, access_sw_vtx_wait), [C_SW_PIO_WAIT] = CNTR_ELEM("PioWait", 0, 0, CNTR_NORMAL, diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index 50b8645d0b876dbf6d58f56d677e3cfcc7984e55..a88ef2433cea28c1c33e85244fac2356a0104f46 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -864,6 +864,7 @@ enum { C_DC_PG_STS_TX_MBE_CNT, C_SW_CPU_INTR, C_SW_CPU_RCV_LIM, + C_SW_CTX0_SEQ_DROP, C_SW_VTX_WAIT, C_SW_PIO_WAIT, C_SW_PIO_DRAIN, diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c index 72c836b826ca84d29fffceceea036b753d095722..7aa1aabb7a43c23eeb30f4f099f69d1c362661c1 100644 --- a/drivers/infiniband/hw/hfi1/driver.c +++ b/drivers/infiniband/hw/hfi1/driver.c @@ -710,6 +710,7 @@ static noinline int skip_rcv_packet(struct hfi1_packet *packet, int thread) { int ret; + packet->rcd->dd->ctx0_seq_drop++; /* Set up for the next packet */ packet->rhqoff += packet->rsize; if (packet->rhqoff >= packet->maxcnt) diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 76861a8b5c1ec28ccfcdce9a6e9a7ff9909b5260..b3ab803bf8b1e41ad85dd433f796aff32584f93b 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -195,23 +195,24 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) fd = kzalloc(sizeof(*fd), GFP_KERNEL); - if (fd) { - fd->rec_cpu_num = -1; /* no cpu affinity by default */ - fd->mm = current->mm; - mmgrab(fd->mm); - fd->dd = dd; - kobject_get(&fd->dd->kobj); - fp->private_data = fd; - } else { - fp->private_data = NULL; - - if (atomic_dec_and_test(&dd->user_refcount)) - complete(&dd->user_comp); - - return -ENOMEM; - } - + if (!fd || init_srcu_struct(&fd->pq_srcu)) + goto nomem; + spin_lock_init(&fd->pq_rcu_lock); + spin_lock_init(&fd->tid_lock); + spin_lock_init(&fd->invalid_lock); + fd->rec_cpu_num = -1; /* no cpu affinity by default */ + fd->mm = current->mm; + mmgrab(fd->mm); + fd->dd = dd; + kobject_get(&fd->dd->kobj); + fp->private_data = fd; return 0; +nomem: + kfree(fd); + fp->private_data = NULL; + if (atomic_dec_and_test(&dd->user_refcount)) + complete(&dd->user_comp); + return -ENOMEM; } static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, @@ -417,21 +418,30 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) { struct hfi1_filedata *fd = kiocb->ki_filp->private_data; - struct hfi1_user_sdma_pkt_q *pq = fd->pq; + struct hfi1_user_sdma_pkt_q *pq; struct hfi1_user_sdma_comp_q *cq = fd->cq; int done = 0, reqs = 0; unsigned long dim = from->nr_segs; + int idx; - if (!cq || !pq) + idx = srcu_read_lock(&fd->pq_srcu); + pq = srcu_dereference(fd->pq, &fd->pq_srcu); + if (!cq || !pq) { + srcu_read_unlock(&fd->pq_srcu, idx); return -EIO; + } - if (!iter_is_iovec(from) || !dim) + if (!iter_is_iovec(from) || !dim) { + srcu_read_unlock(&fd->pq_srcu, idx); return -EINVAL; + } trace_hfi1_sdma_request(fd->dd, fd->uctxt->ctxt, fd->subctxt, dim); - if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) + if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) { + srcu_read_unlock(&fd->pq_srcu, idx); return -ENOSPC; + } while (dim) { int ret; @@ -449,6 +459,7 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) reqs++; } + srcu_read_unlock(&fd->pq_srcu, idx); return reqs; } @@ -824,6 +835,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) if (atomic_dec_and_test(&dd->user_refcount)) complete(&dd->user_comp); + cleanup_srcu_struct(&fdata->pq_srcu); kfree(fdata); return 0; } diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index af550c1767e31ea7a9501aff0e18e4024e5f6686..cf9bc95d80396b74803494e255a06428a4f6f584 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1043,6 +1043,8 @@ struct hfi1_devdata { char *boardname; /* human readable board info */ + u64 ctx0_seq_drop; + /* reset value */ u64 z_int_counter; u64 z_rcv_limit; @@ -1353,10 +1355,13 @@ struct mmu_rb_handler; /* Private data for file operations */ struct hfi1_filedata { + struct srcu_struct pq_srcu; struct hfi1_devdata *dd; struct hfi1_ctxtdata *uctxt; struct hfi1_user_sdma_comp_q *cq; - struct hfi1_user_sdma_pkt_q *pq; + /* update side lock for SRCU */ + spinlock_t pq_rcu_lock; + struct hfi1_user_sdma_pkt_q __rcu *pq; u16 subctxt; /* for cpu affinity; -1 if none */ int rec_cpu_num; diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c index 25e867393463e5cc634d9a304e85dba8f5ddb89d..e3e8d65646e34cd80adcd0f1a56d4f053990e888 100644 --- a/drivers/infiniband/hw/hfi1/sysfs.c +++ b/drivers/infiniband/hw/hfi1/sysfs.c @@ -670,7 +670,11 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, dd_dev_err(dd, "Skipping sc2vl sysfs info, (err %d) port %u\n", ret, port_num); - goto bail; + /* + * Based on the documentation for kobject_init_and_add(), the + * caller should call kobject_put even if this call fails. + */ + goto bail_sc2vl; } kobject_uevent(&ppd->sc2vl_kobj, KOBJ_ADD); @@ -680,7 +684,7 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, dd_dev_err(dd, "Skipping sl2sc sysfs info, (err %d) port %u\n", ret, port_num); - goto bail_sc2vl; + goto bail_sl2sc; } kobject_uevent(&ppd->sl2sc_kobj, KOBJ_ADD); @@ -690,7 +694,7 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, dd_dev_err(dd, "Skipping vl2mtu sysfs info, (err %d) port %u\n", ret, port_num); - goto bail_sl2sc; + goto bail_vl2mtu; } kobject_uevent(&ppd->vl2mtu_kobj, KOBJ_ADD); @@ -700,7 +704,7 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, dd_dev_err(dd, "Skipping Congestion Control sysfs info, (err %d) port %u\n", ret, port_num); - goto bail_vl2mtu; + goto bail_cc; } kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD); @@ -738,7 +742,6 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, kobject_put(&ppd->sl2sc_kobj); bail_sc2vl: kobject_put(&ppd->sc2vl_kobj); -bail: return ret; } @@ -858,8 +861,13 @@ int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd) for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i) device_remove_file(&dev->dev, hfi1_attributes[i]); - for (i = 0; i < dd->num_sdma; i++) - kobject_del(&dd->per_sdma[i].kobj); + /* + * The function kobject_put() will call kobject_del() if the kobject + * has been added successfully. The sysfs files created under the + * kobject directory will also be removed during the process. + */ + for (; i >= 0; i--) + kobject_put(&dd->per_sdma[i].kobj); return ret; } @@ -872,6 +880,10 @@ void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd) struct hfi1_pportdata *ppd; int i; + /* Unwind operations in hfi1_verbs_register_sysfs() */ + for (i = 0; i < dd->num_sdma; i++) + kobject_put(&dd->per_sdma[i].kobj); + for (i = 0; i < dd->num_pports; i++) { ppd = &dd->pport[i]; diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c index b38e3808836ca735c451fdd11c4275e395c751d0..c6d085e1c10d242025296b9bea3c7bb449451f75 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c @@ -90,9 +90,6 @@ int hfi1_user_exp_rcv_init(struct hfi1_filedata *fd, struct hfi1_devdata *dd = uctxt->dd; int ret = 0; - spin_lock_init(&fd->tid_lock); - spin_lock_init(&fd->invalid_lock); - fd->entry_to_rb = kcalloc(uctxt->expected_count, sizeof(struct rb_node *), GFP_KERNEL); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index 4854a4a453b5f8340e1cbb38ec55a73620c0e2ab..f23d47194c1266b90c094a084fcdf365a49e95a2 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -179,7 +179,6 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, pq = kzalloc(sizeof(*pq), GFP_KERNEL); if (!pq) return -ENOMEM; - pq->dd = dd; pq->ctxt = uctxt->ctxt; pq->subctxt = fd->subctxt; @@ -236,7 +235,7 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, goto pq_mmu_fail; } - fd->pq = pq; + rcu_assign_pointer(fd->pq, pq); fd->cq = cq; return 0; @@ -264,8 +263,14 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd, trace_hfi1_sdma_user_free_queues(uctxt->dd, uctxt->ctxt, fd->subctxt); - pq = fd->pq; + spin_lock(&fd->pq_rcu_lock); + pq = srcu_dereference_check(fd->pq, &fd->pq_srcu, + lockdep_is_held(&fd->pq_rcu_lock)); if (pq) { + rcu_assign_pointer(fd->pq, NULL); + spin_unlock(&fd->pq_rcu_lock); + synchronize_srcu(&fd->pq_srcu); + /* at this point there can be no more new requests */ if (pq->handler) hfi1_mmu_rb_unregister(pq->handler); iowait_sdma_drain(&pq->busy); @@ -277,7 +282,8 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd, kfree(pq->req_in_use); kmem_cache_destroy(pq->txreq_cache); kfree(pq); - fd->pq = NULL; + } else { + spin_unlock(&fd->pq_rcu_lock); } if (fd->cq) { vfree(fd->cq->comps); @@ -321,7 +327,8 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, { int ret = 0, i; struct hfi1_ctxtdata *uctxt = fd->uctxt; - struct hfi1_user_sdma_pkt_q *pq = fd->pq; + struct hfi1_user_sdma_pkt_q *pq = + srcu_dereference(fd->pq, &fd->pq_srcu); struct hfi1_user_sdma_comp_q *cq = fd->cq; struct hfi1_devdata *dd = pq->dd; unsigned long idx = 0; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index ad78b471c1129cd4afabb2dcbe94e5350be2f68e..b962dbcfe9a78194447017ca10b61756902e152d 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -593,10 +593,11 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet, opa_get_lid(packet->dlid, 9B)); if (!mcast) goto drop; + rcu_read_lock(); list_for_each_entry_rcu(p, &mcast->qp_list, list) { packet->qp = p->qp; if (hfi1_do_pkey_check(packet)) - goto drop; + goto unlock_drop; spin_lock_irqsave(&packet->qp->r_lock, flags); packet_handler = qp_ok(packet); if (likely(packet_handler)) @@ -605,6 +606,7 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet, ibp->rvp.n_pkt_drops++; spin_unlock_irqrestore(&packet->qp->r_lock, flags); } + rcu_read_unlock(); /* * Notify rvt_multicast_detach() if it is waiting for us * to finish. diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 7e73a1a6cb67146cc545b2296db034a253947ccf..3f8511104c5b6319d9fc614c5e7073a53681fcf4 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1614,8 +1614,9 @@ static int __mlx4_ib_create_default_rules( int i; for (i = 0; i < ARRAY_SIZE(pdefault_rules->rules_create_list); i++) { + union ib_flow_spec ib_spec = {}; int ret; - union ib_flow_spec ib_spec; + switch (pdefault_rules->rules_create_list[i]) { case 0: /* no rule */ diff --git a/drivers/infiniband/hw/mlx5/gsi.c b/drivers/infiniband/hw/mlx5/gsi.c index 79e6309460dc509777324a9875e46573b7d38070..262c18b2f5252dd967fb32b94b6044bb94140c46 100644 --- a/drivers/infiniband/hw/mlx5/gsi.c +++ b/drivers/infiniband/hw/mlx5/gsi.c @@ -507,8 +507,7 @@ int mlx5_ib_gsi_post_send(struct ib_qp *qp, struct ib_send_wr *wr, ret = ib_post_send(tx_qp, &cur_wr.wr, bad_wr); if (ret) { /* Undo the effect of adding the outstanding wr */ - gsi->outstanding_pi = (gsi->outstanding_pi - 1) % - gsi->cap.max_send_wr; + gsi->outstanding_pi--; goto err; } spin_unlock_irqrestore(&gsi->lock, flags); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 84c962820aa2a891d6c3c1655eddc3536f1e398c..d835ef2ce23c09718c59d8d719c42559b5e12fb5 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -4362,7 +4362,9 @@ static void to_rdma_ah_attr(struct mlx5_ib_dev *ibdev, rdma_ah_set_path_bits(ah_attr, path->grh_mlid & 0x7f); rdma_ah_set_static_rate(ah_attr, path->static_rate ? path->static_rate - 5 : 0); - if (path->grh_mlid & (1 << 7)) { + + if (path->grh_mlid & (1 << 7) || + ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) { u32 tc_fl = be32_to_cpu(path->tclass_flowlabel); rdma_ah_set_grh(ah_attr, NULL, @@ -4896,6 +4898,10 @@ struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd, if (udata->outlen && udata->outlen < min_resp_len) return ERR_PTR(-EINVAL); + if (!capable(CAP_SYS_RAWIO) && + init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP) + return ERR_PTR(-EPERM); + dev = to_mdev(pd->device); switch (init_attr->wq_type) { case IB_WQT_RQ: diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 350bc29a066f0596d430d9cc935dcee8cf767937..b473df8eea1ade06e0ac3a734013b8406115f3e2 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -360,8 +360,10 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen) if (mcast == NULL) goto drop; this_cpu_inc(ibp->pmastats->n_multicast_rcv); + rcu_read_lock(); list_for_each_entry_rcu(p, &mcast->qp_list, list) qib_qp_rcv(rcd, hdr, 1, data, tlen, p->qp); + rcu_read_unlock(); /* * Notify rvt_multicast_detach() if it is waiting for us * to finish. diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h index d1cc89f6f2e33e3f844d1138dedfb2b5cb13c5a5..46c8a66731e6ca04f955ae4eae04539e892a4669 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.h @@ -408,7 +408,7 @@ struct rxe_dev { struct list_head pending_mmaps; spinlock_t mmap_offset_lock; /* guard mmap_offset */ - int mmap_offset; + u64 mmap_offset; atomic64_t stats_counters[RXE_NUM_OF_COUNTERS]; diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 9b5691f306a230262103bc25ada8d897838ae14d..ee3f630c92179dac8d4a7351bd43e459d9d72fc2 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -2582,6 +2582,17 @@ isert_wait4logout(struct isert_conn *isert_conn) } } +static void +isert_wait4cmds(struct iscsi_conn *conn) +{ + isert_info("iscsi_conn %p\n", conn); + + if (conn->sess) { + target_sess_cmd_list_set_waiting(conn->sess->se_sess); + target_wait_for_sess_cmds(conn->sess->se_sess); + } +} + /** * isert_put_unsol_pending_cmds() - Drop commands waiting for * unsolicitate dataout @@ -2629,6 +2640,7 @@ static void isert_wait_conn(struct iscsi_conn *conn) ib_drain_qp(isert_conn->qp); isert_put_unsol_pending_cmds(conn); + isert_wait4cmds(conn); isert_wait4logout(isert_conn); queue_work(isert_release_wq, &isert_conn->release_work); diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index d930b6b451b950c351ae0147f11b7b0c5ebf0176..e4025a6bbac810f9768861fdc809e1c1c240b89b 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -541,6 +541,19 @@ static ssize_t debounce_us_store(struct device *dev, } static DEVICE_ATTR_RW(debounce_us); +static struct qpnp_pon_config * +qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) +{ + int i; + + for (i = 0; i < pon->num_pon_config; i++) { + if (pon_type == pon->pon_cfg[i].pon_type) + return &pon->pon_cfg[i]; + } + + return NULL; +} + #define PON_TWM_ENTRY_PBS_BIT BIT(0) static int qpnp_pon_reset_config(struct qpnp_pon *pon, enum pon_power_off_type type) @@ -548,6 +561,7 @@ static int qpnp_pon_reset_config(struct qpnp_pon *pon, int rc; bool disable = false; u16 rst_en_reg; + struct qpnp_pon_config *cfg; /* Ignore the PS_HOLD reset config if TWM ENTRY is enabled */ if (pon->support_twm_config && pon->twm_state == PMIC_TWM_ENABLE) { @@ -558,6 +572,18 @@ static int qpnp_pon_reset_config(struct qpnp_pon *pon, rc); return rc; } + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (cfg) { + /* configure KPDPWR_S2 to Hard reset */ + rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, + QPNP_PON_S2_CNTL_TYPE_MASK, + PON_POWER_OFF_HARD_RESET); + if (rc < 0) + pr_err("Unable to config KPDPWR_N S2 for hard-reset rc=%d\n", + rc); + } + pr_crit("PMIC configured for TWM entry\n"); return 0; } @@ -917,18 +943,6 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) return 0; } -static struct qpnp_pon_config *qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) -{ - int i; - - for (i = 0; i < pon->num_pon_config; i++) { - if (pon_type == pon->pon_cfg[i].pon_type) - return &pon->pon_cfg[i]; - } - - return NULL; -} - static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) { struct qpnp_pon_config *cfg = NULL; diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index dd0f680ddb3e11e2d82b7e08e4dbe118513b50a6..fe2ed14461cbba85d8f34234f5c4fe3d10cacf09 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -250,6 +250,13 @@ static struct hap_addr_val twm_ext_cfg[] = { {REG_HAP_EN_CTL1, 0x80}, /* Enable haptics driver */ }; +static struct hap_addr_val twm_cfg[] = { + {REG_HAP_PLAY, 0x00}, /* Stop playing haptics waveform */ + {REG_HAP_SEL, 0x00}, /* Configure for cmd mode */ + {REG_HAP_EN_CTL1, 0x00}, /* Enable haptics driver */ + {REG_HAP_PERPH_RESET_CTL3, 0x0D}, /* Disable SHUTDOWN1_RB reset */ +}; + static int wf_repeat[8] = {1, 2, 4, 8, 16, 32, 64, 128}; static int wf_s_repeat[4] = {1, 2, 4, 8}; @@ -1060,20 +1067,30 @@ static void qti_haptics_set_gain(struct input_dev *dev, u16 gain) qti_haptics_config_vmax(chip, play->vmax_mv); } -static int qti_haptics_twm_config(struct qti_hap_chip *chip) +static int qti_haptics_twm_config(struct qti_hap_chip *chip, bool ext_pin) { - int rc, i; + int rc = 0, i; - for (i = 0; i < ARRAY_SIZE(twm_ext_cfg); i++) { - rc = qti_haptics_write(chip, twm_ext_cfg[i].addr, - &twm_ext_cfg[i].value, 1); - if (rc < 0) { - dev_err(chip->dev, "Haptics TWM config failed, rc=%d\n", - rc); - return rc; + if (ext_pin) { + for (i = 0; i < ARRAY_SIZE(twm_ext_cfg); i++) { + rc = qti_haptics_write(chip, twm_ext_cfg[i].addr, + &twm_ext_cfg[i].value, 1); + if (rc < 0) + break; + } + } else { + for (i = 0; i < ARRAY_SIZE(twm_cfg); i++) { + rc = qti_haptics_write(chip, twm_cfg[i].addr, + &twm_cfg[i].value, 1); + if (rc < 0) + break; } } - pr_debug("Enabled haptics for TWM mode\n"); + + if (rc < 0) + pr_err("Failed to write twm_config rc=%d\n", rc); + else + pr_debug("Enabled haptics for TWM mode\n"); return 0; } @@ -2032,7 +2049,6 @@ static void qti_haptics_shutdown(struct platform_device *pdev) { struct qti_hap_chip *chip = dev_get_drvdata(&pdev->dev); int rc; - bool enable_haptics_twm; dev_dbg(chip->dev, "Shutdown!\n"); @@ -2048,10 +2064,8 @@ static void qti_haptics_shutdown(struct platform_device *pdev) chip->vdd_enabled = false; } - enable_haptics_twm = chip->haptics_ext_pin_twm && twm_sys_enable; - - if (chip->twm_state == PMIC_TWM_ENABLE && enable_haptics_twm) { - rc = qti_haptics_twm_config(chip); + if (chip->twm_state == PMIC_TWM_ENABLE && twm_sys_enable) { + rc = qti_haptics_twm_config(chip, chip->haptics_ext_pin_twm); if (rc < 0) pr_err("Haptics TWM config failed rc=%d\n", rc); } diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 111a71190547d69a59ee97798240ae060e9b095c..2bca84f4c2b2ea08e9bffa14215598d12745406b 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -149,7 +149,6 @@ static const char * const topbuttonpad_pnp_ids[] = { "LEN0042", /* Yoga */ "LEN0045", "LEN0047", - "LEN0049", "LEN2000", /* S540 */ "LEN2001", /* Edge E431 */ "LEN2002", /* Edge E531 */ @@ -169,9 +168,11 @@ static const char * const smbus_pnp_ids[] = { /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ "LEN0048", /* X1 Carbon 3 */ "LEN0046", /* X250 */ + "LEN0049", /* Yoga 11e */ "LEN004a", /* W541 */ "LEN005b", /* P50 */ "LEN005e", /* T560 */ + "LEN006c", /* T470s */ "LEN0071", /* T480 */ "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */ "LEN0073", /* X1 Carbon G5 (Elantech) */ @@ -182,11 +183,13 @@ static const char * const smbus_pnp_ids[] = { "LEN0097", /* X280 -> ALPS trackpoint */ "LEN009b", /* T580 */ "LEN200f", /* T450s */ + "LEN2044", /* L470 */ "LEN2054", /* E480 */ "LEN2055", /* E580 */ "SYN3052", /* HP EliteBook 840 G4 */ "SYN3221", /* HP 15-ay000 */ "SYN323d", /* HP Spectre X360 13-w013dx */ + "SYN3257", /* HP Envy 13-ad105ng */ NULL }; diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 136f6e7bf797767256e66c1c083cb80c55cd7a1b..0d0f977a2f393dcabc09e01c5178e2f2117354ca 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -534,6 +534,17 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), }, }, + { + /* + * Acer Aspire 5738z + * Touchpad stops working in mux mode when dis- + re-enabled + * with the touchpad enable/disable toggle hotkey + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"), + }, + }, { } }; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 5bf63f76dddac657083bd3ab2ab2b6b0160dd3da..4eff5b44640cf9f57d107548588d432cfcae34d6 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -888,6 +888,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, { const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; + u8 buf[2] = { 0xfc, 0x00 }; struct input_dev *input; unsigned long irq_flags; int error; @@ -957,6 +958,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; } + /* + * Dummy read access. EP0700MLP1 returns bogus data on the first + * register read access and ignores writes. + */ + edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf); + edt_ft5x06_ts_set_regs(tsdata); edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 4f1d3fd5d4121dbd6c517eda7c862ea9ae6b802e..7da44956555e5b80b03379f707045e2956c3be2b 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -441,7 +441,7 @@ static int raydium_i2c_write_object(struct i2c_client *client, return 0; } -static bool raydium_i2c_boot_trigger(struct i2c_client *client) +static int raydium_i2c_boot_trigger(struct i2c_client *client) { static const u8 cmd[7][6] = { { 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 }, @@ -469,7 +469,7 @@ static bool raydium_i2c_boot_trigger(struct i2c_client *client) return 0; } -static bool raydium_i2c_fw_trigger(struct i2c_client *client) +static int raydium_i2c_fw_trigger(struct i2c_client *client) { static const u8 cmd[5][11] = { { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 }, diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 4d2920988d6074c4bdb386bacbd88e3aa306f802..6c228144b3da528564d78aa51cbe77554bb9e36d 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2809,7 +2809,7 @@ static int __init parse_amd_iommu_intr(char *str) { for (; *str; ++str) { if (strncmp(str, "legacy", 6) == 0) { - amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; + amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY_GA; break; } if (strncmp(str, "vapic", 5) == 0) { diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 3054c0971759fb6dede7411c7a93aaa2d9407e43..74c8638aac2b95a035a08604fde95f8eb62261e0 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -348,7 +348,7 @@ #define DTE_GCR3_VAL_A(x) (((x) >> 12) & 0x00007ULL) #define DTE_GCR3_VAL_B(x) (((x) >> 15) & 0x0ffffULL) -#define DTE_GCR3_VAL_C(x) (((x) >> 31) & 0xfffffULL) +#define DTE_GCR3_VAL_C(x) (((x) >> 31) & 0x1fffffULL) #define DTE_GCR3_INDEX_A 0 #define DTE_GCR3_INDEX_B 1 diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index cabacbbae563b52fe4cc8cac9063113498ed4da2..a5711b6cb87ea2f83616a817d3a98cbc88ae3ec4 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1145,7 +1145,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, } arm_smmu_sync_ste_for_sid(smmu, sid); - dst[0] = cpu_to_le64(val); + /* See comment in arm_smmu_write_ctx_desc() */ + WRITE_ONCE(dst[0], cpu_to_le64(val)); arm_smmu_sync_ste_for_sid(smmu, sid); /* It's likely that we'll want to use the new STE soon */ diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index f37b39801f69f667ff6ba0c802bb0eaac4388576..eae4c38d65332598b9a65c827abfd85884748762 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -278,6 +278,7 @@ struct arm_smmu_device { u32 num_context_banks; u32 num_s2_context_banks; DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS); + DECLARE_BITMAP(secure_context_map, ARM_SMMU_MAX_CBS); struct arm_smmu_cb *cbs; atomic_t irptndx; @@ -2392,6 +2393,11 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) arm_smmu_unassign_table(smmu_domain); arm_smmu_secure_domain_unlock(smmu_domain); __arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx); + /* As the nonsecure context bank index is any way set to zero, + * so, directly clearing up the secure cb bitmap. + */ + if (arm_smmu_is_slave_side_secure(smmu_domain)) + __arm_smmu_free_bitmap(smmu->secure_context_map, cfg->cbndx); arm_smmu_power_off(smmu->pwr); arm_smmu_domain_reinit(smmu_domain); @@ -3317,6 +3323,46 @@ static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain, return ret; } +void *get_smmu_from_addr(struct iommu_device *iommu, void __iomem *addr) +{ + struct arm_smmu_device *smmu = NULL; + unsigned long base, mask; + + smmu = arm_smmu_get_by_fwnode(iommu->fwnode); + if (!smmu) + return NULL; + + base = (unsigned long)smmu->base; + mask = ~(smmu->size - 1); + + if ((base & mask) == ((unsigned long)addr & mask)) + return (void *)smmu; + + return NULL; +} + +bool arm_smmu_skip_write(void __iomem *addr) +{ + struct arm_smmu_device *smmu; + int cb; + + smmu = arm_smmu_get_by_addr(addr); + + /* Skip write if smmu not available by now */ + if (!smmu) + return true; + + /* Do not write to global space */ + if (((unsigned long)addr & (smmu->size - 1)) < (smmu->size >> 1)) + return true; + + /* Finally skip writing to secure CB */ + cb = ((unsigned long)addr & ((smmu->size >> 1) - 1)) >> PAGE_SHIFT; + if (test_bit(cb, smmu->secure_context_map)) + return true; + + return false; +} #endif static int arm_smmu_add_device(struct device *dev) @@ -4409,9 +4455,13 @@ static int arm_smmu_alloc_cb(struct iommu_domain *domain, cb = smmu->s2crs[idx].cbndx; } - if (cb >= 0 && arm_smmu_is_static_cb(smmu)) + if (cb >= 0 && arm_smmu_is_static_cb(smmu)) { smmu_domain->slave_side_secure = true; + if (arm_smmu_is_slave_side_secure(smmu_domain)) + bitmap_set(smmu->secure_context_map, cb, 1); + } + if (cb < 0 && !arm_smmu_is_static_cb(smmu)) { mutex_unlock(&smmu->stream_map_mutex); return __arm_smmu_alloc_bitmap(smmu->context_map, @@ -5216,7 +5266,8 @@ static int arm_smmu_device_remove(struct platform_device *pdev) if (arm_smmu_power_on(smmu->pwr)) return -EINVAL; - if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS)) + if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS) || + !bitmap_empty(smmu->secure_context_map, ARM_SMMU_MAX_CBS)) dev_err(&pdev->dev, "removing device with active domains!\n"); idr_destroy(&smmu->asid_idr); diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 3d81e2c8a97e04078797dd9ce2aa121e556252de..b6a62a727b41ae781b99170fb7a48d68eeab96fb 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -212,15 +212,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie, start -= iova_offset(iovad, start); num_pages = iova_align(iovad, end - start) >> iova_shift(iovad); - msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL); - if (!msi_page) - return -ENOMEM; - for (i = 0; i < num_pages; i++) { - msi_page[i].phys = start; - msi_page[i].iova = start; - INIT_LIST_HEAD(&msi_page[i].list); - list_add(&msi_page[i].list, &cookie->msi_page_list); + msi_page = kmalloc(sizeof(*msi_page), GFP_KERNEL); + if (!msi_page) + return -ENOMEM; + + msi_page->phys = start; + msi_page->iova = start; + INIT_LIST_HEAD(&msi_page->list); + list_add(&msi_page->list, &cookie->msi_page_list); start += iovad->granule; } diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 38d0128b8135d2f5a727ae93a375d1094367d195..1f527ca609550bc0e175afdc0fe68bf44b8fd78e 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,13 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) BUG_ON(dev->is_virtfn); + /* + * Ignore devices that have a domain number higher than what can + * be looked up in DMAR, e.g. VMD subdevices with domain 0x10000 + */ + if (pci_domain_nr(dev->bus) > U16_MAX) + return NULL; + /* Only generate path[] for device addition event */ if (event == BUS_NOTIFY_ADD_DEVICE) for (tmp = dev; tmp; tmp = tmp->bus->self) @@ -451,12 +459,13 @@ static int __init dmar_parse_one_andd(struct acpi_dmar_header *header, /* Check for NUL termination within the designated length */ if (strnlen(andd->device_name, header->length - 8) == header->length - 8) { - WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND, + pr_warn(FW_BUG "Your BIOS is broken; ANDD object name is not NUL-terminated\n" "BIOS vendor: %s; Ver: %s; Product Version: %s\n", dmi_get_system_info(DMI_BIOS_VENDOR), dmi_get_system_info(DMI_BIOS_VERSION), dmi_get_system_info(DMI_PRODUCT_VERSION)); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); return -EINVAL; } pr_info("ANDD device: %x name: %s\n", andd->device_number, @@ -482,14 +491,14 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg) return 0; } } - WARN_TAINT( - 1, TAINT_FIRMWARE_WORKAROUND, + pr_warn(FW_BUG "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n" "BIOS vendor: %s; Ver: %s; Product Version: %s\n", - drhd->reg_base_addr, + rhsa->base_address, dmi_get_system_info(DMI_BIOS_VENDOR), dmi_get_system_info(DMI_BIOS_VERSION), dmi_get_system_info(DMI_PRODUCT_VERSION)); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); return 0; } @@ -835,14 +844,14 @@ int __init dmar_table_init(void) static void warn_invalid_dmar(u64 addr, const char *message) { - WARN_TAINT_ONCE( - 1, TAINT_FIRMWARE_WORKAROUND, + pr_warn_once(FW_BUG "Your BIOS is broken; DMAR reported at address %llx%s!\n" "BIOS vendor: %s; Ver: %s; Product Version: %s\n", addr, message, dmi_get_system_info(DMI_BIOS_VENDOR), dmi_get_system_info(DMI_BIOS_VERSION), dmi_get_system_info(DMI_PRODUCT_VERSION)); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); } static int __ref diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index b48666849dbedaff02bbf812647a865cbd0c0ac0..db1b546134f5944ceffa7445740f4677f9e3e424 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3984,10 +3984,11 @@ static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev) /* we know that the this iommu should be at offset 0xa000 from vtbar */ drhd = dmar_find_matched_drhd_unit(pdev); - if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000, - TAINT_FIRMWARE_WORKAROUND, - "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n")) + if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) { + pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; + } } DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu); @@ -5123,8 +5124,10 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, u64 phys = 0; pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level); - if (pte) - phys = dma_pte_addr(pte); + if (pte && dma_pte_present(pte)) + phys = dma_pte_addr(pte) + + (iova & (BIT_MASK(level_to_offset_bits(level) + + VTD_PAGE_SHIFT) - 1)); return phys; } diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index f5573bb9f450e2a19ec22fde1b001fff3c8d8a02..837459762eb39b9ddfd3263c95690d030ca4ba76 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -613,14 +613,15 @@ static irqreturn_t prq_event_thread(int irq, void *d) * any faults on kernel addresses. */ if (!svm->mm) goto bad_req; - /* If the mm is already defunct, don't handle faults. */ - if (!mmget_not_zero(svm->mm)) - goto bad_req; /* If address is not canonical, return invalid response */ if (!is_canonical_address(address)) goto bad_req; + /* If the mm is already defunct, don't handle faults. */ + if (!mmget_not_zero(svm->mm)) + goto bad_req; + down_read(&svm->mm->mmap_sem); vma = find_extend_vma(svm->mm, address); if (!vma || address < vma->vm_start) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index ddd71248902235b2dac945cb68fd6e36273762e8..309579a375fb9ac8569011f1210ec41ad12ce7ff 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -34,6 +34,9 @@ #include #include #include +#ifdef CONFIG_MSM_TZ_SMMU +#include +#endif #include "iommu-debug.h" @@ -107,6 +110,26 @@ void iommu_device_unregister(struct iommu_device *iommu) spin_unlock(&iommu_device_lock); } +#ifdef CONFIG_MSM_TZ_SMMU +void *arm_smmu_get_by_addr(void __iomem *addr) +{ + struct iommu_device *iommu; + unsigned long flags; + void *smmu = NULL; + + spin_lock_irqsave(&iommu_device_lock, flags); + list_for_each_entry(iommu, &iommu_device_list, list) { + smmu = get_smmu_from_addr(iommu, addr); + if (!smmu) + continue; + break; + } + spin_unlock_irqrestore(&iommu_device_lock, flags); + + return smmu; +} +#endif + static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, unsigned type); static int __iommu_attach_device(struct iommu_domain *domain, diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index c8a587d034b0d7e75d276af1b8c7cdc9e02e5aad..920a5df319bc4c650a319b3e3e51bf86834103be 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -327,21 +327,19 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain) { struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); - if (WARN_ON(qcom_domain->iommu)) /* forgot to detach? */ - return; - iommu_put_dma_cookie(domain); - /* NOTE: unmap can be called after client device is powered off, - * for example, with GPUs or anything involving dma-buf. So we - * cannot rely on the device_link. Make sure the IOMMU is on to - * avoid unclocked accesses in the TLB inv path: - */ - pm_runtime_get_sync(qcom_domain->iommu->dev); - - free_io_pgtable_ops(qcom_domain->pgtbl_ops); - - pm_runtime_put_sync(qcom_domain->iommu->dev); + if (qcom_domain->iommu) { + /* + * NOTE: unmap can be called after client device is powered + * off, for example, with GPUs or anything involving dma-buf. + * So we cannot rely on the device_link. Make sure the IOMMU + * is on to avoid unclocked accesses in the TLB inv path: + */ + pm_runtime_get_sync(qcom_domain->iommu->dev); + free_io_pgtable_ops(qcom_domain->pgtbl_ops); + pm_runtime_put_sync(qcom_domain->iommu->dev); + } kfree(qcom_domain); } @@ -386,7 +384,7 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); unsigned i; - if (!qcom_domain->iommu) + if (WARN_ON(!qcom_domain->iommu)) return; pm_runtime_get_sync(qcom_iommu->dev); @@ -397,8 +395,6 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); } pm_runtime_put_sync(qcom_iommu->dev); - - qcom_domain->iommu = NULL; } static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, @@ -779,8 +775,11 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) qcom_iommu->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) + if (res) { qcom_iommu->local_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qcom_iommu->local_base)) + return PTR_ERR(qcom_iommu->local_base); + } qcom_iommu->iface_clk = devm_clk_get(dev, "iface"); if (IS_ERR(qcom_iommu->iface_clk)) { diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 52238e6bed392dd068cd4a1b2118af984f13196a..84b23d902d5b86875cd5be3d9fc858a5d4329665 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -527,7 +527,7 @@ static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd, struct its_cmd_desc *desc) { its_encode_cmd(cmd, GITS_CMD_INVALL); - its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id); + its_encode_collection(cmd, desc->its_invall_cmd.col->col_id); its_fixup_cmd(cmd); @@ -2591,12 +2591,18 @@ static int its_vpe_set_irqchip_state(struct irq_data *d, return 0; } +static int its_vpe_retrigger(struct irq_data *d) +{ + return !its_vpe_set_irqchip_state(d, IRQCHIP_STATE_PENDING, true); +} + static struct irq_chip its_vpe_irq_chip = { .name = "GICv4-vpe", .irq_mask = its_vpe_mask_irq, .irq_unmask = its_vpe_unmask_irq, .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = its_vpe_set_affinity, + .irq_retrigger = its_vpe_retrigger, .irq_set_irqchip_state = its_vpe_set_irqchip_state, .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, }; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index b99af4dcdabdb906cb817c94f0dc2982cda7d645..f3c81a86e05619b872fce879f773c62e0c638717 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -570,6 +571,8 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs err = handle_domain_irq(gic_data.domain, irqnr, regs); if (err) { WARN_ONCE(true, "Unexpected interrupt received!\n"); + log_abnormal_wakeup_reason( + "unexpected HW IRQ %u", irqnr); if (static_key_true(&supports_deactivate)) { if (irqnr < 8192) gic_write_dir(irqnr); @@ -1453,6 +1456,7 @@ static struct struct redist_region *redist_regs; u32 nr_redist_regions; bool single_redist; + int enabled_rdists; u32 maint_irq; int maint_irq_mode; phys_addr_t vcpu_base; @@ -1547,8 +1551,10 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header, * If GICC is enabled and has valid gicr base address, then it means * GICR base is presented via GICC */ - if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) + if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) { + acpi_data.enabled_rdists++; return 0; + } /* * It's perfectly valid firmware can pass disabled GICC entry, driver @@ -1578,8 +1584,10 @@ static int __init gic_acpi_count_gicr_regions(void) count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, gic_acpi_match_gicc, 0); - if (count > 0) + if (count > 0) { acpi_data.single_redist = true; + count = acpi_data.enabled_rdists; + } return count; } diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c index 98b6e1d4b1a68cf8a247f4c75a67d09fd11b6b08..c98358be0bc8b6a4ef0fef7ab84ac531f7fc8ec4 100644 --- a/drivers/irqchip/irq-mbigen.c +++ b/drivers/irqchip/irq-mbigen.c @@ -231,10 +231,16 @@ static int mbigen_irq_domain_alloc(struct irq_domain *domain, return 0; } +static void mbigen_irq_domain_free(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + platform_msi_domain_free(domain, virq, nr_irqs); +} + static const struct irq_domain_ops mbigen_domain_ops = { .translate = mbigen_domain_translate, .alloc = mbigen_irq_domain_alloc, - .free = irq_domain_free_irqs_common, + .free = mbigen_irq_domain_free, }; static int mbigen_of_create_domain(struct platform_device *pdev, @@ -381,6 +387,7 @@ static struct platform_driver mbigen_platform_driver = { .name = "Hisilicon MBIGEN-V2", .of_match_table = mbigen_of_match, .acpi_match_table = ACPI_PTR(mbigen_acpi_match), + .suppress_bind_attrs = true, }, .probe = mbigen_device_probe, }; diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 928858dada756255cbb4c27c2ae0c191373e6513..f1386733d3bc1ded71f0c7d6ef1bf6692b1cdba1 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -68,12 +69,16 @@ static void fpga_irq_unmask(struct irq_data *d) static void fpga_irq_handle(struct irq_desc *desc) { + struct irq_chip *chip = irq_desc_get_chip(desc); struct fpga_irq_data *f = irq_desc_get_handler_data(desc); - u32 status = readl(f->base + IRQ_STATUS); + u32 status; + + chained_irq_enter(chip, desc); + status = readl(f->base + IRQ_STATUS); if (status == 0) { do_bad_IRQ(desc); - return; + goto out; } do { @@ -82,6 +87,9 @@ static void fpga_irq_handle(struct irq_desc *desc) status &= ~(1 << irq); generic_handle_irq(irq_find_mapping(f->domain, irq)); } while (status); + +out: + chained_irq_exit(chip, desc); } /* @@ -204,6 +212,9 @@ int __init fpga_irq_of_init(struct device_node *node, if (of_property_read_u32(node, "valid-mask", &valid_mask)) valid_mask = 0; + writel(clear_mask, base + IRQ_ENABLE_CLEAR); + writel(clear_mask, base + FIQ_ENABLE_CLEAR); + /* Some chips are cascaded from a parent IRQ */ parent_irq = irq_of_parse_and_map(node, 0); if (!parent_irq) { @@ -213,9 +224,6 @@ int __init fpga_irq_of_init(struct device_node *node, fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node); - writel(clear_mask, base + IRQ_ENABLE_CLEAR); - writel(clear_mask, base + FIQ_ENABLE_CLEAR); - /* * On Versatile AB/PB, some secondary interrupts have a direct * pass-thru to the primary controller for IRQs 20 and 22-31 which need diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index 3bf9a127181927d84f374c1b60cc9373dafad149..88c7313cf869383d9bad69fcdd0a940158aacf71 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -43,6 +43,8 @@ #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */ #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */ +#define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */ +#define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */ #define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */ #define PCA963X_MODE1 0x00 @@ -462,12 +464,12 @@ static int pca963x_probe(struct i2c_client *client, PCA963X_MODE2); /* Configure output: open-drain or totem pole (push-pull) */ if (pdata->outdrv == PCA963X_OPEN_DRAIN) - mode2 |= 0x01; + mode2 &= ~PCA963X_MODE2_OUTDRV; else - mode2 |= 0x05; + mode2 |= PCA963X_MODE2_OUTDRV; /* Configure direction: normal or inverted */ if (pdata->dir == PCA963X_INVERTED) - mode2 |= 0x10; + mode2 |= PCA963X_MODE2_INVRT; i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, mode2); } diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index c805d628d04dfa9e24d1a8f26ac2c66824c6565d..f3d7db1cc8289dac00c7196554d11f0071fba191 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -287,22 +287,25 @@ config DM_CRYPT If unsure, say N. config DM_DEFAULT_KEY - tristate "Default-key crypt target support" + tristate "Default-key target support" depends on BLK_DEV_DM - depends on PFK - ---help--- - This (currently Android-specific) device-mapper target allows you to - create a device that assigns a default encryption key to bios that - don't already have one. This can sit between inline cryptographic - acceleration hardware and filesystems that use it. This ensures that - where the filesystem doesn't explicitly specify a key, such as for - filesystem metadata, a default key will be used instead, leaving no - sectors unencrypted. + depends on BLK_INLINE_ENCRYPTION + # dm-default-key doesn't require -o inlinecrypt, but it does currently + # rely on the inline encryption hooks being built into the kernel. + depends on FS_ENCRYPTION_INLINE_CRYPT + help + This device-mapper target allows you to create a device that + assigns a default encryption key to bios that aren't for the + contents of an encrypted file. - To compile this code as a module, choose M here: the module will be - called dm-default-key. + This ensures that all blocks on-disk will be encrypted with + some key, without the performance hit of file contents being + encrypted twice when fscrypt (File-Based Encryption) is used. - If unsure, say N. + It is only appropriate to use dm-default-key when key + configuration is tightly controlled, like it is in Android, + such that all fscrypt keys are at least as hard to compromise + as the default key. config DM_SNAPSHOT tristate "Snapshot target" diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h index 8d1964b472e7e830d4ee35acaaf7cec8033907d6..0bfde500af196078b048f23b9f441edc63026ad8 100644 --- a/drivers/md/bcache/bset.h +++ b/drivers/md/bcache/bset.h @@ -381,7 +381,8 @@ void bch_btree_keys_stats(struct btree_keys *, struct bset_stats *); /* Bkey utility code */ -#define bset_bkey_last(i) bkey_idx((struct bkey *) (i)->d, (i)->keys) +#define bset_bkey_last(i) bkey_idx((struct bkey *) (i)->d, \ + (unsigned int)(i)->keys) static inline struct bkey *bset_bkey_idx(struct bset *i, unsigned idx) { diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h index c82578af56a5bbff035a272f258327a7fce6ecfd..2ea0360108e1d41b57a39b5c5df715c52a641442 100644 --- a/drivers/md/dm-bio-record.h +++ b/drivers/md/dm-bio-record.h @@ -20,8 +20,13 @@ struct dm_bio_details { struct gendisk *bi_disk; u8 bi_partno; + int __bi_remaining; unsigned long bi_flags; struct bvec_iter bi_iter; + bio_end_io_t *bi_end_io; +#if defined(CONFIG_BLK_DEV_INTEGRITY) + struct bio_integrity_payload *bi_integrity; +#endif }; static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) @@ -30,6 +35,11 @@ static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) bd->bi_partno = bio->bi_partno; bd->bi_flags = bio->bi_flags; bd->bi_iter = bio->bi_iter; + bd->__bi_remaining = atomic_read(&bio->__bi_remaining); + bd->bi_end_io = bio->bi_end_io; +#if defined(CONFIG_BLK_DEV_INTEGRITY) + bd->bi_integrity = bio_integrity(bio); +#endif } static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) @@ -38,6 +48,11 @@ static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) bio->bi_partno = bd->bi_partno; bio->bi_flags = bd->bi_flags; bio->bi_iter = bd->bi_iter; + atomic_set(&bio->__bi_remaining, bd->__bi_remaining); + bio->bi_end_io = bd->bi_end_io; +#if defined(CONFIG_BLK_DEV_INTEGRITY) + bio->bi_integrity = bd->bi_integrity; +#endif } #endif diff --git a/drivers/md/dm-bow.c b/drivers/md/dm-bow.c index b92da30a3d42b0cb68b7c873a2b680c5af8f9888..96ddba82ed24e4adb1eebf6b5f10eb3e47600776 100644 --- a/drivers/md/dm-bow.c +++ b/drivers/md/dm-bow.c @@ -622,6 +622,72 @@ static void dm_bow_dtr(struct dm_target *ti) kfree(bc); } +static void dm_bow_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + struct bow_context *bc = ti->private; + const unsigned int block_size = bc->block_size; + + limits->logical_block_size = + max_t(unsigned short, limits->logical_block_size, block_size); + limits->physical_block_size = + max_t(unsigned int, limits->physical_block_size, block_size); + limits->io_min = max_t(unsigned int, limits->io_min, block_size); + + if (limits->max_discard_sectors == 0) { + limits->discard_granularity = 1 << 12; + limits->max_hw_discard_sectors = 1 << 15; + limits->max_discard_sectors = 1 << 15; + bc->forward_trims = false; + } else { + limits->discard_granularity = 1 << 12; + bc->forward_trims = true; + } +} + +static int dm_bow_ctr_optional(struct dm_target *ti, unsigned int argc, + char **argv) +{ + struct bow_context *bc = ti->private; + struct dm_arg_set as; + static const struct dm_arg _args[] = { + {0, 1, "Invalid number of feature args"}, + }; + unsigned int opt_params; + const char *opt_string; + int err; + char dummy; + + as.argc = argc; + as.argv = argv; + + err = dm_read_arg_group(_args, &as, &opt_params, &ti->error); + if (err) + return err; + + while (opt_params--) { + opt_string = dm_shift_arg(&as); + if (!opt_string) { + ti->error = "Not enough feature arguments"; + return -EINVAL; + } + + if (sscanf(opt_string, "block_size:%u%c", + &bc->block_size, &dummy) == 1) { + if (bc->block_size < SECTOR_SIZE || + bc->block_size > 4096 || + !is_power_of_2(bc->block_size)) { + ti->error = "Invalid block_size"; + return -EINVAL; + } + } else { + ti->error = "Invalid feature arguments"; + return -EINVAL; + } + } + + return 0; +} + static int dm_bow_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct bow_context *bc; @@ -629,7 +695,7 @@ static int dm_bow_ctr(struct dm_target *ti, unsigned int argc, char **argv) int ret; struct mapped_device *md = dm_table_get_md(ti->table); - if (argc != 1) { + if (argc < 1) { ti->error = "Invalid argument count"; return -EINVAL; } @@ -652,16 +718,13 @@ static int dm_bow_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad; } - if (bc->dev->bdev->bd_queue->limits.max_discard_sectors == 0) { - bc->dev->bdev->bd_queue->limits.discard_granularity = 1 << 12; - bc->dev->bdev->bd_queue->limits.max_hw_discard_sectors = 1 << 15; - bc->dev->bdev->bd_queue->limits.max_discard_sectors = 1 << 15; - bc->forward_trims = false; - } else { - bc->forward_trims = true; + bc->block_size = bc->dev->bdev->bd_queue->limits.logical_block_size; + if (argc > 1) { + ret = dm_bow_ctr_optional(ti, argc - 1, &argv[1]); + if (ret) + goto bad; } - bc->block_size = bc->dev->bdev->bd_queue->limits.logical_block_size; bc->block_shift = ilog2(bc->block_size); bc->log_sector = kzalloc(bc->block_size, GFP_KERNEL); if (!bc->log_sector) { @@ -726,6 +789,7 @@ static int dm_bow_ctr(struct dm_target *ti, unsigned int argc, char **argv) rb_insert_color(&br->node, &bc->ranges); ti->discards_supported = true; + ti->may_passthrough_inline_crypto = true; return 0; @@ -792,6 +856,7 @@ static int prepare_unchanged_range(struct bow_context *bc, struct bow_range *br, */ original_type = br->type; sector0 = backup_br->sector; + bc->trims_total -= range_size(backup_br); if (backup_br->type == TRIMMED) list_del(&backup_br->trimmed_list); backup_br->type = br->type == SECTOR0_CURRENT ? SECTOR0_CURRENT @@ -1203,7 +1268,7 @@ static int dm_bow_iterate_devices(struct dm_target *ti, static struct target_type bow_target = { .name = "bow", - .version = {1, 1, 1}, + .version = {1, 2, 0}, .module = THIS_MODULE, .ctr = dm_bow_ctr, .dtr = dm_bow_dtr, @@ -1211,6 +1276,7 @@ static struct target_type bow_target = { .status = dm_bow_status, .prepare_ioctl = dm_bow_prepare_ioctl, .iterate_devices = dm_bow_iterate_devices, + .io_hints = dm_bow_io_hints, }; int __init dm_bow_init(void) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index b5f541112fca0b2307bca1648c3d1db02afe88eb..69cdb29ef6be96b49bd096c3c9e58a4a2e22c763 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -2971,8 +2971,8 @@ static void cache_postsuspend(struct dm_target *ti) prevent_background_work(cache); BUG_ON(atomic_read(&cache->nr_io_migrations)); - cancel_delayed_work(&cache->waker); - flush_workqueue(cache->wq); + cancel_delayed_work_sync(&cache->waker); + drain_workqueue(cache->wq); WARN_ON(cache->tracker.in_flight); /* diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 3985210d8ab18fa37f8277ddd7689c06c1e0a9e6..cb959a0e711d92979cfedacc619c396690ed9502 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -126,7 +126,7 @@ struct iv_tcw_private { */ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID, DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD, - DM_CRYPT_ENCRYPT_OVERRIDE }; +}; enum cipher_flags { CRYPT_MODE_INTEGRITY_AEAD, /* Use authenticated mode for cihper */ @@ -486,8 +486,14 @@ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti, const char *opts) { - unsigned bs = crypto_skcipher_blocksize(any_tfm(cc)); - int log = ilog2(bs); + unsigned bs; + int log; + + if (test_bit(CRYPT_MODE_INTEGRITY_AEAD, &cc->cipher_flags)) + bs = crypto_aead_blocksize(any_tfm_aead(cc)); + else + bs = crypto_skcipher_blocksize(any_tfm(cc)); + log = ilog2(bs); /* we need to calculate how far we must shift the sector count * to get the cipher block count, we use this shift in _gen */ @@ -2672,8 +2678,6 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar cc->sector_shift = __ffs(cc->sector_size) - SECTOR_SHIFT; } else if (!strcasecmp(opt_string, "iv_large_sectors")) set_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags); - else if (!strcasecmp(opt_string, "allow_encrypt_override")) - set_bit(DM_CRYPT_ENCRYPT_OVERRIDE, &cc->flags); else { ti->error = "Invalid feature arguments"; return -EINVAL; @@ -2883,15 +2887,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) struct crypt_config *cc = ti->private; /* - * If bio is REQ_PREFLUSH, REQ_NOENCRYPT, or REQ_OP_DISCARD, - * just bypass crypt queues. + * If bio is REQ_PREFLUSH or REQ_OP_DISCARD, just bypass crypt queues. * - for REQ_PREFLUSH device-mapper core ensures that no IO is in-flight * - for REQ_OP_DISCARD caller must use flush if IO ordering matters */ - if (unlikely(bio->bi_opf & REQ_PREFLUSH) || - (unlikely(bio->bi_opf & REQ_NOENCRYPT) && - test_bit(DM_CRYPT_ENCRYPT_OVERRIDE, &cc->flags)) || - bio_op(bio) == REQ_OP_DISCARD) { + if (unlikely(bio->bi_opf & REQ_PREFLUSH || + bio_op(bio) == REQ_OP_DISCARD)) { bio_set_dev(bio, cc->dev->bdev); if (bio_sectors(bio)) bio->bi_iter.bi_sector = cc->start + @@ -2978,8 +2979,6 @@ static void crypt_status(struct dm_target *ti, status_type_t type, num_feature_args += test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags); num_feature_args += cc->sector_size != (1 << SECTOR_SHIFT); num_feature_args += test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags); - num_feature_args += test_bit(DM_CRYPT_ENCRYPT_OVERRIDE, - &cc->flags); if (cc->on_disk_tag_size) num_feature_args++; if (num_feature_args) { @@ -2996,8 +2995,6 @@ static void crypt_status(struct dm_target *ti, status_type_t type, DMEMIT(" sector_size:%d", cc->sector_size); if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags)) DMEMIT(" iv_large_sectors"); - if (test_bit(DM_CRYPT_ENCRYPT_OVERRIDE, &cc->flags)) - DMEMIT(" allow_encrypt_override"); } break; diff --git a/drivers/md/dm-default-key.c b/drivers/md/dm-default-key.c index 0926bd65bd59cda769926f0e6e2799034a0a06f2..dba7543a1bd5bd77a5d4b8c2e3022f08748eca3d 100644 --- a/drivers/md/dm-default-key.c +++ b/drivers/md/dm-default-key.c @@ -1,37 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ +#include #include #include -#include -#define DM_MSG_PREFIX "default-key" -#define DEFAULT_DUN_OFFSET 1 +#define DM_MSG_PREFIX "default-key" + +#define DM_DEFAULT_KEY_MAX_WRAPPED_KEY_SIZE 128 + +#define SECTOR_SIZE (1 << SECTOR_SHIFT) + +static const struct dm_default_key_cipher { + const char *name; + enum blk_crypto_mode_num mode_num; + int key_size; +} dm_default_key_ciphers[] = { + { + .name = "aes-xts-plain64", + .mode_num = BLK_ENCRYPTION_MODE_AES_256_XTS, + .key_size = 64, + }, { + .name = "xchacha12,aes-adiantum-plain64", + .mode_num = BLK_ENCRYPTION_MODE_ADIANTUM, + .key_size = 32, + }, +}; +/** + * struct dm_default_c - private data of a default-key target + * @dev: the underlying device + * @start: starting sector of the range of @dev which this target actually maps. + * For this purpose a "sector" is 512 bytes. + * @cipher_string: the name of the encryption algorithm being used + * @iv_offset: starting offset for IVs. IVs are generated as if the target were + * preceded by @iv_offset 512-byte sectors. + * @sector_size: crypto sector size in bytes (usually 4096) + * @sector_bits: log2(sector_size) + * @key: the encryption key to use + * @max_dun: the maximum DUN that may be used (computed from other params) + */ struct default_key_c { struct dm_dev *dev; sector_t start; - struct blk_encryption_key key; - bool set_dun; - u64 dun_offset; + const char *cipher_string; + u64 iv_offset; + unsigned int sector_size; + unsigned int sector_bits; + struct blk_crypto_key key; + bool is_hw_wrapped; + u64 max_dun; }; +static const struct dm_default_key_cipher * +lookup_cipher(const char *cipher_string) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dm_default_key_ciphers); i++) { + if (strcmp(cipher_string, dm_default_key_ciphers[i].name) == 0) + return &dm_default_key_ciphers[i]; + } + return NULL; +} + static void default_key_dtr(struct dm_target *ti) { struct default_key_c *dkc = ti->private; + int err; - if (dkc->dev) + if (dkc->dev) { + err = blk_crypto_evict_key(dkc->dev->bdev->bd_queue, &dkc->key); + if (err && err != -ENOKEY) + DMWARN("Failed to evict crypto key: %d", err); dm_put_device(ti, dkc->dev); + } + kzfree(dkc->cipher_string); kzfree(dkc); } @@ -39,21 +85,22 @@ static int default_key_ctr_optional(struct dm_target *ti, unsigned int argc, char **argv) { struct default_key_c *dkc = ti->private; - struct dm_arg_set as = {0}; + struct dm_arg_set as; static const struct dm_arg _args[] = { - {0, 2, "Invalid number of feature args"}, + {0, 4, "Invalid number of feature args"}, }; unsigned int opt_params; const char *opt_string; + bool iv_large_sectors = false; char dummy; - int ret; + int err; as.argc = argc; as.argv = argv; - ret = dm_read_arg_group(_args, &as, &opt_params, &ti->error); - if (ret) - return ret; + err = dm_read_arg_group(_args, &as, &opt_params, &ti->error); + if (err) + return err; while (opt_params--) { opt_string = dm_shift_arg(&as); @@ -61,45 +108,105 @@ static int default_key_ctr_optional(struct dm_target *ti, ti->error = "Not enough feature arguments"; return -EINVAL; } - - if (!strcasecmp(opt_string, "set_dun")) { - dkc->set_dun = true; - } else if (sscanf(opt_string, "dun_offset:%llu%c", - &dkc->dun_offset, &dummy) == 1) { - if (dkc->dun_offset == 0) { - ti->error = "dun_offset cannot be 0"; + if (!strcmp(opt_string, "allow_discards")) { + ti->num_discard_bios = 1; + } else if (sscanf(opt_string, "sector_size:%u%c", + &dkc->sector_size, &dummy) == 1) { + if (dkc->sector_size < SECTOR_SIZE || + dkc->sector_size > 4096 || + !is_power_of_2(dkc->sector_size)) { + ti->error = "Invalid sector_size"; return -EINVAL; } + } else if (!strcmp(opt_string, "iv_large_sectors")) { + iv_large_sectors = true; + } else if (!strcmp(opt_string, "wrappedkey_v0")) { + dkc->is_hw_wrapped = true; } else { ti->error = "Invalid feature arguments"; return -EINVAL; } } - if (dkc->dun_offset && !dkc->set_dun) { - ti->error = "Invalid: dun_offset without set_dun"; + /* dm-default-key doesn't implement iv_large_sectors=false. */ + if (dkc->sector_size != SECTOR_SIZE && !iv_large_sectors) { + ti->error = "iv_large_sectors must be specified"; return -EINVAL; } - if (dkc->set_dun && !dkc->dun_offset) - dkc->dun_offset = DEFAULT_DUN_OFFSET; - return 0; } +static void default_key_adjust_sector_size_and_iv(char **argv, + struct dm_target *ti, + struct default_key_c **dkc, + u8 *raw, u32 size, + bool is_legacy) +{ + struct dm_dev *dev; + int i; + union { + u8 bytes[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE]; + u32 words[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE / sizeof(u32)]; + } key_new; + + dev = (*dkc)->dev; + + if (is_legacy) { + memcpy(key_new.bytes, raw, size); + + for (i = 0; i < ARRAY_SIZE(key_new.words); i++) + __cpu_to_be32s(&key_new.words[i]); + + memcpy(raw, key_new.bytes, size); + + if (ti->len & (((*dkc)->sector_size >> SECTOR_SHIFT) - 1)) + (*dkc)->sector_size = SECTOR_SIZE; + + if (dev->bdev->bd_part) + (*dkc)->iv_offset += dev->bdev->bd_part->start_sect; + } +} + /* - * Construct a default-key mapping: + * Construct a default-key mapping: + * + * + * This syntax matches dm-crypt's, but lots of unneeded functionality has been + * removed. Also, dm-default-key requires that the "iv_large_sectors" option be + * given whenever a non-default sector size is used. */ static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct default_key_c *dkc; - size_t key_size; - unsigned long long tmp; + const struct dm_default_key_cipher *cipher; + u8 raw_key[DM_DEFAULT_KEY_MAX_WRAPPED_KEY_SIZE]; + unsigned int raw_key_size; + unsigned int dun_bytes; + unsigned long long tmpll; char dummy; int err; + char *_argv[10]; + bool is_legacy = false; + + if (argc >= 4 && !strcmp(argv[0], "AES-256-XTS")) { + argc = 0; + _argv[argc++] = "aes-xts-plain64"; + _argv[argc++] = argv[1]; + _argv[argc++] = "0"; + _argv[argc++] = argv[2]; + _argv[argc++] = argv[3]; + _argv[argc++] = "3"; + _argv[argc++] = "allow_discards"; + _argv[argc++] = "sector_size:4096"; + _argv[argc++] = "iv_large_sectors"; + _argv[argc] = NULL; + argv = _argv; + is_legacy = true; + } - if (argc < 4) { - ti->error = "Too few arguments"; + if (argc < 5) { + ti->error = "Not enough arguments"; return -EINVAL; } @@ -110,98 +217,159 @@ static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ti->private = dkc; - if (strcmp(argv[0], "AES-256-XTS") != 0) { - ti->error = "Unsupported encryption mode"; + /* */ + dkc->cipher_string = kstrdup(argv[0], GFP_KERNEL); + if (!dkc->cipher_string) { + ti->error = "Out of memory"; + err = -ENOMEM; + goto bad; + } + cipher = lookup_cipher(dkc->cipher_string); + if (!cipher) { + ti->error = "Unsupported cipher"; err = -EINVAL; goto bad; } - key_size = strlen(argv[1]); - if (key_size != 2 * BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS) { - ti->error = "Unsupported key size"; + /* */ + raw_key_size = strlen(argv[1]); + if (raw_key_size > 2 * DM_DEFAULT_KEY_MAX_WRAPPED_KEY_SIZE || + raw_key_size % 2) { + ti->error = "Invalid keysize"; err = -EINVAL; goto bad; } - key_size /= 2; - - if (hex2bin(dkc->key.raw, argv[1], key_size) != 0) { + raw_key_size /= 2; + if (hex2bin(raw_key, argv[1], raw_key_size) != 0) { ti->error = "Malformed key string"; err = -EINVAL; goto bad; } - err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table), + /* */ + if (sscanf(argv[2], "%llu%c", &dkc->iv_offset, &dummy) != 1) { + ti->error = "Invalid iv_offset sector"; + err = -EINVAL; + goto bad; + } + + /* */ + err = dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &dkc->dev); if (err) { ti->error = "Device lookup failed"; goto bad; } - if (sscanf(argv[3], "%llu%c", &tmp, &dummy) != 1) { + /* */ + if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1 || + tmpll != (sector_t)tmpll) { ti->error = "Invalid start sector"; err = -EINVAL; goto bad; } - dkc->start = tmp; + dkc->start = tmpll; - if (argc > 4) { - err = default_key_ctr_optional(ti, argc - 4, &argv[4]); + /* optional arguments */ + dkc->sector_size = SECTOR_SIZE; + if (argc > 5) { + err = default_key_ctr_optional(ti, argc - 5, &argv[5]); if (err) goto bad; } - if (!blk_queue_inlinecrypt(bdev_get_queue(dkc->dev->bdev))) { - ti->error = "Device does not support inline encryption"; + default_key_adjust_sector_size_and_iv(argv, ti, &dkc, raw_key, + raw_key_size, is_legacy); + + dkc->sector_bits = ilog2(dkc->sector_size); + if (ti->len & ((dkc->sector_size >> SECTOR_SHIFT) - 1)) { + ti->error = "Device size is not a multiple of sector_size"; err = -EINVAL; goto bad; } - /* Pass flush requests through to the underlying device. */ - ti->num_flush_bios = 1; + dkc->max_dun = (dkc->iv_offset + ti->len - 1) >> + (dkc->sector_bits - SECTOR_SHIFT); + dun_bytes = DIV_ROUND_UP(fls64(dkc->max_dun), 8); - /* - * We pass discard requests through to the underlying device, although - * the discarded blocks will be zeroed, which leaks information about - * unused blocks. It's also impossible for dm-default-key to know not - * to decrypt discarded blocks, so they will not be read back as zeroes - * and we must set discard_zeroes_data_unsupported. - */ - ti->num_discard_bios = 1; + err = blk_crypto_init_key(&dkc->key, raw_key, raw_key_size, + dkc->is_hw_wrapped, cipher->mode_num, + dun_bytes, dkc->sector_size); + if (err) { + ti->error = "Error initializing blk-crypto key"; + goto bad; + } - /* - * It's unclear whether WRITE_SAME would work with inline encryption; it - * would depend on whether the hardware duplicates the data before or - * after encryption. But since the internal storage in some devices - * (MSM8998-based) doesn't claim to support WRITE_SAME anyway, we don't - * currently have a way to test it. Leave it disabled it for now. - */ - /*ti->num_write_same_bios = 1;*/ + err = blk_crypto_start_using_mode(cipher->mode_num, dun_bytes, + dkc->sector_size, dkc->is_hw_wrapped, + dkc->dev->bdev->bd_queue); + if (err) { + ti->error = "Error starting to use blk-crypto"; + goto bad; + } - return 0; + ti->num_flush_bios = 1; + + ti->may_passthrough_inline_crypto = true; + + err = 0; + goto out; bad: default_key_dtr(ti); +out: + memzero_explicit(raw_key, sizeof(raw_key)); return err; } static int default_key_map(struct dm_target *ti, struct bio *bio) { const struct default_key_c *dkc = ti->private; + sector_t sector_in_target; + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = { 0 }; bio_set_dev(bio, dkc->dev->bdev); - if (bio_sectors(bio)) { - bio->bi_iter.bi_sector = dkc->start + - dm_target_offset(ti, bio->bi_iter.bi_sector); - } - if (!bio->bi_crypt_key && !bio->bi_crypt_skip) { - bio->bi_crypt_key = &dkc->key; + /* + * If the bio is a device-level request which doesn't target a specific + * sector, there's nothing more to do. + */ + if (bio_sectors(bio) == 0) + return DM_MAPIO_REMAPPED; - if (dkc->set_dun) - bio_dun(bio) = (dm_target_offset(ti, - bio->bi_iter.bi_sector) - >> 3) + dkc->dun_offset; - } + /* Map the bio's sector to the underlying device. (512-byte sectors) */ + sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector); + bio->bi_iter.bi_sector = dkc->start + sector_in_target; + + /* + * If the bio should skip dm-default-key (i.e. if it's for an encrypted + * file's contents), or if it doesn't have any data (e.g. if it's a + * DISCARD request), there's nothing more to do. + */ + if (bio_should_skip_dm_default_key(bio) || !bio_has_data(bio)) + return DM_MAPIO_REMAPPED; + + /* + * Else, dm-default-key needs to set this bio's encryption context. + * It must not already have one. + */ + if (WARN_ON_ONCE(bio_has_crypt_ctx(bio))) + return DM_MAPIO_KILL; + + /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */ + dun[0] = dkc->iv_offset + sector_in_target; /* 512-byte sectors */ + if (dun[0] & ((dkc->sector_size >> SECTOR_SHIFT) - 1)) + return DM_MAPIO_KILL; + dun[0] >>= dkc->sector_bits - SECTOR_SHIFT; /* crypto sectors */ + + /* + * This check isn't necessary as we should have calculated max_dun + * correctly, but be safe. + */ + if (WARN_ON_ONCE(dun[0] > dkc->max_dun)) + return DM_MAPIO_KILL; + + bio_crypt_set_ctx(bio, &dkc->key, dun, GFP_NOIO); return DM_MAPIO_REMAPPED; } @@ -220,46 +388,41 @@ static void default_key_status(struct dm_target *ti, status_type_t type, break; case STATUSTYPE_TABLE: - - /* encryption mode */ - DMEMIT("AES-256-XTS"); - - /* reserved for key; dm-crypt shows it, but we don't for now */ - DMEMIT(" -"); - - /* name of underlying device, and the start sector in it */ - DMEMIT(" %s %llu", dkc->dev->name, - (unsigned long long)dkc->start); - - num_feature_args += dkc->set_dun; - num_feature_args += dkc->set_dun - && dkc->dun_offset != DEFAULT_DUN_OFFSET; - - if (num_feature_args) { + /* Omit the key for now. */ + DMEMIT("%s - %llu %s %llu", dkc->cipher_string, dkc->iv_offset, + dkc->dev->name, (unsigned long long)dkc->start); + + num_feature_args += !!ti->num_discard_bios; + if (dkc->sector_size != SECTOR_SIZE) + num_feature_args += 2; + if (dkc->is_hw_wrapped) + num_feature_args += 1; + if (num_feature_args != 0) { DMEMIT(" %d", num_feature_args); - if (dkc->set_dun) - DMEMIT(" set_dun"); - if (dkc->set_dun - && dkc->dun_offset != DEFAULT_DUN_OFFSET) - DMEMIT(" dun_offset:%llu", dkc->dun_offset); + if (ti->num_discard_bios) + DMEMIT(" allow_discards"); + if (dkc->sector_size != SECTOR_SIZE) { + DMEMIT(" sector_size:%u", dkc->sector_size); + DMEMIT(" iv_large_sectors"); + } + if (dkc->is_hw_wrapped) + DMEMIT(" wrappedkey_v0"); } - break; } } static int default_key_prepare_ioctl(struct dm_target *ti, - struct block_device **bdev, fmode_t *mode) + struct block_device **bdev, + fmode_t *mode) { - struct default_key_c *dkc = ti->private; - struct dm_dev *dev = dkc->dev; + const struct default_key_c *dkc = ti->private; + const struct dm_dev *dev = dkc->dev; *bdev = dev->bdev; - /* - * Only pass ioctls through if the device sizes match exactly. - */ - if (dkc->start || + /* Only pass ioctls through if the device sizes match exactly. */ + if (dkc->start != 0 || ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) return 1; return 0; @@ -269,21 +432,35 @@ static int default_key_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { - struct default_key_c *dkc = ti->private; + const struct default_key_c *dkc = ti->private; return fn(ti, dkc->dev, dkc->start, ti->len, data); } +static void default_key_io_hints(struct dm_target *ti, + struct queue_limits *limits) +{ + const struct default_key_c *dkc = ti->private; + const unsigned int sector_size = dkc->sector_size; + + limits->logical_block_size = + max_t(unsigned short, limits->logical_block_size, sector_size); + limits->physical_block_size = + max_t(unsigned int, limits->physical_block_size, sector_size); + limits->io_min = max_t(unsigned int, limits->io_min, sector_size); +} + static struct target_type default_key_target = { - .name = "default-key", - .version = {1, 1, 0}, - .module = THIS_MODULE, - .ctr = default_key_ctr, - .dtr = default_key_dtr, - .map = default_key_map, - .status = default_key_status, - .prepare_ioctl = default_key_prepare_ioctl, - .iterate_devices = default_key_iterate_devices, + .name = "default-key", + .version = {2, 1, 0}, + .module = THIS_MODULE, + .ctr = default_key_ctr, + .dtr = default_key_dtr, + .map = default_key_map, + .status = default_key_status, + .prepare_ioctl = default_key_prepare_ioctl, + .iterate_devices = default_key_iterate_devices, + .io_hints = default_key_io_hints, }; static int __init dm_default_key_init(void) @@ -303,4 +480,4 @@ MODULE_AUTHOR("Paul Lawrence "); MODULE_AUTHOR("Paul Crowley "); MODULE_AUTHOR("Eric Biggers "); MODULE_DESCRIPTION(DM_NAME " target for encrypting filesystem metadata"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index b1b68e01b889cd42823252832a572d234965a8ad..53cd31199f212c225c303a43d3024c33ffe9bbae 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -70,6 +70,11 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, arg_name = dm_shift_arg(as); argc--; + if (!arg_name) { + ti->error = "Insufficient feature arguments"; + return -EINVAL; + } + /* * drop_writes */ diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 23f0f4eaaa2e7b7a70376bc90e6188dde2e36079..b6ca5b1100db33af9ad9e7b132cf869eea9e0438 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -187,6 +187,7 @@ struct dm_integrity_c { struct rb_root in_progress; wait_queue_head_t endio_wait; struct workqueue_struct *wait_wq; + struct workqueue_struct *offload_wq; unsigned char commit_seq; commit_id_t commit_ids[N_COMMIT_IDS]; @@ -1157,7 +1158,7 @@ static void dec_in_flight(struct dm_integrity_io *dio) dio->range.logical_sector += dio->range.n_sectors; bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT); INIT_WORK(&dio->work, integrity_bio_wait); - queue_work(ic->wait_wq, &dio->work); + queue_work(ic->offload_wq, &dio->work); return; } do_endio_flush(ic, dio); @@ -1577,7 +1578,7 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map if (need_sync_io && from_map) { INIT_WORK(&dio->work, integrity_bio_wait); - queue_work(ic->metadata_wq, &dio->work); + queue_work(ic->offload_wq, &dio->work); return; } @@ -3005,6 +3006,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } + ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM, + METADATA_WORKQUEUE_MAX_ACTIVE); + if (!ic->offload_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; + goto bad; + } + ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1); if (!ic->commit_wq) { ti->error = "Cannot allocate workqueue"; @@ -3189,6 +3198,8 @@ static void dm_integrity_dtr(struct dm_target *ti) destroy_workqueue(ic->metadata_wq); if (ic->wait_wq) destroy_workqueue(ic->wait_wq); + if (ic->offload_wq) + destroy_workqueue(ic->offload_wq); if (ic->commit_wq) destroy_workqueue(ic->commit_wq); if (ic->writer_wq) diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index c0651703159206a9f17418bc200aefd73e341bb8..d1fbf3d8b4cc3e19cc272c99ecf04e1206ca4a18 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -61,6 +61,7 @@ int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->num_discard_bios = 1; ti->num_write_same_bios = 1; ti->num_write_zeroes_bios = 1; + ti->may_passthrough_inline_crypto = true; ti->private = lc; return 0; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 0f9a8087e1a01a4226c03f589105bccf8c1ad298..f9607556362059848664cbc53911d761d2f328db 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #define DM_MSG_PREFIX "table" @@ -1597,6 +1599,54 @@ static void dm_table_verify_integrity(struct dm_table *t) } } +#ifdef CONFIG_BLK_INLINE_ENCRYPTION +static int device_intersect_crypto_modes(struct dm_target *ti, + struct dm_dev *dev, sector_t start, + sector_t len, void *data) +{ + struct keyslot_manager *parent = data; + struct keyslot_manager *child = bdev_get_queue(dev->bdev)->ksm; + + keyslot_manager_intersect_modes(parent, child); + return 0; +} + +/* + * Update the inline crypto modes supported by 'q->ksm' to be the intersection + * of the modes supported by all targets in the table. + * + * For any mode to be supported at all, all targets must have explicitly + * declared that they can pass through inline crypto support. For a particular + * mode to be supported, all underlying devices must also support it. + * + * Assume that 'q->ksm' initially declares all modes to be supported. + */ +static void dm_calculate_supported_crypto_modes(struct dm_table *t, + struct request_queue *q) +{ + struct dm_target *ti; + unsigned int i; + + for (i = 0; i < dm_table_get_num_targets(t); i++) { + ti = dm_table_get_target(t, i); + + if (!ti->may_passthrough_inline_crypto) { + keyslot_manager_intersect_modes(q->ksm, NULL); + return; + } + if (!ti->type->iterate_devices) + continue; + ti->type->iterate_devices(ti, device_intersect_crypto_modes, + q->ksm); + } +} +#else /* CONFIG_BLK_INLINE_ENCRYPTION */ +static inline void dm_calculate_supported_crypto_modes(struct dm_table *t, + struct request_queue *q) +{ +} +#endif /* !CONFIG_BLK_INLINE_ENCRYPTION */ + static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) { @@ -1689,16 +1739,6 @@ static int queue_supports_sg_merge(struct dm_target *ti, struct dm_dev *dev, return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); } -static int queue_supports_inline_encryption(struct dm_target *ti, - struct dm_dev *dev, - sector_t start, sector_t len, - void *data) -{ - struct request_queue *q = bdev_get_queue(dev->bdev); - - return q && blk_queue_inlinecrypt(q); -} - static bool dm_table_all_devices_attribute(struct dm_table *t, iterate_devices_callout_fn func) { @@ -1879,13 +1919,10 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, else queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); - if (dm_table_all_devices_attribute(t, queue_supports_inline_encryption)) - queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); - else - queue_flag_clear_unlocked(QUEUE_FLAG_INLINECRYPT, q); - dm_table_verify_integrity(t); + dm_calculate_supported_crypto_modes(t, q); + /* * Some devices don't use blk_integrity but still want stable pages * because they do their own checksumming. diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index 776a4f77f76ce6031d54401a23dd39ca89ca6524..052419ac1ce622fcb61853548f23208776bbc9a6 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -439,7 +439,7 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, fio->level++; if (type == DM_VERITY_BLOCK_TYPE_METADATA) - block += v->data_blocks; + block = block - v->hash_start + v->data_blocks; /* * For RS(M, N), the continuous FEC data is divided into blocks of N @@ -556,6 +556,7 @@ void verity_fec_dtr(struct dm_verity *v) mempool_destroy(f->rs_pool); mempool_destroy(f->prealloc_pool); mempool_destroy(f->extra_pool); + mempool_destroy(f->output_pool); kmem_cache_destroy(f->cache); if (f->data_bufio) diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c index 9b78f4a74a12edbea05badbcedb8e4034f23483a..4d658a0c602587358caca34268f04eb990754227 100644 --- a/drivers/md/dm-zoned-metadata.c +++ b/drivers/md/dm-zoned-metadata.c @@ -132,6 +132,7 @@ struct dmz_metadata { sector_t zone_bitmap_size; unsigned int zone_nr_bitmap_blocks; + unsigned int zone_bits_per_mblk; unsigned int nr_bitmap_blocks; unsigned int nr_map_blocks; @@ -1104,7 +1105,6 @@ static int dmz_init_zone(struct dmz_metadata *zmd, struct dm_zone *zone, if (blkz->type == BLK_ZONE_TYPE_CONVENTIONAL) { set_bit(DMZ_RND, &zone->flags); - zmd->nr_rnd_zones++; } else if (blkz->type == BLK_ZONE_TYPE_SEQWRITE_REQ || blkz->type == BLK_ZONE_TYPE_SEQWRITE_PREF) { set_bit(DMZ_SEQ, &zone->flags); @@ -1165,7 +1165,10 @@ static int dmz_init_zones(struct dmz_metadata *zmd) /* Init */ zmd->zone_bitmap_size = dev->zone_nr_blocks >> 3; - zmd->zone_nr_bitmap_blocks = zmd->zone_bitmap_size >> DMZ_BLOCK_SHIFT; + zmd->zone_nr_bitmap_blocks = + max_t(sector_t, 1, zmd->zone_bitmap_size >> DMZ_BLOCK_SHIFT); + zmd->zone_bits_per_mblk = min_t(sector_t, dev->zone_nr_blocks, + DMZ_BLOCK_SIZE_BITS); /* Allocate zone array */ zmd->zones = kcalloc(dev->nr_zones, sizeof(struct dm_zone), GFP_KERNEL); @@ -1982,7 +1985,7 @@ int dmz_copy_valid_blocks(struct dmz_metadata *zmd, struct dm_zone *from_zone, dmz_release_mblock(zmd, to_mblk); dmz_release_mblock(zmd, from_mblk); - chunk_block += DMZ_BLOCK_SIZE_BITS; + chunk_block += zmd->zone_bits_per_mblk; } to_zone->weight = from_zone->weight; @@ -2043,7 +2046,7 @@ int dmz_validate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone, /* Set bits */ bit = chunk_block & DMZ_BLOCK_MASK_BITS; - nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); + nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit); count = dmz_set_bits((unsigned long *)mblk->data, bit, nr_bits); if (count) { @@ -2122,7 +2125,7 @@ int dmz_invalidate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone, /* Clear bits */ bit = chunk_block & DMZ_BLOCK_MASK_BITS; - nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); + nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit); count = dmz_clear_bits((unsigned long *)mblk->data, bit, nr_bits); @@ -2182,6 +2185,7 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone, { struct dmz_mblock *mblk; unsigned int bit, set_bit, nr_bits; + unsigned int zone_bits = zmd->zone_bits_per_mblk; unsigned long *bitmap; int n = 0; @@ -2196,15 +2200,15 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone, /* Get offset */ bitmap = (unsigned long *) mblk->data; bit = chunk_block & DMZ_BLOCK_MASK_BITS; - nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); + nr_bits = min(nr_blocks, zone_bits - bit); if (set) - set_bit = find_next_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit); + set_bit = find_next_bit(bitmap, zone_bits, bit); else - set_bit = find_next_zero_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit); + set_bit = find_next_zero_bit(bitmap, zone_bits, bit); dmz_release_mblock(zmd, mblk); n += set_bit - bit; - if (set_bit < DMZ_BLOCK_SIZE_BITS) + if (set_bit < zone_bits) break; nr_blocks -= nr_bits; @@ -2307,7 +2311,7 @@ static void dmz_get_zone_weight(struct dmz_metadata *zmd, struct dm_zone *zone) /* Count bits in this block */ bitmap = mblk->data; bit = chunk_block & DMZ_BLOCK_MASK_BITS; - nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); + nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit); n += dmz_count_bits(bitmap, bit, nr_bits); dmz_release_mblock(zmd, mblk); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index a56008b2e7c27ba70e730f18c12cf41032f4c645..bb78417a249bb0c8cedb1a76db2091835626de1d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #define DM_MSG_PREFIX "core" @@ -1249,9 +1251,10 @@ static int clone_bio(struct dm_target_io *tio, struct bio *bio, __bio_clone_fast(clone, bio); + bio_crypt_clone(clone, bio, GFP_NOIO); + if (unlikely(bio_integrity(bio) != NULL)) { int r; - if (unlikely(!dm_target_has_integrity(tio->ti->type) && !dm_target_passes_integrity(tio->ti->type))) { DMWARN("%s: the target %s doesn't support integrity data.", @@ -1647,7 +1650,6 @@ void dm_init_md_queue(struct mapped_device *md) * - must do so here (in alloc_dev callchain) before queue is used */ md->queue->queuedata = md; - md->queue->backing_dev_info->congested_data = md; } void dm_init_normal_md_queue(struct mapped_device *md) @@ -1658,9 +1660,12 @@ void dm_init_normal_md_queue(struct mapped_device *md) /* * Initialize aspects of queue that aren't relevant for blk-mq */ + md->queue->backing_dev_info->congested_data = md; md->queue->backing_dev_info->congested_fn = dm_any_congested; } +static void dm_destroy_inline_encryption(struct request_queue *q); + static void cleanup_mapped_device(struct mapped_device *md) { if (md->wq) @@ -1685,8 +1690,10 @@ static void cleanup_mapped_device(struct mapped_device *md) put_disk(md->disk); } - if (md->queue) + if (md->queue) { + dm_destroy_inline_encryption(md->queue); blk_cleanup_queue(md->queue); + } cleanup_srcu_struct(&md->io_barrier); @@ -1750,6 +1757,12 @@ static struct mapped_device *alloc_dev(int minor) goto bad; dm_init_md_queue(md); + /* + * default to bio-based required ->make_request_fn until DM + * table is loaded and md->type established. If request-based + * table is loaded: blk-mq will override accordingly. + */ + blk_queue_make_request(md->queue, dm_make_request); md->disk = alloc_disk_node(1, numa_node_id); if (!md->disk) @@ -2029,6 +2042,165 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md) } EXPORT_SYMBOL_GPL(dm_get_queue_limits); +#ifdef CONFIG_BLK_INLINE_ENCRYPTION +struct dm_keyslot_evict_args { + const struct blk_crypto_key *key; + int err; +}; + +static int dm_keyslot_evict_callback(struct dm_target *ti, struct dm_dev *dev, + sector_t start, sector_t len, void *data) +{ + struct dm_keyslot_evict_args *args = data; + int err; + + err = blk_crypto_evict_key(dev->bdev->bd_queue, args->key); + if (!args->err) + args->err = err; + /* Always try to evict the key from all devices. */ + return 0; +} + +/* + * When an inline encryption key is evicted from a device-mapper device, evict + * it from all the underlying devices. + */ +static int dm_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, unsigned int slot) +{ + struct mapped_device *md = keyslot_manager_private(ksm); + struct dm_keyslot_evict_args args = { key }; + struct dm_table *t; + int srcu_idx; + int i; + struct dm_target *ti; + + t = dm_get_live_table(md, &srcu_idx); + if (!t) + return 0; + for (i = 0; i < dm_table_get_num_targets(t); i++) { + ti = dm_table_get_target(t, i); + if (!ti->type->iterate_devices) + continue; + ti->type->iterate_devices(ti, dm_keyslot_evict_callback, &args); + } + dm_put_live_table(md, srcu_idx); + return args.err; +} + +struct dm_derive_raw_secret_args { + const u8 *wrapped_key; + unsigned int wrapped_key_size; + u8 *secret; + unsigned int secret_size; + int err; +}; + +static int dm_derive_raw_secret_callback(struct dm_target *ti, + struct dm_dev *dev, sector_t start, + sector_t len, void *data) +{ + struct dm_derive_raw_secret_args *args = data; + struct request_queue *q = dev->bdev->bd_queue; + + if (!args->err) + return 0; + + if (!q->ksm) { + args->err = -EOPNOTSUPP; + return 0; + } + + args->err = keyslot_manager_derive_raw_secret(q->ksm, args->wrapped_key, + args->wrapped_key_size, + args->secret, + args->secret_size); + /* Try another device in case this fails. */ + return 0; +} + +/* + * Retrieve the raw_secret from the underlying device. Given that + * only only one raw_secret can exist for a particular wrappedkey, + * retrieve it only from the first device that supports derive_raw_secret() + */ +static int dm_derive_raw_secret(struct keyslot_manager *ksm, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, unsigned int secret_size) +{ + struct mapped_device *md = keyslot_manager_private(ksm); + struct dm_derive_raw_secret_args args = { + .wrapped_key = wrapped_key, + .wrapped_key_size = wrapped_key_size, + .secret = secret, + .secret_size = secret_size, + .err = -EOPNOTSUPP, + }; + struct dm_table *t; + int srcu_idx; + int i; + struct dm_target *ti; + + t = dm_get_live_table(md, &srcu_idx); + if (!t) + return -EOPNOTSUPP; + for (i = 0; i < dm_table_get_num_targets(t); i++) { + ti = dm_table_get_target(t, i); + if (!ti->type->iterate_devices) + continue; + ti->type->iterate_devices(ti, dm_derive_raw_secret_callback, + &args); + if (!args.err) + break; + } + dm_put_live_table(md, srcu_idx); + return args.err; +} + +static struct keyslot_mgmt_ll_ops dm_ksm_ll_ops = { + .keyslot_evict = dm_keyslot_evict, + .derive_raw_secret = dm_derive_raw_secret, +}; + +static int dm_init_inline_encryption(struct mapped_device *md) +{ + unsigned int features; + unsigned int mode_masks[BLK_ENCRYPTION_MODE_MAX]; + + /* + * Initially declare support for all crypto settings. Anything + * unsupported by a child device will be removed later when calculating + * the device restrictions. + */ + features = BLK_CRYPTO_FEATURE_STANDARD_KEYS | + BLK_CRYPTO_FEATURE_WRAPPED_KEYS; + memset(mode_masks, 0xFF, sizeof(mode_masks)); + + md->queue->ksm = keyslot_manager_create_passthrough(&dm_ksm_ll_ops, + features, + mode_masks, md); + if (!md->queue->ksm) + return -ENOMEM; + return 0; +} + +static void dm_destroy_inline_encryption(struct request_queue *q) +{ + keyslot_manager_destroy(q->ksm); + q->ksm = NULL; +} +#else /* CONFIG_BLK_INLINE_ENCRYPTION */ +static inline int dm_init_inline_encryption(struct mapped_device *md) +{ + return 0; +} + +static inline void dm_destroy_inline_encryption(struct request_queue *q) +{ +} +#endif /* !CONFIG_BLK_INLINE_ENCRYPTION */ + /* * Setup the DM device's queue based on md's type */ @@ -2055,7 +2227,6 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) case DM_TYPE_BIO_BASED: case DM_TYPE_DAX_BIO_BASED: dm_init_normal_md_queue(md); - blk_queue_make_request(md->queue, dm_make_request); /* * DM handles splitting bios as needed. Free the bio_split bioset * since it won't be used (saves 1 process per bio-based DM device). @@ -2068,6 +2239,12 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) break; } + r = dm_init_inline_encryption(md); + if (r) { + DMERR("Cannot initialize inline encryption"); + return r; + } + return 0; } diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c index 829b4ce057d8cbaa873a6cfdd2cbc1ed934b5e18..97f16fe14f542002760496f2d3c4ed343b9c0a49 100644 --- a/drivers/md/persistent-data/dm-space-map-common.c +++ b/drivers/md/persistent-data/dm-space-map-common.c @@ -382,6 +382,33 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin, return -ENOSPC; } +int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll, + dm_block_t begin, dm_block_t end, dm_block_t *b) +{ + int r; + uint32_t count; + + do { + r = sm_ll_find_free_block(new_ll, begin, new_ll->nr_blocks, b); + if (r) + break; + + /* double check this block wasn't used in the old transaction */ + if (*b >= old_ll->nr_blocks) + count = 0; + else { + r = sm_ll_lookup(old_ll, *b, &count); + if (r) + break; + + if (count) + begin = *b + 1; + } + } while (count); + + return r; +} + static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b, int (*mutator)(void *context, uint32_t old, uint32_t *new), void *context, enum allocation_event *ev) diff --git a/drivers/md/persistent-data/dm-space-map-common.h b/drivers/md/persistent-data/dm-space-map-common.h index b3078d5eda0c335c2986b84128d3e5bde01e8b8e..8de63ce39bdd53d099cb91eb50647f0d703d727a 100644 --- a/drivers/md/persistent-data/dm-space-map-common.h +++ b/drivers/md/persistent-data/dm-space-map-common.h @@ -109,6 +109,8 @@ int sm_ll_lookup_bitmap(struct ll_disk *ll, dm_block_t b, uint32_t *result); int sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result); int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin, dm_block_t end, dm_block_t *result); +int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll, + dm_block_t begin, dm_block_t end, dm_block_t *result); int sm_ll_insert(struct ll_disk *ll, dm_block_t b, uint32_t ref_count, enum allocation_event *ev); int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev); int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev); diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c index 32adf6b4a9c7097e12796f8b396f80bfc8867c0a..bf4c5e2ccb6ffc8d8e0fa5ba049429bdb6dc18d0 100644 --- a/drivers/md/persistent-data/dm-space-map-disk.c +++ b/drivers/md/persistent-data/dm-space-map-disk.c @@ -167,8 +167,10 @@ static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b) enum allocation_event ev; struct sm_disk *smd = container_of(sm, struct sm_disk, sm); - /* FIXME: we should loop round a couple of times */ - r = sm_ll_find_free_block(&smd->old_ll, smd->begin, smd->old_ll.nr_blocks, b); + /* + * Any block we allocate has to be free in both the old and current ll. + */ + r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b); if (r) return r; diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index b23cac2c473819cd944843d728272760d273fb23..31a999458be955dd41234444c2d2dc31efc7a0c0 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -447,7 +447,10 @@ static int sm_metadata_new_block_(struct dm_space_map *sm, dm_block_t *b) enum allocation_event ev; struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); - r = sm_ll_find_free_block(&smm->old_ll, smm->begin, smm->old_ll.nr_blocks, b); + /* + * Any block we allocate has to be free in both the old and current ll. + */ + r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, smm->begin, smm->ll.nr_blocks, b); if (r) return r; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 296c5f8a8c633a11450f6d12a8df6de768f54142..1991c22be51a9f44e60f4ddc9ee3688554c03a12 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -372,10 +372,10 @@ int adv748x_write_block(struct adv748x_state *state, int client_page, #define io_read(s, r) adv748x_read(s, ADV748X_PAGE_IO, r) #define io_write(s, r, v) adv748x_write(s, ADV748X_PAGE_IO, r, v) -#define io_clrset(s, r, m, v) io_write(s, r, (io_read(s, r) & ~m) | v) +#define io_clrset(s, r, m, v) io_write(s, r, (io_read(s, r) & ~(m)) | (v)) #define hdmi_read(s, r) adv748x_read(s, ADV748X_PAGE_HDMI, r) -#define hdmi_read16(s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, r+1)) & m) +#define hdmi_read16(s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, (r)+1)) & (m)) #define hdmi_write(s, r, v) adv748x_write(s, ADV748X_PAGE_HDMI, r, v) #define repeater_read(s, r) adv748x_read(s, ADV748X_PAGE_REPEATER, r) @@ -383,11 +383,11 @@ int adv748x_write_block(struct adv748x_state *state, int client_page, #define sdp_read(s, r) adv748x_read(s, ADV748X_PAGE_SDP, r) #define sdp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_SDP, r, v) -#define sdp_clrset(s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~m) | v) +#define sdp_clrset(s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~(m)) | (v)) #define cp_read(s, r) adv748x_read(s, ADV748X_PAGE_CP, r) #define cp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v) -#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v) +#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~(m)) | (v)) #define txa_read(s, r) adv748x_read(s, ADV748X_PAGE_TXA, r) #define txb_read(s, r) adv748x_read(s, ADV748X_PAGE_TXB, r) diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 8a430640c85d512038d4de97960d12768c728190..1a20d0d558d3e88a0cb0b12dda532864e13cff16 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -423,10 +423,12 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + code->code = mt9v032->format.code; return 0; } @@ -434,7 +436,11 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + + if (fse->index >= 3) + return -EINVAL; + if (mt9v032->format.code != fse->code) return -EINVAL; fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index); diff --git a/drivers/media/platform/msm/ais/ais_isp/Makefile b/drivers/media/platform/msm/ais/ais_isp/Makefile index 96ff9c02a624cbaa7d851b350ee3b435e27183e6..277eb8275180f6377f5ac2b3c1f1257a674b3172 100644 --- a/drivers/media/platform/msm/ais/ais_isp/Makefile +++ b/drivers/media/platform/msm/ais/ais_isp/Makefile @@ -8,5 +8,6 @@ ccflags-y += -Idrivers/media/platform/msm/ais/cam_cdm/ obj-$(CONFIG_MSM_AIS) += csid_hw/ obj-$(CONFIG_MSM_AIS) += vfe_hw/ +obj-$(CONFIG_MSM_AIS) += utils/ obj-$(CONFIG_MSM_AIS) += ais_ife_dev.o diff --git a/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.c b/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.c index f46889625f8f955fdcbf18ae82591c5144938fa8..89e378afcebe5930223994ef0c0968b53985c60e 100644 --- a/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.c +++ b/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.c @@ -476,16 +476,12 @@ static int ais_ife_dev_cb(void *priv, struct ais_ife_event_data *evt_data) return -EINVAL; } - spin_lock_bh(&p_ife_dev->eventq_lock); - /* Queue the event */ memcpy(event.u.data, (void *)evt_data, sizeof(*evt_data)); event.id = V4L_EVENT_ID_AIS_IFE; event.type = V4L_EVENT_TYPE_AIS_IFE; v4l2_event_queue(p_ife_dev->cam_sd.sd.devnode, &event); - spin_unlock_bh(&p_ife_dev->eventq_lock); - return 0; } @@ -502,7 +498,8 @@ static void ais_ife_dev_iommu_fault_handler( p_ife_dev = (struct ais_ife_dev *)token; - CAM_ERR(CAM_ISP, "IFE%d Pagefault at %lu", p_ife_dev->hw_idx, iova); + CAM_ERR(CAM_ISP, "IFE%d Pagefault at iova 0x%x %s", + p_ife_dev->hw_idx, iova, domain->name); } static int ais_ife_dev_remove(struct platform_device *pdev) @@ -553,7 +550,6 @@ static int ais_ife_dev_probe(struct platform_device *pdev) } mutex_init(&p_ife_dev->mutex); - spin_lock_init(&p_ife_dev->eventq_lock); /* * for now, we only support one iommu handle. later @@ -575,13 +571,19 @@ static int ais_ife_dev_probe(struct platform_device *pdev) goto attach_fail; } - rc = cam_smmu_get_handle("cam-secure", + rc = cam_smmu_get_handle("ife-cp", &p_ife_dev->iommu_hdl_secure); if (rc) { CAM_ERR(CAM_ISP, "Failed to get secure iommu handle %d", rc); goto secure_fail; } + rc = cam_smmu_ops(p_ife_dev->iommu_hdl_secure, CAM_SMMU_ATTACH); + if (rc && rc != -EALREADY) { + CAM_ERR(CAM_ISP, "Attach secure iommu handle failed %d", rc); + goto secure_fail; + } + CAM_DBG(CAM_ISP, "iommu_handles: non-secure[0x%x], secure[0x%x]", p_ife_dev->iommu_hdl, p_ife_dev->iommu_hdl_secure); @@ -589,6 +591,9 @@ static int ais_ife_dev_probe(struct platform_device *pdev) cam_smmu_set_client_page_fault_handler(p_ife_dev->iommu_hdl, ais_ife_dev_iommu_fault_handler, p_ife_dev); + cam_smmu_set_client_page_fault_handler(p_ife_dev->iommu_hdl_secure, + ais_ife_dev_iommu_fault_handler, p_ife_dev); + hw_init.hw_idx = p_ife_dev->hw_idx; hw_init.iommu_hdl = p_ife_dev->iommu_hdl; hw_init.iommu_hdl_secure = p_ife_dev->iommu_hdl_secure; @@ -598,14 +603,14 @@ static int ais_ife_dev_probe(struct platform_device *pdev) rc = ais_ife_csid_hw_init(&p_ife_dev->p_csid_drv, &hw_init); if (rc) { CAM_ERR(CAM_ISP, "IFE%d no CSID dev", p_ife_dev->hw_idx, rc); - goto secure_fail; + goto secure_attach_fail; } rc = ais_vfe_hw_init(&p_ife_dev->p_vfe_drv, &hw_init, p_ife_dev->p_csid_drv); if (rc) { CAM_ERR(CAM_ISP, "IFE%d no VFE dev", p_ife_dev->hw_idx, rc); - goto secure_fail; + goto secure_attach_fail; } CAM_INFO(CAM_ISP, "IFE%d probe complete", p_ife_dev->hw_idx); @@ -614,6 +619,9 @@ static int ais_ife_dev_probe(struct platform_device *pdev) return 0; +secure_attach_fail: + cam_smmu_ops(p_ife_dev->iommu_hdl_secure, + CAM_SMMU_DETACH); secure_fail: cam_smmu_ops(p_ife_dev->iommu_hdl, CAM_SMMU_DETACH); diff --git a/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.h b/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.h index 340b6ee91b43169d61ca7dcf73cc4d95fef237a7..4273c4c1f7ab7fe74456188a7bc454d8acd5b5eb 100644 --- a/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.h +++ b/drivers/media/platform/msm/ais/ais_isp/ais_ife_dev.h @@ -40,7 +40,6 @@ struct ais_ife_dev { int iommu_hdl; int iommu_hdl_secure; - spinlock_t eventq_lock; struct mutex mutex; int32_t open_cnt; }; diff --git a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c index eaf983776cb010edb94a385843aa328c80eb3b4f..77b0e1905d496deabfc35fdb1683c978e1d5a1fd 100644 --- a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c @@ -577,24 +577,6 @@ static int ais_ife_csid_config_rdi_path( else path_cfg->pix_enable = true; - /* - * RDI path config and enable the time stamp capture - * Enable the measurement blocks - */ - cfg0 = (path_cfg->vc << csid_reg->cmn_reg->vc_shift_val) | - (path_cfg->dt << csid_reg->cmn_reg->dt_shift_val) | - (path_cfg->cid << csid_reg->cmn_reg->dt_id_shift_val) | - (path_cfg->decode_fmt << csid_reg->cmn_reg->fmt_shift_val) | - (path_cfg->plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | - (path_cfg->crop_enable << - csid_reg->cmn_reg->crop_h_en_shift_val) | - (path_cfg->crop_enable << - csid_reg->cmn_reg->crop_v_en_shift_val) | - (1 << 2) | 3; - - cam_io_w_mb(cfg0, soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); - /* select the post irq sub sample strobe for time stamp capture */ cam_io_w_mb(CSID_TIMESTAMP_STB_POST_IRQ, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr); @@ -701,8 +683,18 @@ static int ais_ife_csid_config_rdi_path( } } - /* Enable the path */ - cfg0 |= (1 << csid_reg->cmn_reg->path_en_shift_val); + /* RDI path config and enable*/ + cfg0 = (path_cfg->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_cfg->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_cfg->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (path_cfg->decode_fmt << csid_reg->cmn_reg->fmt_shift_val) | + (path_cfg->plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | + (path_cfg->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_cfg->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << csid_reg->cmn_reg->path_en_shift_val) | + (1 << 2) | 3; cam_io_w_mb(cfg0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); diff --git a/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h b/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h index e09030b2196f4f55a50a7b289654051be9df19a5..a6ac796674ecc9f708ac80dd320d08ab2584e9f0 100644 --- a/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h +++ b/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h @@ -479,6 +479,7 @@ struct ais_ife_frame_msg { enum ais_ife_msg_type { AIS_IFE_MSG_SOF, AIS_IFE_MSG_FRAME_DONE, + AIS_IFE_MSG_OUTPUT_WARNING, AIS_IFE_MSG_OUTPUT_ERROR, AIS_IFE_MSG_CSID_WARNING, AIS_IFE_MSG_CSID_ERROR diff --git a/drivers/media/platform/msm/ais/ais_isp/utils/Makefile b/drivers/media/platform/msm/ais/ais_isp/utils/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bada56e9bf980e8403ecd9556d8b0f7cf427ba5f --- /dev/null +++ b/drivers/media/platform/msm/ais/ais_isp/utils/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/ais/cam_core +ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp/include +ccflags-y += -Idrivers/media/platform/msm/ais/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/ais/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/ais/cam_sync +ccflags-y += -Idrivers/media/platform/msm/ais/cam_utils +ccflags-y += -Idrivers/media/platform/msm/ais/cam_cdm/ + +obj-$(CONFIG_MSM_AIS) += ais_isp_trace.o diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi b/drivers/media/platform/msm/ais/ais_isp/utils/ais_isp_trace.c similarity index 76% rename from arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi rename to drivers/media/platform/msm/ais/ais_isp/utils/ais_isp_trace.c index faafcf82f5e3ce0aac93a47d06e5c3ae907aabe9..659acf4b11865d91767b43cbb1f2167cb2485852 100644 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi +++ b/drivers/media/platform/msm/ais/ais_isp/utils/ais_isp_trace.c @@ -8,12 +8,9 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + * */ -#include "trinket-audio-overlay.dtsi" - -&sm6150_snd { - qcom,msm-mbhc-usbc-audio-supported = <1>; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <1>; -}; +/* Instantiate tracepoints */ +#define CREATE_TRACE_POINTS +#include "ais_isp_trace.h" diff --git a/drivers/media/platform/msm/ais/ais_isp/utils/ais_isp_trace.h b/drivers/media/platform/msm/ais/ais_isp/utils/ais_isp_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..e2ff0184306ea1df21f4eb8df0b44f5d7b71102f --- /dev/null +++ b/drivers/media/platform/msm/ais/ais_isp/utils/ais_isp_trace.h @@ -0,0 +1,229 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#if !defined(_AIS_ISP_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _AIS_ISP_TRACE_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM camera +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE ais_isp_trace + +#include +#include +#include "ais_isp_hw.h" + +TRACE_EVENT(ais_isp_vfe_irq_activated, + TP_PROTO(uint8_t id, uint32_t status0, uint32_t status1), + TP_ARGS(id, status0, status1), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint32_t, status0) + __field(uint32_t, status1) + ), + TP_fast_assign( + __entry->id = id; + __entry->status0 = status0; + __entry->status1 = status1; + ), + TP_printk( + "vfe%d: irq 0x%08x 0x%08x", + __entry->id, + __entry->status0, __entry->status1 + ) +); + +TRACE_EVENT(ais_isp_irq_process, + TP_PROTO(uint8_t id, uint8_t evt, uint8_t state), + TP_ARGS(id, evt, state), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, evt) + __field(uint8_t, state) + ), + TP_fast_assign( + __entry->id = id; + __entry->evt = evt; + __entry->state = state; + ), + TP_printk( + "vfe%d: irq event %d (%d)", + __entry->id, __entry->evt, __entry->state + ) +); + +TRACE_EVENT(ais_isp_vfe_state, + TP_PROTO(uint8_t id, uint8_t path, uint8_t state), + TP_ARGS(id, path, state), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint8_t, state) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->state = state; + ), + TP_printk( + "vfe%d:%d: state %d", + __entry->id, __entry->path, __entry->state + ) +); + +TRACE_EVENT(ais_isp_vfe_sof, + TP_PROTO(uint8_t id, uint8_t path, struct ais_ife_rdi_timestamps *ts, + uint32_t fifo, uint32_t miss), + TP_ARGS(id, path, ts, fifo, miss), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint32_t, fifo) + __field(uint32_t, miss) + __field(uint64_t, ts_cur) + __field(uint64_t, ts_prev) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->fifo = fifo; + __entry->miss = miss; + __entry->ts_cur = ts->cur_sof_ts; + __entry->ts_prev = ts->prev_sof_ts; + ), + TP_printk( + "vfe%d:%d: sof %llu %llu fifo %u miss %u", + __entry->id, __entry->path, __entry->ts_cur, __entry->ts_prev, + __entry->fifo, __entry->miss + ) +); + +TRACE_EVENT(ais_isp_vfe_q_sof, + TP_PROTO(uint8_t id, uint8_t path, uint32_t frame, uint64_t ts), + TP_ARGS(id, path, frame, ts), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint32_t, frame) + __field(uint64_t, ts) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->frame = frame; + __entry->ts = ts; + ), + TP_printk( + "vfe%d:%d: sof %d %llu", + __entry->id, __entry->path, __entry->frame, __entry->ts + ) +); + +TRACE_EVENT(ais_isp_vfe_buf_done, + TP_PROTO(uint8_t id, uint8_t path, uint8_t idx, uint32_t frame, + uint8_t fifo, uint8_t match), + TP_ARGS(id, path, idx, frame, fifo, match), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint8_t, idx) + __field(uint32_t, frame) + __field(uint8_t, fifo) + __field(uint8_t, match) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->idx = idx; + __entry->frame = frame; + __entry->fifo = fifo; + __entry->match = match; + ), + TP_printk( + "vfe%d:%d: buf_done %d (%d fifo %d match %d)", + __entry->id, __entry->path, __entry->idx, __entry->frame, + __entry->fifo, __entry->match + ) +); + +TRACE_EVENT(ais_isp_vfe_enq_buf_hw, + TP_PROTO(uint8_t id, uint8_t path, uint8_t idx, + uint8_t fifo, uint8_t full), + TP_ARGS(id, path, idx, fifo, full), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint8_t, idx) + __field(uint8_t, fifo) + __field(uint8_t, full) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->idx = idx; + __entry->fifo = fifo; + __entry->full = full; + ), + TP_printk( + "vfe%d:%d: enq buf hw %d fifo %d full %d", + __entry->id, __entry->path, __entry->idx, + __entry->fifo, __entry->full + ) +); + +TRACE_EVENT(ais_isp_vfe_enq_req, + TP_PROTO(uint8_t id, uint8_t path, uint8_t idx), + TP_ARGS(id, path, idx), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint8_t, idx) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->idx = idx; + ), + TP_printk( + "vfe%d:%d: enq req %d", + __entry->id, __entry->path, __entry->idx + ) +); + +TRACE_EVENT(ais_isp_vfe_error, + TP_PROTO(uint8_t id, uint8_t path, uint8_t err, uint8_t payload), + TP_ARGS(id, path, err, payload), + TP_STRUCT__entry( + __field(uint8_t, id) + __field(uint8_t, path) + __field(uint8_t, err) + __field(uint8_t, payload) + ), + TP_fast_assign( + __entry->id = id; + __entry->path = path; + __entry->err = err; + __entry->payload = payload; + ), + TP_printk( + "vfe%d:%d: error %d %d", + __entry->id, __entry->path, __entry->err, __entry->payload + ) +); + +#endif /* _AIS_ISP_TRACE_H */ + +/* This part must be outside protection */ +#include diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/Makefile b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/Makefile index 45f022014a743075100effd9c1290ea8a9a7fc79..81e5b8b88dcdc99e0a2ce8cbcae2578a8e66247a 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/Makefile +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/Makefile @@ -5,6 +5,7 @@ ccflags-y += -Idrivers/media/platform/msm/ais/cam_smmu/ ccflags-y += -Idrivers/media/platform/msm/ais/cam_req_mgr/ ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp/include +ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp/utils ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp/vfe_hw/include ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe_bus/include ccflags-y += -Idrivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe_bus diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c index 73a57ca7ae650687e3a95f841879dde0ccf81fd3..ba0c2b9e13888b525505864f38498a9096bd0113 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c @@ -20,6 +20,7 @@ #include "ais_vfe_soc.h" #include "ais_vfe_core.h" #include "cam_debug_util.h" +#include "ais_isp_trace.h" /*VFE TOP DEFINITIONS*/ #define AIS_VFE_HW_RESET_HW_AND_REG_VAL 0x00003F9F @@ -52,9 +53,10 @@ #define AIS_VFE_REGUP_RDI_SHIFT 1 #define AIS_VFE_REGUP_RDI_ALL 0x1E -/*VFE BUS DEFINITIONS*/ -#define MAX_NUM_BUF_HW_FIFOQ 4 +/*Allow max of 4 HW FIFO Q + 2 delayed buffers before error*/ +#define MAX_NUM_BUF_SW_FIFOQ_ERR 6 +/*VFE BUS DEFINITIONS*/ #define AIS_VFE_BUS_SET_DEBUG_REG 0x82 #define AIS_VFE_RDI_BUS_DEFAULT_WIDTH 0xFF01 @@ -72,8 +74,6 @@ static void ais_clear_rdi_path(struct ais_vfe_rdi_output *rdi_path) int i; rdi_path->frame_cnt = 0; - rdi_path->sof_ts = 0; - rdi_path->sof_hw_ts = 0; rdi_path->num_buffer_hw_q = 0; INIT_LIST_HEAD(&rdi_path->buffer_q); @@ -84,6 +84,17 @@ static void ais_clear_rdi_path(struct ais_vfe_rdi_output *rdi_path) list_add_tail(&rdi_path->buffers[i].list, &rdi_path->free_buffer_list); } + + memset(&rdi_path->last_sof_info, 0, sizeof(rdi_path->last_sof_info)); + + rdi_path->num_sof_info_q = 0; + INIT_LIST_HEAD(&rdi_path->sof_info_q); + INIT_LIST_HEAD(&rdi_path->free_sof_info_list); + for (i = 0; i < AIS_VFE_MAX_SOF_INFO; i++) { + INIT_LIST_HEAD(&rdi_path->sof_info[i].list); + list_add_tail(&rdi_path->sof_info[i].list, + &rdi_path->free_sof_info_list); + } } static int ais_vfe_bus_hw_init(struct ais_vfe_hw_core_info *core_info) @@ -427,6 +438,8 @@ int ais_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) goto EXIT; } + rdi_path->secure_mode = rdi_cfg->out_cfg.secure_mode; + cam_io_w(0xf, core_info->mem_base + client_regs->burst_limit); /*disable pack as it is done in CSID*/ cam_io_w(0x0, core_info->mem_base + client_regs->packer_cfg); @@ -664,19 +677,27 @@ int ais_vfe_write(void *hw_priv, void *write_args, uint32_t arg_size) return -EPERM; } -static void ais_vfe_queue_to_hw(struct ais_vfe_hw_core_info *core_info, +static void ais_vfe_q_bufs_to_hw(struct ais_vfe_hw_core_info *core_info, enum ais_ife_output_path_id path) { struct ais_vfe_rdi_output *rdi_path = NULL; struct ais_vfe_buffer_t *vfe_buf = NULL; struct ais_vfe_bus_ver2_hw_info *bus_hw_info = NULL; struct ais_vfe_bus_ver2_reg_offset_bus_client *client_regs = NULL; + uint32_t fifo_status = 0; + bool is_full = false; + struct ais_ife_rdi_get_timestamp_args get_ts; rdi_path = &core_info->rdi_out[path]; bus_hw_info = core_info->vfe_hw_info->bus_hw_info; client_regs = &bus_hw_info->bus_client_reg[path]; - while (rdi_path->num_buffer_hw_q < MAX_NUM_BUF_HW_FIFOQ) { + fifo_status = cam_io_r_mb(core_info->mem_base + + bus_hw_info->common_reg.addr_fifo_status); + + is_full = fifo_status & (1 << path); + + while (!is_full) { if (list_empty(&rdi_path->buffer_q)) break; @@ -684,17 +705,38 @@ static void ais_vfe_queue_to_hw(struct ais_vfe_hw_core_info *core_info, struct ais_vfe_buffer_t, list); list_del_init(&vfe_buf->list); - CAM_DBG(CAM_ISP, "IFE%d BUF| RDI%d Q %d(0x%x) FIFO:%d", + get_ts.path = path; + get_ts.ts = &vfe_buf->ts_hw; + core_info->csid_hw->hw_ops.process_cmd( + core_info->csid_hw->hw_priv, + AIS_IFE_CSID_CMD_GET_TIME_STAMP, + &get_ts, + sizeof(get_ts)); + + + CAM_DBG(CAM_ISP, "IFE%d|RDI%d: Q %d(0x%x) FIFO:%d ts %llu", core_info->vfe_idx, path, vfe_buf->bufIdx, vfe_buf->iova_addr, - rdi_path->num_buffer_hw_q); + rdi_path->num_buffer_hw_q, vfe_buf->ts_hw.cur_sof_ts); cam_io_w_mb(vfe_buf->iova_addr, core_info->mem_base + client_regs->image_addr); list_add_tail(&vfe_buf->list, &rdi_path->buffer_hw_q); ++rdi_path->num_buffer_hw_q; + + + fifo_status = cam_io_r_mb(core_info->mem_base + + bus_hw_info->common_reg.addr_fifo_status); + is_full = fifo_status & (1 << path); + + trace_ais_isp_vfe_enq_buf_hw(core_info->vfe_idx, path, + vfe_buf->bufIdx, rdi_path->num_buffer_hw_q, is_full); } + + if (rdi_path->num_buffer_hw_q > MAX_NUM_BUF_SW_FIFOQ_ERR) + CAM_WARN(CAM_ISP, "Excessive number of buffers in SW FIFO (%d)", + rdi_path->num_buffer_hw_q); } @@ -737,8 +779,11 @@ static int ais_vfe_cmd_enq_buf(struct ais_vfe_hw_core_info *core_info, vfe_buf->bufIdx = enq_buf->buffer.idx; vfe_buf->mem_handle = enq_buf->buffer.mem_handle; - mmu_hdl = cam_mem_is_secure_buf(vfe_buf->mem_handle) ? - core_info->iommu_hdl_secure : core_info->iommu_hdl; + mmu_hdl = core_info->iommu_hdl; + + if (cam_mem_is_secure_buf(vfe_buf->mem_handle) || rdi_path->secure_mode) + mmu_hdl = core_info->iommu_hdl_secure; + rc = cam_mem_get_io_buf(vfe_buf->mem_handle, mmu_hdl, &vfe_buf->iova_addr, &src_buf_size); if (rc < 0) { @@ -766,8 +811,15 @@ static int ais_vfe_cmd_enq_buf(struct ais_vfe_hw_core_info *core_info, vfe_buf->iova_addr += enq_buf->buffer.offset; spin_lock(&rdi_path->buffer_lock); + + trace_ais_isp_vfe_enq_req(core_info->vfe_idx, enq_buf->path, + enq_buf->buffer.idx); + list_add_tail(&vfe_buf->list, &rdi_path->buffer_q); - ais_vfe_queue_to_hw(core_info, enq_buf->path); + + if (rdi_path->state < AIS_ISP_RESOURCE_STATE_STREAMING) + ais_vfe_q_bufs_to_hw(core_info, enq_buf->path); + spin_unlock(&rdi_path->buffer_lock); } @@ -816,6 +868,201 @@ int ais_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, return rc; } +static uint8_t ais_vfe_get_num_missed_sof( + uint64_t cur_sof, + uint64_t prev_sof, + uint64_t last_sof, + uint64_t ts_delta) +{ + uint8_t miss_sof = 0; + + if (prev_sof == last_sof) { + miss_sof = 0; + } else if (prev_sof < last_sof) { + //rollover case + miss_sof = (int)(((U64_MAX - last_sof) + prev_sof + 1 + + ts_delta/2) / ts_delta); + } else { + miss_sof = (int)((prev_sof - last_sof + ts_delta/2) / ts_delta); + } + + return miss_sof; +} + +static int ais_vfe_q_sof(struct ais_vfe_hw_core_info *core_info, + enum ais_ife_output_path_id path, + struct ais_sof_info_t *p_sof) +{ + struct ais_vfe_rdi_output *p_rdi = &core_info->rdi_out[path]; + struct ais_sof_info_t *p_sof_info = NULL; + int rc = 0; + + if (!list_empty(&p_rdi->free_sof_info_list)) { + p_sof_info = list_first_entry(&p_rdi->free_sof_info_list, + struct ais_sof_info_t, list); + list_del_init(&p_sof_info->list); + p_sof_info->frame_cnt = p_sof->frame_cnt; + p_sof_info->sof_ts = p_sof->sof_ts; + p_sof_info->cur_sof_hw_ts = p_sof->cur_sof_hw_ts; + p_sof_info->prev_sof_hw_ts = p_sof->prev_sof_hw_ts; + list_add_tail(&p_sof_info->list, &p_rdi->sof_info_q); + p_rdi->num_sof_info_q++; + + trace_ais_isp_vfe_q_sof(core_info->vfe_idx, path, + p_sof->frame_cnt, p_sof->cur_sof_hw_ts); + + CAM_DBG(CAM_ISP, "I%d|R%d|F%llu: sof %llu", + core_info->vfe_idx, path, p_sof->frame_cnt, + p_sof_info->cur_sof_hw_ts); + } else { + rc = -1; + + CAM_ERR(CAM_ISP, + "I%d|R%d|F%llu: free timestamp empty (%d) sof %llu", + core_info->vfe_idx, path, p_sof->frame_cnt, + p_rdi->num_buffer_hw_q, p_sof->cur_sof_hw_ts); + } + + return rc; +} + + +static void ais_vfe_handle_sof_rdi(struct ais_vfe_hw_core_info *core_info, + struct ais_vfe_hw_work_data *work_data, + enum ais_ife_output_path_id path) +{ + struct ais_vfe_rdi_output *p_rdi = &core_info->rdi_out[path]; + uint64_t cur_sof_hw_ts = work_data->ts_hw[path].cur_sof_ts; + uint64_t prev_sof_hw_ts = work_data->ts_hw[path].prev_sof_ts; + + p_rdi->frame_cnt++; + + if (p_rdi->num_buffer_hw_q) { + struct ais_sof_info_t sof = {}; + uint64_t ts_delta; + uint8_t miss_sof = 0; + + if (cur_sof_hw_ts < prev_sof_hw_ts) + ts_delta = cur_sof_hw_ts + + (U64_MAX - prev_sof_hw_ts); + else + ts_delta = cur_sof_hw_ts - prev_sof_hw_ts; + + + //check any missing SOFs + if (p_rdi->frame_cnt > 1) { + if (ts_delta == 0) { + CAM_ERR(CAM_ISP, "IFE%d RDI%d ts_delta is 0", + core_info->vfe_idx, path); + } else { + miss_sof = ais_vfe_get_num_missed_sof( + cur_sof_hw_ts, + prev_sof_hw_ts, + p_rdi->last_sof_info.cur_sof_hw_ts, + ts_delta); + + CAM_DBG(CAM_ISP, + "I%d R%d miss_sof %u prev %llu last %llu cur %llu", + core_info->vfe_idx, path, + miss_sof, prev_sof_hw_ts, + p_rdi->last_sof_info.cur_sof_hw_ts, + cur_sof_hw_ts); + } + } + + trace_ais_isp_vfe_sof(core_info->vfe_idx, path, + &work_data->ts_hw[path], + p_rdi->num_buffer_hw_q, miss_sof); + + if (p_rdi->frame_cnt == 1 && prev_sof_hw_ts != 0) { + //enq missed first frame + sof.sof_ts = work_data->ts; + sof.cur_sof_hw_ts = prev_sof_hw_ts; + sof.frame_cnt = p_rdi->frame_cnt++; + + ais_vfe_q_sof(core_info, path, &sof); + } else if (miss_sof > 0) { + if (miss_sof > 1) { + int i = 0; + int miss_idx = miss_sof - 1; + + for (i = 0; i < (miss_sof - 1); i++) { + + sof.sof_ts = work_data->ts; + sof.cur_sof_hw_ts = prev_sof_hw_ts - + (ts_delta * miss_idx); + sof.frame_cnt = p_rdi->frame_cnt++; + + ais_vfe_q_sof(core_info, path, &sof); + + miss_idx--; + } + } + + //enq prev + sof.sof_ts = work_data->ts; + sof.cur_sof_hw_ts = prev_sof_hw_ts; + sof.frame_cnt = p_rdi->frame_cnt++; + + ais_vfe_q_sof(core_info, path, &sof); + } + + //enq curr + sof.sof_ts = work_data->ts; + sof.cur_sof_hw_ts = cur_sof_hw_ts; + sof.frame_cnt = p_rdi->frame_cnt; + + ais_vfe_q_sof(core_info, path, &sof); + + } else { + trace_ais_isp_vfe_sof(core_info->vfe_idx, path, + &work_data->ts_hw[path], + p_rdi->num_buffer_hw_q, 0); + + CAM_DBG(CAM_ISP, "I%d R%d Flush SOF (%d) HW Q empty", + core_info->vfe_idx, path, + p_rdi->num_sof_info_q); + + if (p_rdi->num_sof_info_q) { + struct ais_sof_info_t *p_sof_info; + + while (!list_empty(&p_rdi->sof_info_q)) { + p_sof_info = list_first_entry( + &p_rdi->sof_info_q, + struct ais_sof_info_t, list); + list_del_init(&p_sof_info->list); + list_add_tail(&p_sof_info->list, + &p_rdi->free_sof_info_list); + } + p_rdi->num_sof_info_q = 0; + } + + trace_ais_isp_vfe_error(core_info->vfe_idx, + path, 1, 0); + + //send warning + core_info->event.type = AIS_IFE_MSG_OUTPUT_WARNING; + core_info->event.path = path; + core_info->event.u.err_msg.reserved = 0; + + core_info->event_cb(core_info->event_cb_priv, + &core_info->event); + + } + + p_rdi->last_sof_info.cur_sof_hw_ts = cur_sof_hw_ts; + + //send sof only for current frame + core_info->event.type = AIS_IFE_MSG_SOF; + core_info->event.path = path; + core_info->event.u.sof_msg.frame_id = p_rdi->frame_cnt; + core_info->event.u.sof_msg.hw_ts = cur_sof_hw_ts; + + core_info->event_cb(core_info->event_cb_priv, + &core_info->event); + +} + static int ais_vfe_handle_sof( struct ais_vfe_hw_core_info *core_info, struct ais_vfe_hw_work_data *work_data) @@ -827,7 +1074,7 @@ static int ais_vfe_handle_sof( CAM_DBG(CAM_ISP, "IFE%d SOF RDIs 0x%x", core_info->vfe_idx, work_data->path); - for (path = 0; path <= AIS_IFE_PATH_MAX; path++) { + for (path = 0; path < AIS_IFE_PATH_MAX; path++) { if (!(work_data->path & (1 << path))) continue; @@ -836,17 +1083,12 @@ static int ais_vfe_handle_sof( if (p_rdi->state != AIS_ISP_RESOURCE_STATE_STREAMING) continue; - p_rdi->frame_cnt++; - p_rdi->sof_ts = work_data->ts; - p_rdi->sof_hw_ts = work_data->ts_hw[path].cur_sof_ts; + ais_vfe_handle_sof_rdi(core_info, work_data, path); - core_info->event.type = AIS_IFE_MSG_SOF; - core_info->event.path = path; - core_info->event.u.sof_msg.frame_id = p_rdi->frame_cnt; - core_info->event.u.sof_msg.hw_ts = p_rdi->sof_ts; - - core_info->event_cb(core_info->event_cb_priv, - &core_info->event); + //enq buffers + spin_lock_bh(&p_rdi->buffer_lock); + ais_vfe_q_bufs_to_hw(core_info, path); + spin_unlock_bh(&p_rdi->buffer_lock); } return rc; @@ -867,34 +1109,43 @@ static int ais_vfe_handle_error( CAM_ERR(CAM_ISP, "IFE%d ERROR on RDIs 0x%x", core_info->vfe_idx, work_data->path); + trace_ais_isp_vfe_error(core_info->vfe_idx, + work_data->path, 0, 0); + top_hw_info = core_info->vfe_hw_info->top_hw_info; bus_hw_info = core_info->vfe_hw_info->bus_hw_info; bus_hw_irq_regs = bus_hw_info->common_reg.irq_reg_info.irq_reg_set; - for (path = 0; path <= AIS_IFE_PATH_MAX; path++) { + for (path = 0; path < AIS_IFE_PATH_MAX; path++) { if (!(work_data->path & (1 << path))) continue; p_rdi = &core_info->rdi_out[path]; + if (p_rdi->state != AIS_ISP_RESOURCE_STATE_STREAMING) continue; + CAM_ERR(CAM_ISP, "IFE%d Turn off RDI %d", + core_info->vfe_idx, path); + p_rdi->state = AIS_ISP_RESOURCE_STATE_ERROR; client_regs = &bus_hw_info->bus_client_reg[path]; + core_info->bus_wr_mask1 &= ~(1 << path); + cam_io_w_mb(core_info->bus_wr_mask1, + core_info->mem_base + + bus_hw_irq_regs[1].mask_reg_offset); + /* Disable WM and reg-update */ cam_io_w_mb(0x0, core_info->mem_base + client_regs->cfg); cam_io_w_mb(AIS_VFE_REGUP_RDI_ALL, core_info->mem_base + top_hw_info->common_reg->reg_update_cmd); + cam_io_w_mb((1 << path), core_info->mem_base + - bus_hw_info->common_reg.sw_reset); + bus_hw_info->common_reg.sw_reset); - core_info->bus_wr_mask1 &= ~(1 << path); - cam_io_w_mb(core_info->bus_wr_mask1, - core_info->mem_base + - bus_hw_irq_regs[1].mask_reg_offset); core_info->event.type = AIS_IFE_MSG_OUTPUT_ERROR; core_info->event.path = path; @@ -914,19 +1165,34 @@ static void ais_vfe_bus_handle_client_frame_done( struct ais_vfe_rdi_output *rdi_path = NULL; struct ais_vfe_buffer_t *vfe_buf = NULL; struct ais_vfe_bus_ver2_hw_info *bus_hw_info = NULL; + uint64_t frame_cnt = 0; + uint64_t sof_ts; + uint64_t cur_sof_hw_ts; bool last_addr_match = false; - CAM_DBG(CAM_ISP, "Frame Done Client %d", path); + + CAM_DBG(CAM_ISP, "I%d|R%d last_addr 0x%x", + core_info->vfe_idx, path, last_addr); + + if (last_addr == 0) { + CAM_ERR(CAM_ISP, "I%d|R%d null last_addr", + core_info->vfe_idx, path); + return; + } rdi_path = &core_info->rdi_out[path]; bus_hw_info = core_info->vfe_hw_info->bus_hw_info; - spin_lock_bh(&rdi_path->buffer_lock); + core_info->event.type = AIS_IFE_MSG_FRAME_DONE; + core_info->event.path = path; while (rdi_path->num_buffer_hw_q && !last_addr_match) { + struct ais_sof_info_t *p_sof_info = NULL; + bool is_sof_match = false; + if (list_empty(&rdi_path->buffer_hw_q)) { - CAM_ERR(CAM_ISP, "Received RDI%d FD while SW Q empty", - path); + CAM_DBG(CAM_ISP, "I%d|R%d: FD while HW Q empty", + core_info->vfe_idx, path); break; } @@ -935,35 +1201,125 @@ static void ais_vfe_bus_handle_client_frame_done( list_del_init(&vfe_buf->list); --rdi_path->num_buffer_hw_q; - CAM_DBG(CAM_ISP, "IFE%d BUF| RDI%d DQ %d (0x%x) FIFO:%d|0x%x", + if (last_addr == vfe_buf->iova_addr) + last_addr_match = true; + else + CAM_WARN(CAM_ISP, "IFE%d buf %d did not match addr", + core_info->vfe_idx, vfe_buf->bufIdx); + + CAM_DBG(CAM_ISP, "I%d|R%d BUF DQ %d (0x%x) FIFO:%d|0x%x", core_info->vfe_idx, path, vfe_buf->bufIdx, vfe_buf->iova_addr, rdi_path->num_buffer_hw_q, last_addr); - core_info->event.type = AIS_IFE_MSG_FRAME_DONE; - core_info->event.path = path; - core_info->event.u.frame_msg.frame_id = rdi_path->frame_cnt; + if (!list_empty(&rdi_path->sof_info_q)) { + while (!is_sof_match && + !list_empty(&rdi_path->sof_info_q)) { + p_sof_info = + list_first_entry(&rdi_path->sof_info_q, + struct ais_sof_info_t, list); + list_del_init(&p_sof_info->list); + rdi_path->num_sof_info_q--; + if (p_sof_info->cur_sof_hw_ts > + vfe_buf->ts_hw.cur_sof_ts) { + is_sof_match = true; + break; + } + list_add_tail(&p_sof_info->list, + &rdi_path->free_sof_info_list); + } + + if (!is_sof_match) { + p_sof_info = NULL; + CAM_ERR(CAM_ISP, + "I%d|R%d: can't find the match sof", + core_info->vfe_idx, path); + } + + } else + CAM_ERR(CAM_ISP, "I%d|R%d: SOF info Q is empty", + core_info->vfe_idx, path); + + if (p_sof_info) { + frame_cnt = p_sof_info->frame_cnt; + sof_ts = p_sof_info->sof_ts; + cur_sof_hw_ts = p_sof_info->cur_sof_hw_ts; + list_add_tail(&p_sof_info->list, + &rdi_path->free_sof_info_list); + } else { + frame_cnt = sof_ts = cur_sof_hw_ts = 0; + } + + CAM_DBG(CAM_ISP, "I%d|R%d|F%llu: si [%llu, %llu, %llu]", + core_info->vfe_idx, path, frame_cnt, sof_ts, + cur_sof_hw_ts); + + + trace_ais_isp_vfe_buf_done(core_info->vfe_idx, path, + vfe_buf->bufIdx, + frame_cnt, + rdi_path->num_buffer_hw_q, + last_addr_match); + + core_info->event.u.frame_msg.frame_id = frame_cnt; core_info->event.u.frame_msg.buf_idx = vfe_buf->bufIdx; - core_info->event.u.frame_msg.ts = rdi_path->sof_ts; - core_info->event.u.frame_msg.hw_ts = rdi_path->sof_hw_ts; + core_info->event.u.frame_msg.ts = sof_ts; + core_info->event.u.frame_msg.hw_ts = cur_sof_hw_ts; core_info->event_cb(core_info->event_cb_priv, &core_info->event); - if (last_addr == vfe_buf->iova_addr) - last_addr_match = true; - else - CAM_WARN(CAM_ISP, "IFE%d buf %d did not match addr", - core_info->vfe_idx, vfe_buf->bufIdx); list_add_tail(&vfe_buf->list, &rdi_path->free_buffer_list); } - if (!last_addr_match) + if (!last_addr_match) { CAM_ERR(CAM_ISP, "IFE%d BUF| RDI%d NO MATCH addr 0x%x", core_info->vfe_idx, path, last_addr); - ais_vfe_queue_to_hw(core_info, path); + trace_ais_isp_vfe_error(core_info->vfe_idx, path, 1, 1); + + //send warning + core_info->event.type = AIS_IFE_MSG_OUTPUT_WARNING; + core_info->event.path = path; + core_info->event.u.err_msg.reserved = 1; + + core_info->event_cb(core_info->event_cb_priv, + &core_info->event); + } + + /* Flush SOF info Q if HW Buffer Q is empty */ + if (rdi_path->num_buffer_hw_q == 0) { + struct ais_sof_info_t *p_sof_info = NULL; + + CAM_DBG(CAM_ISP, "I%d|R%d|F%llu: Flush SOF (%d) HW Q empty", + core_info->vfe_idx, path, frame_cnt, + rdi_path->num_sof_info_q); + + while (!list_empty(&rdi_path->sof_info_q)) { + p_sof_info = list_first_entry(&rdi_path->sof_info_q, + struct ais_sof_info_t, list); + list_del_init(&p_sof_info->list); + list_add_tail(&p_sof_info->list, + &rdi_path->free_sof_info_list); + } + + rdi_path->num_sof_info_q = 0; + + trace_ais_isp_vfe_error(core_info->vfe_idx, path, 1, 0); + + //send warning + core_info->event.type = AIS_IFE_MSG_OUTPUT_WARNING; + core_info->event.path = path; + core_info->event.u.err_msg.reserved = 0; + + core_info->event_cb(core_info->event_cb_priv, + &core_info->event); + } + + spin_lock_bh(&rdi_path->buffer_lock); + + ais_vfe_q_bufs_to_hw(core_info, path); spin_unlock_bh(&rdi_path->buffer_lock); } @@ -1101,6 +1457,8 @@ static int ais_vfe_process_irq_bh(void *priv, void *data) } work_data = (struct ais_vfe_hw_work_data *)data; + + trace_ais_isp_irq_process(core_info->vfe_idx, work_data->evt_type, 1); CAM_DBG(CAM_ISP, "VFE[%d] event %d", core_info->vfe_idx, work_data->evt_type); @@ -1123,6 +1481,8 @@ static int ais_vfe_process_irq_bh(void *priv, void *data) break; } + trace_ais_isp_irq_process(core_info->vfe_idx, work_data->evt_type, 2); + return rc; } @@ -1147,6 +1507,8 @@ static int ais_vfe_dispatch_irq(struct cam_hw_info *vfe_hw, work_data = (struct ais_vfe_hw_work_data *)task->payload; *work_data = *p_work; + trace_ais_isp_irq_process(core_info->vfe_idx, p_work->evt_type, 0); + task->process_cb = ais_vfe_process_irq_bh; rc = cam_req_mgr_workq_enqueue_task(task, vfe_hw, CRM_TASK_PRIORITY_0); @@ -1174,6 +1536,8 @@ irqreturn_t ais_vfe_irq(int irq_num, void *data) cam_io_w_mb(ife_status[1], core_info->mem_base + AIS_VFE_IRQ_CLEAR1); cam_io_w_mb(0x1, core_info->mem_base + AIS_VFE_IRQ_CMD); + trace_ais_isp_vfe_irq_activated(core_info->vfe_idx, + ife_status[0], ife_status[1]); CAM_DBG(CAM_ISP, "VFE%d irq status 0x%x 0x%x", core_info->vfe_idx, ife_status[0], ife_status[1]); @@ -1230,6 +1594,7 @@ irqreturn_t ais_vfe_irq(int irq_num, void *data) CAM_DBG(CAM_ISP, "IFE%d BUS_WR", core_info->vfe_idx); work_data.evt_type = AIS_VFE_HW_IRQ_EVENT_BUS_WR; ais_vfe_irq_fill_bus_wr_status(core_info, &work_data); + ais_vfe_dispatch_irq(vfe_hw, &work_data); } if (ife_status[1]) { @@ -1238,9 +1603,10 @@ irqreturn_t ais_vfe_irq(int irq_num, void *data) AIS_VFE_STATUS1_RDI_OVERFLOW_IRQ_SHFT) & AIS_VFE_STATUS1_RDI_OVERFLOW_IRQ_MSK; - CAM_ERR(CAM_ISP, "IFE%d Overflow 0x%x", - core_info->vfe_idx, - work_data.path); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "IFE%d Overflow 0x%x", + core_info->vfe_idx, + work_data.path); work_data.evt_type = AIS_VFE_HW_IRQ_EVENT_ERROR; ais_vfe_dispatch_irq(vfe_hw, &work_data); } diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.h b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.h index 5e97352e730078a90c335ef301720b8e4f772a2c..ad097ce4bd0fcd090686e7e037a8f824a81e1ff2 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.h +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.h @@ -20,8 +20,9 @@ #include "ais_vfe_bus_ver2.h" #include "ais_vfe_top_ver2.h" -#define AIS_VFE_WORKQ_NUM_TASK 16 +#define AIS_VFE_WORKQ_NUM_TASK 20 #define AIS_VFE_MAX_BUF 12 +#define AIS_VFE_MAX_SOF_INFO 8 enum ais_vfe_hw_irq_event { AIS_VFE_HW_IRQ_EVENT_SOF, @@ -81,12 +82,22 @@ struct ais_vfe_buffer_t { int32_t mem_handle; uint64_t iova_addr; uint32_t bufIdx; + struct ais_ife_rdi_timestamps ts_hw; +}; + +struct ais_sof_info_t { + struct list_head list; + uint64_t frame_cnt; + uint64_t sof_ts; + uint64_t cur_sof_hw_ts; + uint64_t prev_sof_hw_ts; }; struct ais_vfe_rdi_output { enum ais_isp_resource_state state; uint32_t en_cfg; + uint32_t secure_mode; spinlock_t buffer_lock; struct ais_vfe_buffer_t buffers[AIS_VFE_MAX_BUF]; @@ -96,8 +107,12 @@ struct ais_vfe_rdi_output { struct list_head free_buffer_list; uint64_t frame_cnt; - uint64_t sof_ts; - uint64_t sof_hw_ts; + + uint8_t num_sof_info_q; + struct ais_sof_info_t sof_info[AIS_VFE_MAX_SOF_INFO]; + struct list_head sof_info_q; + struct list_head free_sof_info_list; + struct ais_sof_info_t last_sof_info; }; struct ais_vfe_hw_core_info { diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe170.h b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe170.h index 9dff0fce58be67661a2aa3ad085d3fceedda41ec..bf947f734c5ebddbf34df61e7cfd03dd1ac56ef6 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe170.h +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe170.h @@ -429,6 +429,7 @@ static struct ais_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .addr_sync_cfg = 0x0000207C, .addr_sync_frame_hdr = 0x00002080, .addr_sync_no_sync = 0x00002084, + .addr_fifo_status = 0x000020A8, .debug_status_cfg = 0x0000226C, .debug_status_0 = 0x00002270, }, diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175.h b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175.h index 96f6e132ad76c6fdebb7a39980a63f7c17d8c89f..b9ab2d54e7d2a0bb5cb13cc2bb0421119f191cbb 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175.h +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175.h @@ -502,6 +502,7 @@ static struct ais_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { .addr_sync_cfg = 0x0000207C, .addr_sync_frame_hdr = 0x00002080, .addr_sync_no_sync = 0x00002084, + .addr_fifo_status = 0x000020A8, .debug_status_cfg = 0x0000226C, .debug_status_0 = 0x00002270, }, diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175_130.h b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175_130.h index f08acc80a34630accaf092fe0a64ab40b3138a0d..e834f5302d5f75ce3a5e419ddeffba85ab00ea83 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175_130.h +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe175_130.h @@ -601,6 +601,7 @@ static struct ais_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { .addr_sync_cfg = 0x0000207C, .addr_sync_frame_hdr = 0x00002080, .addr_sync_no_sync = 0x00002084, + .addr_fifo_status = 0x000020A8, }, .num_client = 24, .is_lite = 0, diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe_lite17x.h b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe_lite17x.h index da34e081bb0c4c9b6fcf5ad98734a1f105f45066..fa042e9815c294b6621fe6cd3a7a02757ca2f05f 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe_lite17x.h +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe17x/ais_vfe_lite17x.h @@ -148,6 +148,7 @@ static struct ais_vfe_bus_ver2_hw_info vfe17x_bus_hw_info = { .addr_sync_cfg = 0x0000207C, .addr_sync_frame_hdr = 0x00002080, .addr_sync_no_sync = 0x00002084, + .addr_fifo_status = 0x000020A8, }, .num_client = 4, .is_lite = 1, diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe_bus/ais_vfe_bus_ver2.h b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe_bus/ais_vfe_bus_ver2.h index e81deba043c82bb097dd33f1b6d0e280cffce847..435fea779fd751de2d9aa6799ba767e545a86069 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe_bus/ais_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/vfe_bus/ais_vfe_bus_ver2.h @@ -119,6 +119,7 @@ struct ais_vfe_bus_ver2_reg_offset_common { uint32_t addr_sync_cfg; uint32_t addr_sync_frame_hdr; uint32_t addr_sync_no_sync; + uint32_t addr_fifo_status; uint32_t debug_status_cfg; uint32_t debug_status_0; }; diff --git a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 7c349f66c3dea582f09b7cbe60dbef5c57aa69c4..78e8332729eadb11bb21a574404d2ec68c3f21e3 100644 --- a/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/ais/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -6337,9 +6337,10 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) return -EINVAL; } - if (cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl, - CAM_SMMU_ATTACH)) { - CAM_ERR(CAM_ISP, "Attach iommu handle failed."); + rc = cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl, + CAM_SMMU_ATTACH); + if (rc && rc != -EALREADY) { + CAM_ERR(CAM_ISP, "Attach iommu handle failed %d", rc); goto attach_fail; } diff --git a/drivers/media/platform/msm/ais/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/ais/cam_req_mgr/cam_mem_mgr.c index 33094cd010a1fcd69509aa3af90594921d969deb..33949b9161fbc44b52bb3c8abdf67c409ed3a2b7 100644 --- a/drivers/media/platform/msm/ais/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/ais/cam_req_mgr/cam_mem_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -217,6 +217,7 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, tbl.bufq[idx].fd, iova_ptr, len_ptr); + if (rc) { CAM_ERR(CAM_MEM, "fail to map buf_hdl:0x%x, mmu_hdl: 0x%x for fd:%d", @@ -511,6 +512,9 @@ static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, } else if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) { heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_CAMERA; + } else if (cmd->flags & CAM_MEM_FLAG_CP_PIXEL) { + heap_id = ION_HEAP(ION_SECURE_HEAP_ID); + ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_PIXEL; } else { heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | ION_HEAP(ION_CAMERA_HEAP_ID); @@ -540,8 +544,9 @@ static int cam_mem_util_check_alloc_flags(struct cam_mem_mgr_alloc_cmd *cmd) return -EINVAL; } - if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && - cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + if (((cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) || + (cmd->flags & CAM_MEM_FLAG_CP_PIXEL)) && + (cmd->flags & CAM_MEM_FLAG_KMD_ACCESS)) { CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); return -EINVAL; } @@ -562,8 +567,9 @@ static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd) return -EINVAL; } - if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && - cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + if (((cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) || + (cmd->flags & CAM_MEM_FLAG_CP_PIXEL)) && + (cmd->flags & CAM_MEM_FLAG_KMD_ACCESS)) { CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed, flags=0x%x", cmd->flags); diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c index 45eb1f449d35412a362708dc6d0dfe1d9a9551b7..419d748f5f1d3cfd75238ced8b15655d34a6f31e 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c @@ -2015,7 +2015,14 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, struct cam_cci_ctrl *cci_ctrl) { int32_t rc = 0; - struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + struct cci_device *cci_dev; + + if (sd == NULL || cci_ctrl == NULL) { + CAM_ERR(CAM_CCI, "cci_ctrl or sd null"); + rc = -ENODEV; + return rc; + } + cci_dev = v4l2_get_subdevdata(sd); CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); @@ -2073,12 +2080,10 @@ int32_t cam_cci_core_cam_ctrl(struct v4l2_subdev *sd, CAM_DBG(CAM_CCI, "cmd %d", cmd->op_code); - if (cmd->op_code != AIS_SENSOR_I2C_POWER_DOWN) { - if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { - CAM_ERR(CAM_CCI, "Invalid handle type: %d", + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_CCI, "Invalid handle type: %d", cmd->handle_type); - return -EINVAL; - } + return -EINVAL; } cci_ctrl.cci_info = kzalloc(sizeof(struct cam_sensor_cci_client), @@ -2092,7 +2097,7 @@ int32_t cam_cci_core_cam_ctrl(struct v4l2_subdev *sd, sensor_cap.slot_info = cci_dev->soc_info.index; if (copy_to_user(u64_to_user_ptr(cmd->handle), - &sensor_cap, sizeof(struct cam_sensor_query_cap))) { + &sensor_cap, sizeof(sensor_cap))) { CAM_ERR(CAM_CCI, "Failed Copy to User"); rc = -EFAULT; } diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.c index 4a6edef2f0fbec01e41b71bbb392bfe3c7953628..6f6b7b2890e9dc3545faae6335079495c406fabb 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -37,9 +37,6 @@ static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd, } switch (cmd) { - case VIDIOC_MSM_CCI_CFG: - rc = cam_cci_core_cfg(sd, arg); - break; case VIDIOC_CAM_CONTROL: rc = cam_cci_core_cam_ctrl(sd, arg); break; diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.h index 1c21e035447ef4868c1023ce919f6543bfc390ae..3e410b30e0acfbeb8aab434920fc6fc9fc7396a0 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -324,7 +324,5 @@ static inline struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) } #endif -#define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) #endif /* _CAM_CCI_DEV_H_ */ diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index 16edb38d0f8899596bf2997137b37af8006b7774..0078142eead32061afed4f880b8e8ad66002e404 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,7 +12,7 @@ #include "cam_sensor_cmn_header.h" #include "cam_sensor_i2c.h" -#include "cam_cci_dev.h" +#include "cam_cci_core.h" int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, uint32_t addr, uint32_t *data, @@ -36,8 +36,8 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; - rc = v4l2_subdev_call(cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + + rc = cam_cci_core_cfg(cci_client->cci_subdev, &cci_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "rc = %d", rc); return rc; @@ -88,14 +88,18 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; cci_ctrl.status = -EFAULT; - rc = v4l2_subdev_call(cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); - rc = cci_ctrl.status; + + rc = cam_cci_core_cfg(cci_client->cci_subdev, &cci_ctrl); CAM_DBG(CAM_SENSOR, "addr = 0x%x, rc = %d", addr, rc); - for (i = 0; i < num_byte; i++) { - data[i] = buf[i]; - CAM_DBG(CAM_SENSOR, "Byte %d: Data: 0x%x\n", i, data[i]); + + if (!rc) { + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + CAM_DBG(CAM_SENSOR, "Byte %d: Data: 0x%x", + i, data[i]); + } } + kfree(buf); return rc; } @@ -124,13 +128,13 @@ static int32_t cam_cci_i2c_write_table_cmd( cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = write_setting->addr_type; cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; - rc = v4l2_subdev_call(cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + + rc = cam_cci_core_cfg(cci_client->cci_subdev, &cci_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); return rc; } - rc = cci_ctrl.status; + if (write_setting->delay > 20) msleep(write_setting->delay); else if (write_setting->delay) @@ -229,11 +233,11 @@ int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client, cci_ctrl.cmd = cci_cmd; cci_ctrl.cci_info = cci_client; - rc = v4l2_subdev_call(cci_client->cci_subdev, - core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + + rc = cam_cci_core_cfg(cci_client->cci_subdev, &cci_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); - return rc; } - return cci_ctrl.status; + + return rc; } diff --git a/drivers/media/platform/msm/ais/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/ais/cam_smmu/cam_smmu_api.c index a89270254ca4a9f0c4e76147ab93b7b13c424b0b..256842c73c204f3876713fc5d716858b91ba211e 100644 --- a/drivers/media/platform/msm/ais/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/ais/cam_smmu/cam_smmu_api.c @@ -36,7 +36,7 @@ #define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE) #define COOKIE_MASK ((1<> COOKIE_SIZE) & COOKIE_MASK) @@ -105,7 +105,10 @@ struct cam_context_bank_info { dma_addr_t va_start; size_t va_len; const char *name; + /* stage 2 only */ bool is_secure; + /* stage 1 */ + bool is_secure_pixel; uint8_t scratch_buf_support; uint8_t firmware_support; uint8_t shared_support; @@ -3269,6 +3272,20 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, goto end; } + if (cb->is_secure_pixel) { + int secure_vmid = VMID_CP_PIXEL; + + rc = iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_SECURE_VMID, &secure_vmid); + if (rc) { + CAM_ERR(CAM_SMMU, + "programming secure vmid failed: %s %d", + dev_name(dev), rc); + rc = -ENODEV; + goto end; + } + } + return rc; end: if (cb->shared_support) { @@ -3345,6 +3362,10 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, mem_map_node = of_get_child_by_name(of_node, "iova-mem-map"); cb->is_secure = of_property_read_bool(of_node, "qcom,secure-cb"); + if (!cb->is_secure) + cb->is_secure_pixel = of_property_read_bool(of_node, + "qcom,secure-pixel-cb"); + /* * We always expect a memory map node, except when it is a secure * context bank. diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index 3c61d883d4579585317fd21c72e35cd1ae10ecb9..60e11681b60422fcfd923021e06d098c182a9c41 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c @@ -1053,8 +1053,8 @@ static int cam_context_dump_context(struct cam_context *ctx, struct cam_context_dump_header *hdr; char *dst; uint64_t *addr, *start; - uintptr_t cpu_addr; - size_t buf_len; + uintptr_t cpu_addr = 0; + size_t buf_len = 0; uint32_t min_len, remain_len; struct cam_ctx_request *req; int i; diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 91a1b141e6596fd018577da845b3e6848185afbb..2caf6d0a844d9d04410f16c9936fbb5292074cb2 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1579,6 +1579,7 @@ static int cam_fd_mgr_hw_dump(void *hw_mgr_priv, frame_req->submit_timestamp.tv_usec, cur_time.tv_sec, cur_time.tv_usec); + memset(&fd_dump_args, 0, sizeof(fd_dump_args)); rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &fd_dump_args.cpu_addr, &fd_dump_args.buf_len); if (!fd_dump_args.cpu_addr || !fd_dump_args.buf_len || rc) { diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 2143bb70afeabc118177073b344863b0f5fc54bd..e3b5bb3d89024395567503a7cb7d2f2ca8242f02 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -4611,6 +4611,7 @@ static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args) frm_process->submit_timestamp[i].tv_usec, cur_time.tv_sec, cur_time.tv_usec); + memset(&icp_dump_args, 0, sizeof(icp_dump_args)); rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &icp_dump_args.cpu_addr, &icp_dump_args.buf_len); if (!icp_dump_args.cpu_addr || !icp_dump_args.buf_len || rc) { diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index 2ac164251e0127ac3245601050aa3b84a8ddb745..e1fa02cb1f167c2c8e4690c8489d35199c802bb1 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -228,7 +228,7 @@ static void __cam_isp_ctx_dump_state_monitor_array( ctx_monitor = ctx_isp->cam_isp_ctx_state_monitor; if (log_rate_limit) - CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + CAM_DBG(CAM_ISP, "Dumping state information for preceding requests"); else CAM_INFO(CAM_ISP, @@ -241,7 +241,7 @@ static void __cam_isp_ctx_dump_state_monitor_array( CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES); if (log_rate_limit) { - CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + CAM_DBG(CAM_ISP, "time[%lld] last reported req_id[%u] frame id[%lld] applied id[%lld] current state[%s] next state[%s] hw_event[%s]", ctx_monitor[index].evt_time_stamp, ctx_monitor[index].last_reported_id, @@ -876,11 +876,13 @@ static int __cam_isp_ctx_reg_upd_in_epoch_state( else if (ctx_isp->fps && ((rup_event_data->irq_mono_boot_time - ctx_isp->irq_timestamps) > ((1000*1000)/ctx_isp->fps))) { ctx_isp->irq_delay_detect = true; - trace_cam_isp_irq_delay_detect("IRQ delay at reg_upd", - ctx, req->request_id, - ctx_isp->substate_activated, - (rup_event_data->irq_mono_boot_time - - ctx_isp->irq_timestamps)); + + if (req) + trace_cam_isp_irq_delay_detect("IRQ delay at reg_upd", + ctx, req->request_id, + ctx_isp->substate_activated, + (rup_event_data->irq_mono_boot_time - + ctx_isp->irq_timestamps)); } ctx_isp->irq_timestamps = rup_event_data->irq_mono_boot_time; @@ -905,7 +907,7 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( list_del_init(&req->list); req_isp = (struct cam_isp_ctx_req *) req->req_priv; - if (req_isp->num_fence_map_out != 0) { + if (req_isp && req_isp->num_fence_map_out != 0) { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; CAM_DBG(CAM_REQ, @@ -1196,7 +1198,7 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; + struct cam_ctx_request *req = NULL; struct cam_isp_ctx_req *req_isp = NULL; struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; @@ -1885,7 +1887,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( list_del_init(&req->list); req_isp = (struct cam_isp_ctx_req *) req->req_priv; - if (req_isp->num_fence_map_out != 0) { + if (req_isp && req_isp->num_fence_map_out != 0) { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", @@ -1903,7 +1905,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( * state so change substate here. */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; - if (req_isp->num_fence_map_out != 1) + if (req_isp && req_isp->num_fence_map_out != 1) goto end; if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && @@ -2308,7 +2310,7 @@ static int __cam_isp_ctx_dump_in_top_state(struct cam_context *ctx, struct timeval cur_time; int rc = 0; uintptr_t cpu_addr; - size_t buf_len; + size_t buf_len = 0; struct cam_isp_context_dump_header *hdr; uint64_t *addr, *start; uint8_t *dst; @@ -2343,6 +2345,7 @@ static int __cam_isp_ctx_dump_in_top_state(struct cam_context *ctx, is_dump_only_event_record = true; } ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + memset(&cpu_addr, 0, sizeof(cpu_addr)); rc = cam_mem_get_cpu_buf(dump_info->buf_handle, &cpu_addr, &buf_len); if (!cpu_addr || !buf_len || rc) { @@ -2486,6 +2489,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_hw_stop_args stop_args; struct cam_isp_start_args start_isp; struct cam_hw_reset_args reset_args; + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { CAM_INFO(CAM_ISP, "ctx id:%d Last request id to flush is %lld", ctx->ctx_id, flush_req->req_id); @@ -3362,7 +3366,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", packet->header.request_id); - rc = -EINVAL; + rc = -EBADR; goto free_cpu_buf; } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 2b1c98df6420460c94a21952cf9e12da5c21cb5b..0e9c34e52976ba260fcc070ee0adcc701f1ad16e 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -4664,6 +4664,7 @@ static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args) int i; int rc = 0; + memset(&isp_hw_dump_args, 0, sizeof(isp_hw_dump_args)); rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &isp_hw_dump_args.cpu_addr, &isp_hw_dump_args.buf_len); diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 1a995646a9470b352049c2a65bc33004cc5e9193..0b5855a9c28f3fa00107929da826624cdbe40eaf 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,112 @@ static struct cam_jpeg_hw_mgr g_jpeg_hw_mgr; static int32_t cam_jpeg_hw_mgr_cb(uint32_t irq_status, int32_t result_size, void *data); static int cam_jpeg_mgr_process_cmd(void *priv, void *data); +static int cam_jpeg_insert_cdm_change_base( + struct cam_hw_config_args *config_args, + struct cam_jpeg_hw_ctx_data *ctx_data, + struct cam_jpeg_hw_mgr *hw_mgr); + +static int cam_jpeg_process_next_hw_update(void *priv, void *data) +{ + int rc; + int i = 0; + struct cam_jpeg_hw_mgr *hw_mgr = priv; + struct cam_hw_update_entry *cmd; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_hw_config_args *config_args = NULL; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + uint32_t cdm_cfg_to_insert = 0; + + if (!data || !priv) { + CAM_ERR(CAM_JPEG, "Invalid data"); + return -EINVAL; + } + + ctx_data = (struct cam_jpeg_hw_ctx_data *)data; + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + config_args = (struct cam_hw_config_args *)&p_cfg_req->hw_cfg_args; + + if (!hw_mgr->devices[dev_type][0]->hw_ops.reset) { + CAM_ERR(CAM_JPEG, "op reset null "); + rc = -EFAULT; + goto end_error; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.reset( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg hw reset failed %d", rc); + goto end_error; + } + + cdm_cmd = ctx_data->cdm_cmd; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + cdm_cmd->cmd_arrary_count = 0; + + /* insert cdm chage base cmd */ + rc = cam_jpeg_insert_cdm_change_base(config_args, + ctx_data, hw_mgr); + if (rc) { + CAM_ERR(CAM_JPEG, "insert change base failed %d", rc); + goto end_error; + } + + /* insert next cdm payload at index */ + /* for enc or dma 1st pass at index 1 */ + /* for dma 2nd pass at index 2, for 3rd at 4 */ + if (p_cfg_req->num_hw_entry_processed == 0) + cdm_cfg_to_insert = CAM_JPEG_CFG; + else + cdm_cfg_to_insert = p_cfg_req->num_hw_entry_processed + 2; + + CAM_DBG(CAM_JPEG, "processed %d total %d using cfg entry %d for %pK", + p_cfg_req->num_hw_entry_processed, + config_args->num_hw_update_entries, + cdm_cfg_to_insert, + p_cfg_req); + + cmd = (config_args->hw_update_entries + cdm_cfg_to_insert); + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].bl_addr.mem_handle = + cmd->handle; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].offset = + cmd->offset; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = + cmd->len; + CAM_DBG(CAM_JPEG, "i %d entry h %d o %d l %d", + i, cmd->handle, cmd->offset, cmd->len); + cdm_cmd->cmd_arrary_count++; + + rc = cam_cdm_submit_bls( + hw_mgr->cdm_info[dev_type][0].cdm_handle, + cdm_cmd); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to apply the configs %d", rc); + goto end_error; + } + + if (!hw_mgr->devices[dev_type][0]->hw_ops.start) { + CAM_ERR(CAM_JPEG, "op start null "); + rc = -EINVAL; + goto end_error; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.start( + hw_mgr->devices[dev_type][0]->hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to apply the configs %d", + rc); + goto end_error; + } + + return 0; +end_error: + return rc; +} static int cam_jpeg_mgr_process_irq(void *priv, void *data) { @@ -93,6 +199,21 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) return -EINVAL; } + p_cfg_req->num_hw_entry_processed++; + CAM_DBG(CAM_JPEG, "hw entry processed %d", + p_cfg_req->num_hw_entry_processed); + + if ((task_data->result_size > 0) && + (p_cfg_req->num_hw_entry_processed < + p_cfg_req->hw_cfg_args.num_hw_update_entries - 2)) { + /* start processing next entry before marking device free */ + rc = cam_jpeg_process_next_hw_update(priv, ctx_data); + if (!rc) { + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return 0; + } + } + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; irq_cb.data = NULL; irq_cb.b_set_cb = false; @@ -159,7 +280,9 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) if ((p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset / sizeof(uint32_t)) >= cmd_buf_len) { - CAM_ERR(CAM_JPEG, "Not enough buf"); + CAM_ERR(CAM_JPEG, "Invalid offset: %u cmd buf len: %zu", + p_cfg_req->hw_cfg_args.hw_update_entries[ + CAM_JPEG_PARAM].offset, cmd_buf_len); return -EINVAL; } @@ -288,7 +411,9 @@ static int cam_jpeg_insert_cdm_change_base( if (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset >= ch_base_len) { - CAM_ERR(CAM_JPEG, "Not enough buf"); + CAM_ERR(CAM_JPEG, "Not enough buf offset %d len %d", + config_args->hw_update_entries[CAM_JPEG_CHBASE].offset, + ch_base_len); return -EINVAL; } CAM_DBG(CAM_JPEG, "iova %pK len %zu offset %d", @@ -327,8 +452,6 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) int rc; int i = 0; struct cam_jpeg_hw_mgr *hw_mgr = priv; - struct cam_hw_update_entry *cmd; - struct cam_cdm_bl_request *cdm_cmd; struct cam_hw_config_args *config_args = NULL; struct cam_jpeg_hw_ctx_data *ctx_data = NULL; uintptr_t request_id = 0; @@ -430,68 +553,14 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) goto end_callcb; } - if (!hw_mgr->devices[dev_type][0]->hw_ops.reset) { - CAM_ERR(CAM_JPEG, "op reset null "); - rc = -EFAULT; - goto end_callcb; - } - rc = hw_mgr->devices[dev_type][0]->hw_ops.reset( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) { - CAM_ERR(CAM_JPEG, "jpeg hw reset failed %d", rc); - goto end_callcb; - } - - cdm_cmd = ctx_data->cdm_cmd; - cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; - cdm_cmd->flag = false; - cdm_cmd->userdata = NULL; - cdm_cmd->cookie = 0; - cdm_cmd->cmd_arrary_count = 0; - - rc = cam_jpeg_insert_cdm_change_base(config_args, - ctx_data, hw_mgr); + /* insert one of the cdm payloads */ + rc = cam_jpeg_process_next_hw_update(priv, ctx_data); if (rc) { - CAM_ERR(CAM_JPEG, "insert change base failed %d", rc); + CAM_ERR(CAM_JPEG, "next hw update failed %d", rc); goto end_callcb; } - CAM_DBG(CAM_JPEG, "num hw up %d", config_args->num_hw_update_entries); - for (i = CAM_JPEG_CFG; i < (config_args->num_hw_update_entries - 1); - i++) { - cmd = (config_args->hw_update_entries + i); - cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].bl_addr.mem_handle - = cmd->handle; - cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].offset = - cmd->offset; - cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = - cmd->len; - CAM_DBG(CAM_JPEG, "i %d entry h %d o %d l %d", - i, cmd->handle, cmd->offset, cmd->len); - cdm_cmd->cmd_arrary_count++; - } - - rc = cam_cdm_submit_bls( - hw_mgr->cdm_info[dev_type][0].cdm_handle, cdm_cmd); - if (rc) { - CAM_ERR(CAM_JPEG, "Failed to apply the configs %d", rc); - goto rel_cpu_buf; - } - if (!hw_mgr->devices[dev_type][0]->hw_ops.start) { - CAM_ERR(CAM_JPEG, "op start null "); - rc = -EINVAL; - goto rel_cpu_buf; - } - rc = hw_mgr->devices[dev_type][0]->hw_ops.start( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) { - CAM_ERR(CAM_JPEG, "Failed to start hw %d", - rc); - goto rel_cpu_buf; - } cam_common_util_get_curr_timestamp(&p_cfg_req->submit_timestamp); if (cam_mem_put_cpu_buf( config_args->hw_update_entries[CAM_JPEG_CHBASE].handle)) @@ -501,11 +570,6 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; -rel_cpu_buf: - if (cam_mem_put_cpu_buf( - config_args->hw_update_entries[CAM_JPEG_CHBASE].handle)) - CAM_WARN(CAM_JPEG, "unable to put info for cmd buf: 0x%x", - config_args->hw_update_entries[CAM_JPEG_CHBASE].handle); end_callcb: mutex_unlock(&hw_mgr->hw_mgr_mutex); if (p_cfg_req) { @@ -578,6 +642,7 @@ static int cam_jpeg_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) request_id = (uintptr_t)config_args->priv; p_cfg_req->req_id = request_id; + p_cfg_req->num_hw_entry_processed = 0; hw_update_entries = config_args->hw_update_entries; CAM_DBG(CAM_JPEG, "ctx_data = %pK req_id = %lld %zd", ctx_data, request_id, (uintptr_t)config_args->priv); @@ -797,6 +862,7 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); } + CAM_DBG(CAM_JPEG, "received num cmd buf %d", packet->num_cmd_buf); j = prepare_args->num_hw_update_entries; rc = cam_packet_util_get_kmd_buffer(packet, &kmd_buf); @@ -1103,6 +1169,7 @@ static int cam_jpeg_mgr_hw_dump(void *hw_mgr_priv, void *dump_hw_args) p_cfg_req->submit_timestamp.tv_usec, cur_time.tv_sec, cur_time.tv_usec); + memset(&jpeg_dump_args, 0, sizeof(jpeg_dump_args)); rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &jpeg_dump_args.cpu_addr, &jpeg_dump_args.buf_len); if (!jpeg_dump_args.cpu_addr || !jpeg_dump_args.buf_len || rc) { diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h index 2dc11dfa0746ba92a2f2f0c5e30bfed593736ffd..3f317524611f278b9679e58271ec3f7c5f4bc032 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -83,6 +83,7 @@ struct cam_jpeg_hw_cdm_info_t { * @dev_type: Dev type for cfg request * @req_id: Request Id * @submit_timestamp: Timestamp of submitting request + * @num_hw_entry_processed: Cdm payloads already processed */ struct cam_jpeg_hw_cfg_req { struct list_head list; @@ -90,6 +91,7 @@ struct cam_jpeg_hw_cfg_req { uint32_t dev_type; uintptr_t req_id; struct timeval submit_timestamp; + uint32_t num_hw_entry_processed; }; /** diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/cam_jpeg_dma_hw_info_ver_4_2_0.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/cam_jpeg_dma_hw_info_ver_4_2_0.h new file mode 100644 index 0000000000000000000000000000000000000000..ff8997bd46156d2321cc5133542cc6a99ed51b6e --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/cam_jpeg_dma_hw_info_ver_4_2_0.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef CAM_JPEG_DMA_HW_INFO_VER_4_2_0_H +#define CAM_JPEG_DMA_HW_INFO_VER_4_2_0_H + +#define CAM_JPEGDMA_HW_IRQ_STATUS_SESSION_DONE (1 << 0) +#define CAM_JPEGDMA_HW_IRQ_STATUS_RD_BUF_DONE (1 << 1) +#define CAM_JPEGDMA_HW_IRQ_STATUS_WR_BUF_DONE (1 << 5) +#define CAM_JPEGDMA_HW_IRQ_STATUS_AXI_HALT (1 << 9) +#define CAM_JPEGDMA_HW_IRQ_STATUS_RST_DONE (1 << 10) + +#define CAM_JPEGDMA_HW_MASK_COMP_FRAMEDONE \ + CAM_JPEGDMA_HW_IRQ_STATUS_SESSION_DONE +#define CAM_JPEGDMA_HW_MASK_COMP_RESET_ACK \ + CAM_JPEGDMA_HW_IRQ_STATUS_RST_DONE + +static struct cam_jpeg_dma_device_hw_info cam_jpeg_dma_hw_info = { + .reg_offset = { + .hw_version = 0x0, + .int_clr = 0x14, + .int_status = 0x10, + .int_mask = 0x0C, + .hw_cmd = 0x1C, + .reset_cmd = 0x08, + .encode_size = 0x180, + }, + .reg_val = { + .int_clr_clearall = 0xFFFFFFFF, + .int_mask_disable_all = 0x00000000, + .int_mask_enable_all = 0xFFFFFFFF, + .hw_cmd_start = 0x00000001, + .reset_cmd = 0x32083, + .hw_cmd_stop = 0x00000004, + }, + .int_status = { + .framedone = CAM_JPEGDMA_HW_MASK_COMP_FRAMEDONE, + .resetdone = CAM_JPEGDMA_HW_MASK_COMP_RESET_ACK, + .iserror = 0x0, + .stopdone = CAM_JPEGDMA_HW_IRQ_STATUS_AXI_HALT, + } +}; + +#endif /* CAM_JPEG_DMA_HW_INFO_VER_4_2_0_H */ diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c index 037a39e5eb125577fc098db34c29517d0546954e..169a027d95fffc6db7f5134abd4acbb47a8eb4a8 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,6 +31,15 @@ #include "cam_cpas_api.h" #include "cam_debug_util.h" +#define CAM_JPEG_HW_IRQ_IS_FRAME_DONE(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.framedone) +#define CAM_JPEG_HW_IRQ_IS_RESET_ACK(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.resetdone) +#define CAM_JPEG_HW_IRQ_IS_STOP_DONE(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.stopdone) + +#define CAM_JPEG_DMA_RESET_TIMEOUT msecs_to_jiffies(500) + int cam_jpeg_dma_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { @@ -131,7 +140,7 @@ int cam_jpeg_dma_deinit_hw(void *device_priv, rc = cam_jpeg_dma_disable_soc_resources(soc_info); if (rc) - CAM_ERR(CAM_JPEG, "soc enable failed %d", rc); + CAM_ERR(CAM_JPEG, "soc disable failed %d", rc); rc = cam_cpas_stop(core_info->cpas_handle); if (rc) @@ -142,6 +151,226 @@ int cam_jpeg_dma_deinit_hw(void *device_priv, return 0; } +irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data) +{ + struct cam_hw_info *jpeg_dma_dev = data; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + uint32_t irq_status = 0; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + + if (!jpeg_dma_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return IRQ_HANDLED; + } + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + hw_info = core_info->jpeg_dma_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + irq_status = cam_io_r_mb(mem_base + + core_info->jpeg_dma_hw_info->reg_offset.int_status); + cam_io_w_mb(irq_status, + soc_info->reg_map[0].mem_base + + core_info->jpeg_dma_hw_info->reg_offset.int_clr); + CAM_DBG(CAM_JPEG, "irq_num %d irq_status = %x , core_state %d", + irq_num, irq_status, core_info->core_state); + if (CAM_JPEG_HW_IRQ_IS_FRAME_DONE(irq_status, hw_info)) { + spin_lock(&jpeg_dma_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_DMA_CORE_READY) { + core_info->result_size = 1; + CAM_DBG(CAM_JPEG, "result_size %d", + core_info->result_size); + core_info->core_state = + CAM_JPEG_DMA_CORE_RESETTING_ON_DONE; + cam_io_w_mb(hw_info->reg_val.reset_cmd, + mem_base + hw_info->reg_offset.reset_cmd); + } else { + CAM_WARN(CAM_JPEG, "unexpected frame done "); + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + } + spin_unlock(&jpeg_dma_dev->hw_lock); + } + + if (CAM_JPEG_HW_IRQ_IS_RESET_ACK(irq_status, hw_info)) { + spin_lock(&jpeg_dma_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_DMA_CORE_RESETTING) { + core_info->core_state = CAM_JPEG_DMA_CORE_READY; + core_info->result_size = -1; + complete(&jpeg_dma_dev->hw_complete); + } else if (core_info->core_state == + CAM_JPEG_DMA_CORE_RESETTING_ON_DONE) { + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + core_info->result_size, + core_info->irq_cb.data); + } else { + CAM_WARN(CAM_JPEG, "unexpected frame done"); + } + core_info->result_size = -1; + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + } else { + CAM_ERR(CAM_JPEG, "unexpected reset irq"); + } + spin_unlock(&jpeg_dma_dev->hw_lock); + } + if (CAM_JPEG_HW_IRQ_IS_STOP_DONE(irq_status, hw_info)) { + spin_lock(&jpeg_dma_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_DMA_CORE_ABORTING) { + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + complete(&jpeg_dma_dev->hw_complete); + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + -1, + core_info->irq_cb.data); + } + } else { + CAM_ERR(CAM_JPEG, "unexpected abort irq"); + } + spin_unlock(&jpeg_dma_dev->hw_lock); + } + + return IRQ_HANDLED; +} + +int cam_jpeg_dma_reset_hw(void *data, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = data; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + unsigned long rem_jiffies; + + if (!jpeg_dma_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + /* maskdisable.clrirq.maskenable.resetcmd */ + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + hw_info = core_info->jpeg_dma_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_dma_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_DMA_CORE_RESETTING) { + CAM_ERR(CAM_JPEG, "dma alrady resetting"); + spin_unlock(&jpeg_dma_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return 0; + } + + reinit_completion(&jpeg_dma_dev->hw_complete); + + core_info->core_state = CAM_JPEG_DMA_CORE_RESETTING; + spin_unlock(&jpeg_dma_dev->hw_lock); + + cam_io_w_mb(hw_info->reg_val.int_mask_disable_all, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.int_clr_clearall, + mem_base + hw_info->reg_offset.int_clr); + cam_io_w_mb(hw_info->reg_val.int_mask_enable_all, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.reset_cmd, + mem_base + hw_info->reg_offset.reset_cmd); + + rem_jiffies = wait_for_completion_timeout(&jpeg_dma_dev->hw_complete, + CAM_JPEG_DMA_RESET_TIMEOUT); + if (!rem_jiffies) { + CAM_ERR(CAM_JPEG, "dma error Reset Timeout"); + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + } + + mutex_unlock(&core_info->core_mutex); + return 0; +} + +int cam_jpeg_dma_start_hw(void *data, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = data; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + + if (!jpeg_dma_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + hw_info = core_info->jpeg_dma_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + if (core_info->core_state != CAM_JPEG_DMA_CORE_READY) { + CAM_ERR(CAM_JPEG, "Error not ready"); + return -EINVAL; + } + + CAM_DBG(CAM_JPEG, "Starting DMA"); + cam_io_w_mb(0x00000601, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.hw_cmd_start, + mem_base + hw_info->reg_offset.hw_cmd); + + return 0; +} + +int cam_jpeg_dma_stop_hw(void *data, + void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = data; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + unsigned long rem_jiffies; + + if (!jpeg_dma_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + hw_info = core_info->jpeg_dma_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_dma_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_DMA_CORE_ABORTING) { + CAM_ERR(CAM_JPEG, "alrady stopping"); + spin_unlock(&jpeg_dma_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return 0; + } + + reinit_completion(&jpeg_dma_dev->hw_complete); + core_info->core_state = CAM_JPEG_DMA_CORE_ABORTING; + spin_unlock(&jpeg_dma_dev->hw_lock); + + cam_io_w_mb(hw_info->reg_val.hw_cmd_stop, + mem_base + hw_info->reg_offset.hw_cmd); + + rem_jiffies = wait_for_completion_timeout(&jpeg_dma_dev->hw_complete, + CAM_JPEG_DMA_RESET_TIMEOUT); + if (!rem_jiffies) { + CAM_ERR(CAM_JPEG, "error Reset Timeout"); + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + } + + mutex_unlock(&core_info->core_mutex); + return 0; +} + int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -186,12 +415,7 @@ int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, rc = -EINVAL; break; } - + if (rc) + CAM_ERR(CAM_JPEG, "error cmdtype %d rc = %d", cmd_type, rc); return rc; } - -irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data) -{ - return IRQ_HANDLED; -} - diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h index 8f5fd58698d22ed2c2fac03eb80b0840e0468508..737c2f217feb6549b025720cb9e74406e729731c 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,14 +21,44 @@ #include "cam_jpeg_hw_intf.h" +struct cam_jpeg_dma_reg_offsets { + uint32_t hw_version; + uint32_t int_status; + uint32_t int_clr; + uint32_t int_mask; + uint32_t hw_cmd; + uint32_t reset_cmd; + uint32_t encode_size; +}; + +struct cam_jpeg_dma_regval { + uint32_t int_clr_clearall; + uint32_t int_mask_disable_all; + uint32_t int_mask_enable_all; + uint32_t hw_cmd_start; + uint32_t reset_cmd; + uint32_t hw_cmd_stop; +}; + +struct cam_jpeg_dma_int_status { + uint32_t framedone; + uint32_t resetdone; + uint32_t iserror; + uint32_t stopdone; +}; + struct cam_jpeg_dma_device_hw_info { - uint32_t reserved; + struct cam_jpeg_dma_reg_offsets reg_offset; + struct cam_jpeg_dma_regval reg_val; + struct cam_jpeg_dma_int_status int_status; }; enum cam_jpeg_dma_core_state { CAM_JPEG_DMA_CORE_NOT_READY, CAM_JPEG_DMA_CORE_READY, CAM_JPEG_DMA_CORE_RESETTING, + CAM_JPEG_DMA_CORE_ABORTING, + CAM_JPEG_DMA_CORE_RESETTING_ON_DONE, CAM_JPEG_DMA_CORE_STATE_MAX, }; @@ -39,12 +69,19 @@ struct cam_jpeg_dma_device_core_info { struct cam_jpeg_set_irq_cb irq_cb; int32_t ref_count; struct mutex core_mutex; + int32_t result_size; }; int cam_jpeg_dma_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size); int cam_jpeg_dma_deinit_hw(void *device_priv, void *init_hw_args, uint32_t arg_size); +int cam_jpeg_dma_start_hw(void *device_priv, + void *start_hw_args, uint32_t arg_size); +int cam_jpeg_dma_stop_hw(void *device_priv, + void *stop_hw_args, uint32_t arg_size); +int cam_jpeg_dma_reset_hw(void *device_priv, + void *reset_hw_args, uint32_t arg_size); int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size); irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data); diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c index fd4fdab19fa73552892e249c89e52c0a37534583..f91eee86335274fd9daf1e348de79730013d2b8a 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,11 +25,7 @@ #include "cam_jpeg_hw_mgr_intf.h" #include "cam_cpas_api.h" #include "cam_debug_util.h" - -static struct cam_jpeg_dma_device_hw_info cam_jpeg_dma_hw_info = { - .reserved = 0, -}; -EXPORT_SYMBOL(cam_jpeg_dma_hw_info); +#include "cam_jpeg_dma_hw_info_ver_4_2_0.h" static int cam_jpeg_dma_register_cpas(struct cam_hw_soc_info *soc_info, struct cam_jpeg_dma_device_core_info *core_info, @@ -142,6 +138,9 @@ static int cam_jpeg_dma_probe(struct platform_device *pdev) jpeg_dma_dev_intf->hw_priv = jpeg_dma_dev; jpeg_dma_dev_intf->hw_ops.init = cam_jpeg_dma_init_hw; jpeg_dma_dev_intf->hw_ops.deinit = cam_jpeg_dma_deinit_hw; + jpeg_dma_dev_intf->hw_ops.start = cam_jpeg_dma_start_hw; + jpeg_dma_dev_intf->hw_ops.stop = cam_jpeg_dma_stop_hw; + jpeg_dma_dev_intf->hw_ops.reset = cam_jpeg_dma_reset_hw; jpeg_dma_dev_intf->hw_ops.process_cmd = cam_jpeg_dma_process_cmd; jpeg_dma_dev_intf->hw_type = CAM_JPEG_DEV_DMA; @@ -186,13 +185,11 @@ static int cam_jpeg_dma_probe(struct platform_device *pdev) mutex_init(&jpeg_dma_dev->hw_mutex); spin_lock_init(&jpeg_dma_dev->hw_lock); init_completion(&jpeg_dma_dev->hw_complete); - - CAM_DBG(CAM_JPEG, " hwidx %d", jpeg_dma_dev_intf->hw_idx); - + CAM_DBG(CAM_JPEG, "JPEG-DMA component bound successfully"); return rc; error_reg_cpas: - rc = cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info); + cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info); error_init_soc: mutex_destroy(&core_info->core_mutex); error_match_dev: diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 54dd62c44f67c907b9a38eef8cdf9c4d5c821ae6..196742d064485aa8348ee74cf212d28e3b9376b8 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -350,7 +350,7 @@ int cam_jpeg_enc_start_hw(void *data, return -EINVAL; } spin_unlock(&jpeg_enc_dev->hw_lock); - + CAM_DBG(CAM_JPEG, "Starting JPEG ENC"); cam_io_w_mb(hw_info->reg_val.hw_cmd_start, mem_base + hw_info->reg_offset.hw_cmd); diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c index d4daa6dde308957bfb2561ae340211a9f942bd3c..be703d6c3055dde7e4d32794dc2809e048bcf31d 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -185,7 +185,7 @@ static int cam_jpeg_enc_probe(struct platform_device *pdev) mutex_init(&jpeg_enc_dev->hw_mutex); spin_lock_init(&jpeg_enc_dev->hw_lock); init_completion(&jpeg_enc_dev->hw_complete); - + CAM_DBG(CAM_JPEG, "JPEG-Encoder component bound successfully"); return rc; error_reg_cpas: diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index f6fa30c7c646416127ee2015fbadfa15b844f46b..cb03a57acd36ea2f8e1777ee22cb22bc2ad81494 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -695,6 +695,7 @@ static int cam_lrme_mgr_hw_dump(void *hw_mgr_priv, void *hw_dump_args) CAM_ERR(CAM_LRME, "Failed to get hw device"); return rc; } + memset(&lrme_dump_args, 0, sizeof(lrme_dump_args)); rc = cam_mem_get_cpu_buf(dump_args->buf_handle, &lrme_dump_args.cpu_addr, &lrme_dump_args.buf_len); diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index ec4297822fb7c857f0e2cb365648f8abf88eab0e..4de0f639a670b9d8ce5418b64f44212071545a65 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -273,13 +273,15 @@ static int cam_lrme_hw_dev_remove(struct platform_device *pdev) kfree(lrme_core); deinit_platform_res: - rc = cam_lrme_soc_deinit_resources(&lrme_hw->soc_info); - if (rc) - CAM_ERR(CAM_LRME, "Error in LRME soc deinit, rc=%d", rc); - - mutex_destroy(&lrme_hw->hw_mutex); - kfree(lrme_hw); + if (lrme_hw) { + rc = cam_lrme_soc_deinit_resources(&lrme_hw->soc_info); + if (rc) + CAM_ERR(CAM_LRME, + "Error in LRME soc deinit, rc=%d", rc); + mutex_destroy(&lrme_hw->hw_mutex); + kfree(lrme_hw); + } return rc; } diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index dfbc9b07e4a483ede4f1ec3205874d0ef278391a..2969baaaceebc6ea9cdc36862c2c808196d49d09 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -696,13 +696,19 @@ static int32_t __cam_req_mgr_find_slot_for_req( */ static int __cam_req_mgr_check_sync_for_mslave( struct cam_req_mgr_core_link *link, - struct cam_req_mgr_slot *slot) + struct cam_req_mgr_slot *slot, + uint64_t request_id) { struct cam_req_mgr_core_link *sync_link = NULL; struct cam_req_mgr_slot *sync_slot = NULL; + struct cam_req_mgr_slot *sync_rd_slot = NULL; int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; int64_t req_id = 0, sync_req_id = 0; int32_t sync_num_slots = 0; + uint64_t sync_frame_duration = 0; + int32_t sync_req_status = 0; + uint64_t sof_timestamp_delta = 0; + int sync_link_idx = 0; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -713,6 +719,12 @@ static int __cam_req_mgr_check_sync_for_mslave( req_id = slot->req_id; sync_num_slots = sync_link->req.in_q->num_slots; sync_rd_idx = sync_link->req.in_q->rd_idx; + sync_rd_slot = &sync_link->req.in_q->slot[sync_rd_idx]; + + sof_timestamp_delta = + link->sof_timestamp >= sync_link->sof_timestamp + ? link->sof_timestamp - sync_link->sof_timestamp + : sync_link->sof_timestamp - link->sof_timestamp; CAM_DBG(CAM_CRM, "link_hdl %x req %lld frame_skip_flag %d open_req_cnt:%d initial_sync_req [%lld,%lld] is_master:%d", @@ -742,6 +754,10 @@ static int __cam_req_mgr_check_sync_for_mslave( return -EINVAL; } + if (sync_link->prev_sof_timestamp) + sync_frame_duration = sync_link->sof_timestamp - + sync_link->prev_sof_timestamp; + if (link->is_master) { rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); if (rc) { @@ -763,7 +779,6 @@ static int __cam_req_mgr_check_sync_for_mslave( CAM_DBG(CAM_CRM, "Req: %lld [master] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; return rc; } @@ -830,10 +845,34 @@ static int __cam_req_mgr_check_sync_for_mslave( CAM_DBG(CAM_CRM, "Req: %lld [slave] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; return rc; } + sync_link_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, request_id); + if (sync_link_idx != -1) { + sync_req_status = + sync_link->req.in_q->slot[sync_link_idx].status; + if (sync_req_status != CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_DBG(CAM_CRM, + "Skipping initial sync req %lld id %d as master not applied", + request_id, sync_link_idx); + return -EINVAL; + } + } else + sync_req_status = 0; + + if ((sync_link->initial_sync_req == req_id) && + (sync_req_status == CRM_SLOT_STATUS_REQ_APPLIED) && + (sof_timestamp_delta < (sync_frame_duration / 2)) && + (((sync_link_idx - sync_rd_idx + sync_num_slots) % + sync_num_slots) <= 1) && + (sync_rd_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, "Skipping initial sync req for slave"); + return -EINVAL; + } + next_idx = link->req.in_q->rd_idx; rd_idx = sync_link->req.in_q->rd_idx; __cam_req_mgr_inc_idx(&next_idx, @@ -1215,7 +1254,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, } rc = __cam_req_mgr_check_sync_for_mslave( - link, slot); + link, slot, trigger_data->req_id); } else { rc = __cam_req_mgr_check_sync_req_is_ready( link, slot); @@ -2218,6 +2257,42 @@ int cam_req_mgr_process_error(void *priv, void *data) return rc; } +static void cam_req_mgr_process_reset_for_dual_link( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_trigger_notify *trigger_data) +{ + int32_t idx = -1; + int32_t sync_idx = -1; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_req_queue *sync_in_q = NULL; + + in_q = link->req.in_q; + sync_in_q = link->sync_link->req.in_q; + + sync_idx = __cam_req_mgr_find_slot_for_req(sync_in_q, + trigger_data->req_id); + if (link->is_master) + __cam_req_mgr_dec_idx(&sync_idx, + (link->max_delay - link->sync_link->max_delay), + sync_in_q->num_slots); + else + __cam_req_mgr_inc_idx(&sync_idx, + (link->sync_link->max_delay - link->max_delay), + sync_in_q->num_slots); + if (sync_idx != -1 && + (sync_in_q->slot[sync_in_q->rd_idx].status == + CRM_SLOT_STATUS_REQ_APPLIED)) { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + CAM_DBG(CAM_CRM, "Reset req: %lld idx: %d link_hdl: %x", + trigger_data->req_id, idx, + link->link_hdl); + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } +} + /** * cam_req_mgr_process_trigger() * @@ -2256,12 +2331,18 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) mutex_lock(&link->req.lock); if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) { - idx = __cam_req_mgr_find_slot_for_req(in_q, - trigger_data->req_id); - if (idx >= 0) { - if (idx == in_q->last_applied_idx) - in_q->last_applied_idx = -1; - __cam_req_mgr_reset_req_slot(link, idx); + if (link->sync_link && + (link->is_master || link->sync_link->is_master)) { + cam_req_mgr_process_reset_for_dual_link(link, + trigger_data); + } else { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + if (idx >= 0) { + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } } } @@ -2295,6 +2376,8 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) CAM_DBG(CAM_REQ, "No pending req to apply to lower pd devices"); rc = 0; + __cam_req_mgr_inc_idx(&in_q->rd_idx, + 1, in_q->num_slots); goto release_lock; } __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); @@ -3183,7 +3266,7 @@ int cam_req_mgr_schedule_request( CAM_INFO(CAM_CRM, "request %lld is flushed, last_flush_id to flush %u", sched_req->req_id, link->last_flush_id); - rc = -EINVAL; + rc = -EBADR; goto end; } @@ -3422,6 +3505,8 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) struct cam_req_mgr_connected_device *dev = NULL; struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; if (!control) { CAM_ERR(CAM_CRM, "Control command is NULL"); @@ -3485,6 +3570,18 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) if (dev->ops && dev->ops->process_evt) dev->ops->process_evt(&evt_data); } + in_q = link->req.in_q; + /* reset all slots */ + for (j = 0; j < in_q->num_slots; j++) { + slot = &in_q->slot[j]; + slot->req_id = -1; + slot->sync_mode = + CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->skip_idx = 1; + slot->status = CRM_SLOT_STATUS_NO_REQ; + } + in_q->wr_idx = 0; + in_q->rd_idx = 0; } else { CAM_ERR(CAM_CRM, "Invalid link control command"); rc = -EINVAL; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index 69b5af0026100e20b4d2648e747597da4da9e7c7..9f8ee883355aeb20b96ef4decb1028672262c7d4 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -404,7 +404,7 @@ static int cam_cci_platform_probe(struct platform_device *pdev) new_cci_dev->v4l2_dev_str.name = new_cci_dev->device_name; new_cci_dev->v4l2_dev_str.sd_flags = - (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + V4L2_SUBDEV_FL_HAS_EVENTS; new_cci_dev->v4l2_dev_str.ent_function = CAM_CCI_DEVICE_TYPE; new_cci_dev->v4l2_dev_str.token = diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index 2e4c032cb3227ca43fa079d49fa8d7ceb90abfc2..fd93dedd01f1e4834d63bf6cf434cf78f5b1d937 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -317,6 +317,6 @@ static inline struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) #endif #define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) #endif /* _CAM_CCI_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h index 51ffc1872af489a31e7c781005fa42fe700b3879..0aa91d58767acd5c1a8a0450ba2c316fc7343df0 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -19,10 +19,10 @@ struct csiphy_reg_parms_t csiphy_v1_2_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 7, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 22, - .csiphy_3ph_config_array_size = 38, + .csiphy_2ph_config_array_size = 23, + .csiphy_3ph_config_array_size = 30, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -30,8 +30,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_2 = { struct csiphy_reg_t csiphy_common_reg_1_2_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, - {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, @@ -65,34 +64,34 @@ csiphy_reg_t csiphy_2ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -108,78 +107,83 @@ csiphy_reg_t csiphy_2ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -189,34 +193,34 @@ struct csiphy_reg_t {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -231,40 +235,42 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x075C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -276,19 +282,20 @@ struct csiphy_reg_t {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -296,14 +303,16 @@ struct csiphy_reg_t {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -311,9 +320,6 @@ struct csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -339,25 +345,17 @@ csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -379,21 +377,13 @@ csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -419,12 +409,7 @@ csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -437,7 +422,7 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 8, + .data_rate_reg_array_size = 6, .csiphy_data_rate_regs = { {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -445,14 +430,12 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { {0x984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 8, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -460,14 +443,18 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 8, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -475,8 +462,13 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, } } diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c index 593bed9b137d41071c928c699bf9a836975ac741..bb950a7bade7d9427749b92a47c2882743c05e70 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -177,7 +177,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet, uint32_t temp; uint32_t *dst_cpu_addr; uint32_t *src_buf_iova_addr; - size_t dst_buf_len; + size_t dst_buf_len = 0; size_t src_buf_size; int i; int rc = 0; diff --git a/drivers/media/platform/msm/npu_v2/npu_common.h b/drivers/media/platform/msm/npu_v2/npu_common.h index e9e3e1f2c079ebef783e360731f69b5a1e645040..0929edd48bd34fbf531bce81ef66483e2b545128 100644 --- a/drivers/media/platform/msm/npu_v2/npu_common.h +++ b/drivers/media/platform/msm/npu_v2/npu_common.h @@ -294,6 +294,7 @@ struct npu_device { struct llcc_slice_desc *sys_cache; uint32_t execute_v2_flag; bool cxlimit_registered; + bool npu_dsp_sid_mapped; uint32_t hw_version; }; diff --git a/drivers/media/platform/msm/npu_v2/npu_dev.c b/drivers/media/platform/msm/npu_v2/npu_dev.c index f872192825b8f47773b3911d7098130a84d338f5..39544b5df9411d2baab50d9e0b29bfd6e600a3e8 100644 --- a/drivers/media/platform/msm/npu_v2/npu_dev.c +++ b/drivers/media/platform/msm/npu_v2/npu_dev.c @@ -1464,6 +1464,8 @@ static int npu_get_property(struct npu_client *client, case MSM_NPU_PROP_ID_DRV_FEATURE: prop.prop_param[0] = MSM_NPU_FEATURE_MULTI_EXECUTE | MSM_NPU_FEATURE_ASYNC_EXECUTE; + if (npu_dev->npu_dsp_sid_mapped) + prop.prop_param[0] |= MSM_NPU_FEATURE_DSP_SID_MAPPED; break; default: ret = npu_host_get_fw_property(client->npu_dev, &prop); @@ -1741,7 +1743,7 @@ int npu_set_bw(struct npu_device *npu_dev, int new_ib, int new_ab) static int npu_adjust_max_power_level(struct npu_device *npu_dev) { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; - uint32_t fmax_reg_value, fmax, fmax_pwrlvl; + uint32_t fmax_reg_value, fmax, fmax_pwrlvl = pwr->max_pwrlevel; struct npu_pwrlevel *level; int i, j; @@ -2234,6 +2236,10 @@ static int npu_hw_info_init(struct npu_device *npu_dev) NPU_DBG("NPU_HW_VERSION 0x%x\n", npu_dev->hw_version); npu_disable_core_power(npu_dev); + npu_dev->npu_dsp_sid_mapped = + of_property_read_bool(npu_dev->pdev->dev.of_node, + "qcom,npu-dsp-sid-mapped"); + return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 740df57d2ead4ace6a2dd9c3671f3a43b6153193..dbcc9434185db9a4913b6d014bd15f138d596120 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -521,6 +521,15 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) return -EINVAL; } + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for type = %d\n", b->type); + return -EINVAL; + } + mutex_lock(&q->lock); + + for (i = 0; i < b->length; i++) { b->m.planes[i].m.fd = b->m.planes[i].reserved[0]; b->m.planes[i].data_offset = b->m.planes[i].reserved[1]; @@ -545,19 +554,11 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) tag_data.output_tag = b->m.planes[0].reserved[6]; msm_comm_store_tags(inst, &tag_data); - q = msm_comm_get_vb2q(inst, b->type); - if (!q) { - dprintk(VIDC_ERR, - "Failed to find buffer queue for type = %d\n", b->type); - return -EINVAL; - } - - mutex_lock(&q->lock); rc = vb2_qbuf(&q->vb2_bufq, b); - mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc); + mutex_unlock(&q->lock); return rc; } EXPORT_SYMBOL(msm_vidc_qbuf); @@ -1879,7 +1880,6 @@ void *msm_vidc_open(int core_id, int session_type) mutex_init(&inst->bufq[CAPTURE_PORT].lock); mutex_init(&inst->bufq[OUTPUT_PORT].lock); mutex_init(&inst->lock); - mutex_init(&inst->flush_lock); INIT_MSM_VIDC_LIST(&inst->scratchbufs); INIT_MSM_VIDC_LIST(&inst->freqs); @@ -2003,7 +2003,6 @@ void *msm_vidc_open(int core_id, int session_type) mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); mutex_destroy(&inst->lock); - mutex_destroy(&inst->flush_lock); DEINIT_MSM_VIDC_LIST(&inst->scratchbufs); DEINIT_MSM_VIDC_LIST(&inst->persistbufs); @@ -2157,7 +2156,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst) mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); mutex_destroy(&inst->lock); - mutex_destroy(&inst->flush_lock); msm_vidc_debugfs_deinit_inst(inst); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index bf6141b6870d781a07fa8f1c806a0dcc23ac9f6b..4d370c6fe25d5e903786ae0005b9194489adc6fc 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -1206,7 +1206,7 @@ int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, * batch size count of extra buffers added on output port */ if (is_output_buffer(inst, buffer_type)) { - if (inst->decode_batching && is_decode_session(inst) && + if (is_batching_allowed(inst) && count < inst->batch.size) count = inst->batch.size; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index ff824d7fad035e942fe83682e8c690541c6670d3..516af3055a734e28ce1a0b4d709a5dfea8fbca5a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2079,7 +2079,11 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) return; } - mutex_lock(&inst->flush_lock); + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); + if (msm_comm_get_stream_output_mode(inst) == HAL_VIDEO_DECODER_SECONDARY) { @@ -2122,7 +2126,11 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) v4l2_event_queue_fh(&inst->event_handler, &flush_event); exit: - mutex_unlock(&inst->flush_lock); + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + put_inst(inst); } @@ -2331,7 +2339,7 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( return NULL; } - mutex_lock(&inst->bufq[port].lock); + WARN_ON(!mutex_is_locked(&inst->bufq[port].lock)); found = false; q = &inst->bufq[port].vb2_bufq; if (!q->streaming) { @@ -2347,7 +2355,6 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( } } unlock: - mutex_unlock(&inst->bufq[port].lock); if (!found) { print_vidc_buffer(VIDC_ERR, "vb2 not found for", inst, mbuf); return NULL; @@ -2362,6 +2369,7 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, struct vb2_buffer *vb2; struct vb2_v4l2_buffer *vbuf; u32 i, port; + int rc = 0; if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", @@ -2378,16 +2386,20 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, else return -EINVAL; - vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); - if (!vb2) - return -EINVAL; - /* * access vb2 buffer under q->lock and if streaming only to * ensure the buffer was not free'd by vb2 framework while * we are accessing it here. */ mutex_lock(&inst->bufq[port].lock); + vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); + if (!vb2) { + rc = -EINVAL; + dprintk(VIDC_ERR, "%s:port %d buffer not found\n", + __func__, port); + goto unlock; + } + if (inst->bufq[port].vb2_bufq.streaming) { vbuf = to_vb2_v4l2_buffer(vb2); vbuf->flags = mbuf->vvb.flags; @@ -2403,9 +2415,9 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: port %d is not streaming\n", __func__, port); } +unlock: mutex_unlock(&inst->bufq[port].lock); - - return 0; + return rc; } bool heic_encode_session_supported(struct msm_vidc_inst *inst) @@ -3196,7 +3208,7 @@ static int msm_comm_init_buffer_count(struct msm_vidc_inst *inst) HAL_BUFFER_INPUT); bufreq->buffer_count_min = inst->fmts[port].input_min_count; /* batching needs minimum batch size count of input buffers */ - if (inst->decode_batching && is_decode_session(inst) && + if (is_batching_allowed(inst) && bufreq->buffer_count_min < inst->batch.size) bufreq->buffer_count_min = inst->batch.size; bufreq->buffer_count_min_host = bufreq->buffer_count_actual = @@ -5316,7 +5328,11 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) return 0; } - mutex_lock(&inst->flush_lock); + if (ip_flush) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (op_flush) + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); + /* enable in flush */ inst->in_flush = true; @@ -5370,7 +5386,12 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) rc = call_hfi_op(hdev, session_flush, inst->session, HAL_FLUSH_OUTPUT); } - mutex_unlock(&inst->flush_lock); + + if (op_flush) + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); + if (ip_flush) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + if (rc) { dprintk(VIDC_ERR, "Sending flush to firmware failed, flush out all buffers\n"); @@ -6453,7 +6474,6 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, else return -EINVAL; - mutex_lock(&inst->bufq[port].lock); if (inst->bufq[port].vb2_bufq.streaming) { vb->planes[0].bytesused = 0; vb2_buffer_done(vb, VB2_BUF_STATE_DONE); @@ -6461,7 +6481,6 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: port %d is not streaming\n", __func__, port); } - mutex_unlock(&inst->bufq[port].lock); return 0; } @@ -6815,7 +6834,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, int i = 0; u32 planes[VIDEO_MAX_PLANES] = {0}; - mutex_lock(&inst->flush_lock); + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); mutex_lock(&inst->registeredbufs.lock); found = false; /* check if mbuf was not removed by any chance */ @@ -6904,7 +6923,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, print_vidc_buffer(VIDC_ERR, "rbr qbuf failed", inst, mbuf); } - mutex_unlock(&inst->flush_lock); + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); } int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 21453f6a6c8a92efedd4a2663f9eb74c67dc9aaa..b89bb08b3ae594df9194b0648ca006404e0f9c7e 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -442,7 +442,7 @@ struct msm_vidc_core { struct msm_vidc_inst { struct list_head list; - struct mutex sync_lock, lock, flush_lock; + struct mutex sync_lock, lock; struct msm_vidc_core *core; enum session_type session_type; void *session; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 8950bcf80677bacdfe4b537e85a7ddc5e2061c13..798f57ba8bc2525ce704ad9e6bc942b3b5dea3a2 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -995,10 +995,9 @@ struct hal_fw_info { }; enum hal_flush { - HAL_FLUSH_INPUT, - HAL_FLUSH_OUTPUT, - HAL_FLUSH_ALL, - HAL_UNUSED_FLUSH = 0x10000000, + HAL_FLUSH_INPUT = BIT(0), + HAL_FLUSH_OUTPUT = BIT(1), + HAL_FLUSH_ALL = HAL_FLUSH_INPUT | HAL_FLUSH_OUTPUT, }; enum hal_event_type { diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c index b7892f3efd988a45da8ebc18b9a2bd9222ed8157..5c4c3f0c57be1c45ea2f258abf2db4602a9bdb8f 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-hw.c +++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c @@ -14,8 +14,8 @@ #define MAX_SRC_WIDTH 2048 /* Reset & boot poll config */ -#define POLL_RST_MAX 50 -#define POLL_RST_DELAY_MS 20 +#define POLL_RST_MAX 500 +#define POLL_RST_DELAY_MS 2 enum bdisp_target_plan { BDISP_RGB, @@ -382,7 +382,7 @@ int bdisp_hw_reset(struct bdisp_dev *bdisp) for (i = 0; i < POLL_RST_MAX; i++) { if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE) break; - msleep(POLL_RST_DELAY_MS); + udelay(POLL_RST_DELAY_MS * 1000); } if (i == POLL_RST_MAX) dev_err(bdisp->dev, "Reset timeout\n"); diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 42e383a48ffe896f4539684a15b7eacd853d4bc5..b6dcae1ecc1be1f60db30af7c7a07dbe6ed4b522 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -544,16 +544,16 @@ static void enable_irqs(struct cal_ctx *ctx) static void disable_irqs(struct cal_ctx *ctx) { + u32 val; + /* Disable IRQ_WDMA_END 0/1 */ - reg_write_field(ctx->dev, - CAL_HL_IRQENABLE_CLR(2), - CAL_HL_IRQ_CLEAR, - CAL_HL_IRQ_MASK(ctx->csi2_port)); + val = 0; + set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port)); + reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(2), val); /* Disable IRQ_WDMA_START 0/1 */ - reg_write_field(ctx->dev, - CAL_HL_IRQENABLE_CLR(3), - CAL_HL_IRQ_CLEAR, - CAL_HL_IRQ_MASK(ctx->csi2_port)); + val = 0; + set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port)); + reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(3), val); /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */ reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0); } diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 3c2e248ceca87ee4d97da97fd1576ab89457137f..03dbbfba71fc6951ad1ecb3ef779de0a880fee02 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -427,7 +427,7 @@ static int iguanair_probe(struct usb_interface *intf, int ret, pipein, pipeout; struct usb_host_interface *idesc; - idesc = intf->altsetting; + idesc = intf->cur_altsetting; if (idesc->desc.bNumEndpoints < 2) return -ENODEV; diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 427cda457af68e49e09cfaff4a927ddc80ab5292..5104678f29b76a14e96bfae1cf4bbf18141cb7c3 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -510,6 +510,9 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb) return ret; } + if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1) + return -ENODEV; + switch (fc_usb->udev->speed) { case USB_SPEED_LOW: err("cannot handle USB speed because it is too slow."); @@ -543,9 +546,6 @@ static int flexcop_usb_probe(struct usb_interface *intf, struct flexcop_device *fc = NULL; int ret; - if (intf->cur_altsetting->desc.bNumEndpoints < 1) - return -ENODEV; - if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { err("out of memory\n"); return -ENOMEM; diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index 1ee7ec55829388e56df80680c7c04938fc0a4459..33dd54c8fa0410f3f0165efe87db72489aa516ba 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -821,7 +821,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ - if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1) + if (intf->cur_altsetting->desc.bNumEndpoints < rc_ep + 1) return -ENODEV; purb = usb_alloc_urb(0, GFP_KERNEL); @@ -841,7 +841,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) * Some devices like the Hauppauge NovaTD model 52009 use an interrupt * endpoint, while others use a bulk one. */ - e = &intf->altsetting[0].endpoint[rc_ep].desc; + e = &intf->cur_altsetting->endpoint[rc_ep].desc; if (usb_endpoint_dir_in(e)) { if (usb_endpoint_xfer_bulk(e)) { pipe = usb_rcvbulkpipe(d->udev, rc_ep); diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index 8106a47a0dd0e8831fb8871020de6a0b1c884611..b51d2de1aca86fb95d75498cfc72302d4e9fc6a7 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -3478,6 +3478,11 @@ static void ov511_mode_init_regs(struct sd *sd) return; } + if (alt->desc.bNumEndpoints < 1) { + sd->gspca_dev.usb_err = -ENODEV; + return; + } + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); @@ -3604,6 +3609,11 @@ static void ov518_mode_init_regs(struct sd *sd) return; } + if (alt->desc.bNumEndpoints < 1) { + sd->gspca_dev.usb_err = -ENODEV; + return; + } + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index e72c3e1ab9ff41f0a39d685d4615a8bd3cb06914..9caa5ef9d9e08f1b2bbe9ec9390119355c6e2150 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -289,6 +289,9 @@ static int stv06xx_start(struct gspca_dev *gspca_dev) return -EIO; } + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); if (err < 0) @@ -313,11 +316,21 @@ static int stv06xx_start(struct gspca_dev *gspca_dev) static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) { + struct usb_interface_cache *intfc; struct usb_host_interface *alt; struct sd *sd = (struct sd *) gspca_dev; + intfc = gspca_dev->dev->actconfig->intf_cache[0]; + + if (intfc->num_altsetting < 2) + return -ENODEV; + + alt = &intfc->altsetting[1]; + + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); @@ -330,6 +343,10 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) struct usb_host_interface *alt; struct sd *sd = (struct sd *) gspca_dev; + /* + * Existence of altsetting and endpoint was verified in + * stv06xx_isoc_init() + */ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c index e1ce96e9405f5ed89a23c5c0a59a7b5290b5cd93..8d855b2756ba0647db08d4eb6b3ecf4f4b840bf8 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c @@ -194,6 +194,10 @@ static int pb0100_start(struct sd *sd) alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) return -ENODEV; + + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); /* If we don't have enough bandwidth use a lower framerate */ diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c index 68656e7986c752c982e65fea98d563cb12c7f03e..765a5d03e7cc96a9e570f6c7dad725773b3987dd 100644 --- a/drivers/media/usb/gspca/xirlink_cit.c +++ b/drivers/media/usb/gspca/xirlink_cit.c @@ -1451,6 +1451,9 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev) return -EIO; } + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); } @@ -2634,6 +2637,7 @@ static int sd_start(struct gspca_dev *gspca_dev) static int sd_isoc_init(struct gspca_dev *gspca_dev) { + struct usb_interface_cache *intfc; struct usb_host_interface *alt; int max_packet_size; @@ -2649,8 +2653,17 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) break; } + intfc = gspca_dev->dev->actconfig->intf_cache[0]; + + if (intfc->num_altsetting < 2) + return -ENODEV; + + alt = &intfc->altsetting[1]; + + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); return 0; @@ -2673,6 +2686,9 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) break; } + /* + * Existence of altsetting and endpoint was verified in sd_isoc_init() + */ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); if (packet_size <= min_packet_size) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 68df16b3ce72030c0b566dc31f93a58d51a040b8..50a61143898b5421874edc7bfb51c3fbce95382a 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -56,7 +56,7 @@ int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 0); + value, index, NULL, 0, USB_CTRL_GET_TIMEOUT); if (ret < 0) return ret; } diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 3668a04359e8004bc0ea5c89c91def7c28a568f1..7c23d82313a84e8ea9a71791b4c564d8c2d21c7b 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -720,7 +720,8 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) ret = usb_control_msg(usbtv->udev, usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, USBTV_BASE + 0x0244, (void *)data, 3, 0); + 0, USBTV_BASE + 0x0244, (void *)data, 3, + USB_CTRL_GET_TIMEOUT); if (ret < 0) goto error; } @@ -771,7 +772,7 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, (void *)data, size, 0); + 0, index, (void *)data, size, USB_CTRL_SET_TIMEOUT); error: if (ret < 0) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 653dd932ac6820f768647aa479b426992eb19750..591ca125bd9684e7dc52cdbba48b4744d89ef02b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1446,6 +1446,11 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, break; if (forward == prev) continue; + if (forward->chain.next || forward->chain.prev) { + uvc_trace(UVC_TRACE_DESCR, "Found reference to " + "entity %d already in chain.\n", forward->id); + return -EINVAL; + } switch (UVC_ENTITY_TYPE(forward)) { case UVC_VC_EXTENSION_UNIT: @@ -1527,6 +1532,13 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, return -1; } + if (term->chain.next || term->chain.prev) { + uvc_trace(UVC_TRACE_DESCR, "Found reference to " + "entity %d already in chain.\n", + term->id); + return -EINVAL; + } + if (uvc_trace_param & UVC_TRACE_PROBE) printk(KERN_CONT " %d", term->id); diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index f412429cf5ba586958a3693a35eee48ad7043c51..c55e607f5631d34ec898ffdd7d513ae5bab44514 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -352,8 +352,11 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) BUG_ON(dma->sglen); if (dma->pages) { - for (i = 0; i < dma->nr_pages; i++) + for (i = 0; i < dma->nr_pages; i++) { + if (dma->direction == DMA_FROM_DEVICE) + set_page_dirty_lock(dma->pages[i]); put_page(dma->pages[i]); + } kfree(dma->pages); dma->pages = NULL; } diff --git a/drivers/media/v4l2loopback-master/v4l2loopback.c b/drivers/media/v4l2loopback-master/v4l2loopback.c index 7aba7d108d2ef3a61dd63a434590e4f456b95adf..bf825d86b3817f40fa346541e0355f93bf9d8d0c 100644 --- a/drivers/media/v4l2loopback-master/v4l2loopback.c +++ b/drivers/media/v4l2loopback-master/v4l2loopback.c @@ -199,11 +199,20 @@ MODULE_PARM_DESC(max_height, "maximum frame height"); #define CID_SUSTAIN_FRAMERATE (V4L2LOOPBACK_CID_BASE + 1) #define CID_TIMEOUT (V4L2LOOPBACK_CID_BASE + 2) #define CID_TIMEOUT_IMAGE_IO (V4L2LOOPBACK_CID_BASE + 3) +#define CID_CROP_DATASIZE (V4L2_CTRL_CLASS_USER + 0x1000) static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl); static const struct v4l2_ctrl_ops v4l2loopback_ctrl_ops = { .s_ctrl = v4l2loopback_s_ctrl, }; +static int v4l2loopback_datasize_g_ctrl(struct v4l2_ctrl *ctrl); +static int v4l2loopback_datasize_s_ctrl(struct v4l2_ctrl *ctrl); +static int v4l2loopback_datasize_try_ctrl(struct v4l2_ctrl *ctrl); +static const struct v4l2_ctrl_ops v4l2loopback_datasize_ctrl_ops = { + .s_ctrl = v4l2loopback_datasize_s_ctrl, + .try_ctrl = v4l2loopback_datasize_try_ctrl, + .g_volatile_ctrl = v4l2loopback_datasize_g_ctrl +}; static const struct v4l2_ctrl_config v4l2loopback_ctrl_keepformat = { .ops = &v4l2loopback_ctrl_ops, .id = CID_KEEP_FORMAT, @@ -244,6 +253,17 @@ static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeoutimageio = { .step = 1, .def = 0, }; +static const struct v4l2_ctrl_config v4l2loopback_ctrl_datasize = { + .ops = &v4l2loopback_datasize_ctrl_ops, + .id = CID_CROP_DATASIZE, + .name = "crop_datasize", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = V4L2LOOPBACK_SIZE_MIN_WIDTH * V4L2LOOPBACK_SIZE_MIN_HEIGHT, + .max = V4L2LOOPBACK_SIZE_MAX_WIDTH * V4L2LOOPBACK_SIZE_MAX_HEIGHT, + .step = 1, + .def = V4L2LOOPBACK_SIZE_DEFAULT_WIDTH * + V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT, +}; /* module structures */ @@ -269,6 +289,7 @@ struct v4l2_loopback_device { /* pixel and stream format */ struct v4l2_pix_format pix_format; struct v4l2_captureparm capture_param; + struct v4l2_crop frame_crop; unsigned long frame_jiffies; /* ctrls */ @@ -1050,6 +1071,119 @@ static int vidioc_s_fmt_out(struct file *file, void *priv, return ret; } +/* returns the crop capabilities for a device *dev + * as this is a loopback and does not control an actual sensor, + * just return the reported maximum supported dimensions + */ +static int v4l2_loopback_cropcap(struct v4l2_loopback_device *dev, + struct v4l2_cropcap *cropcap) +{ + cropcap->defrect = (struct v4l2_rect) {0, 0, + V4L2LOOPBACK_SIZE_MAX_WIDTH, + V4L2LOOPBACK_SIZE_MAX_HEIGHT}; + cropcap->bounds = (struct v4l2_rect) {0, 0, + V4L2LOOPBACK_SIZE_MAX_WIDTH, + V4L2LOOPBACK_SIZE_MAX_HEIGHT}; + cropcap->pixelaspect = (struct v4l2_fract){1, 1}; + cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + return 0; +} + +/* wrapper function with the necessary arguments for struct v4l2_ioctl_ops + */ +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cropcap) +{ + struct v4l2_loopback_device *dev; + + MARK(); + dev = v4l2loopback_getdevice(file); + + return v4l2_loopback_cropcap(dev, cropcap); +} + +/* return the currently set dimensions for cropping + */ +static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) +{ + struct v4l2_loopback_device *dev; + int ret = 0; + + MARK(); + if (crop != NULL) { + dev = v4l2loopback_getdevice(file); + crop->c = dev->frame_crop.c; + crop->type = dev->frame_crop.type; + } else { + ret = -EINVAL; + } + return ret; +} + +/* set new dimensions for cropping and limit them to acceptable values + */ +static int v4l2_loopback_s_crop(struct v4l2_loopback_device *dev, + const struct v4l2_crop *crop, bool limit_to_pix_format) +{ + struct v4l2_rect c; + int ret = 0; + + if (crop != NULL) { + c = crop->c; + + if (limit_to_pix_format) { + c.left = min(c.left, + (typeof(c.left)) dev->pix_format.width - 1); + c.top = min(c.top, + (typeof(c.top)) dev->pix_format.height - 1); + } + + c.left = max(c.left, 0); + c.top = max(c.top, 0); + + if (limit_to_pix_format) { + c.width = min(c.width, (typeof(c.width)) + dev->pix_format.width - c.left); + c.height = min(c.height, (typeof(c.height)) + dev->pix_format.height - c.top); + } + + c.width = max_t(typeof(c.width), + c.width, V4L2LOOPBACK_SIZE_MIN_WIDTH); + c.height = max_t(typeof(c.height), + c.height, V4L2LOOPBACK_SIZE_MIN_HEIGHT); + + c.left = min(c.left, max_width - 1); + c.top = min(c.top, max_height - 1); + c.width = min(c.width, (typeof(c.width)) max_width - c.left); + c.height = min(c.height, (typeof(c.height)) max_height - c.top); + + if (dev->buffer_size > 0 && + c.width * c.height > dev->buffer_size) + c.height = + (typeof(c.height)) dev->buffer_size / c.width; + + dev->frame_crop.c = c; + dev->frame_crop.type = crop->type; + } else { + ret = -EINVAL; + } + return ret; +} + +/* wrapper function with the necessary arguments for struct v4l2_ioctl_ops + */ +static int vidioc_s_crop(struct file *file, void *priv, + const struct v4l2_crop *crop) +{ + struct v4l2_loopback_device *dev; + + MARK(); + dev = v4l2loopback_getdevice(file); + + return v4l2_loopback_s_crop(dev, crop, true); +} + /*#define V4L2L_OVERLAY*/ #ifdef V4L2L_OVERLAY /* ------------------ OVERLAY ----------------------- */ @@ -1214,6 +1348,31 @@ static int v4l2loopback_set_ctrl(struct v4l2_loopback_device *dev, return 0; } +static int v4l2loopback_datasize_get_ctrl(struct v4l2_loopback_device *dev, + u32 id, + s32 *val) +{ + struct v4l2_pix_format pix_format; + const struct v4l2l_format *format; + __u32 pixfmt; + __u32 w; + __u32 h; + + switch (id) { + case CID_CROP_DATASIZE: + pixfmt = dev->pix_format.pixelformat; + format = format_by_fourcc(pixfmt); + w = dev->frame_crop.c.width - dev->frame_crop.c.left; + h = dev->frame_crop.c.height - dev->frame_crop.c.top; + pix_format_set_size(&pix_format, format, w, h); + *val = (s32) pix_format.sizeimage; + break; + default: + return -EINVAL; + } + return 0; +} + static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_loopback_device *dev = container_of(ctrl->handler, @@ -1222,6 +1381,24 @@ static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl) return v4l2loopback_set_ctrl(dev, ctrl->id, ctrl->val); } +static int v4l2loopback_datasize_g_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_loopback_device *dev = container_of(ctrl->handler, + struct v4l2_loopback_device, ctrl_handler); + + return v4l2loopback_datasize_get_ctrl(dev, ctrl->id, &ctrl->val); +} + +static int v4l2loopback_datasize_s_ctrl(struct v4l2_ctrl *ctrl) +{ + return -EINVAL; +} + +static int v4l2loopback_datasize_try_ctrl(struct v4l2_ctrl *ctrl) +{ + return -EINVAL; +} + /* returns set of device outputs, in our case there is only one * called on VIDIOC_ENUMOUTPUT */ @@ -2260,6 +2437,9 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr) { int ret; struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + struct v4l2_ctrl *ctrl; snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "v4l2loopback-%03d", nr); @@ -2330,6 +2510,12 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr) v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_sustainframerate, NULL); v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeout, NULL); v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeoutimageio, NULL); + ctrl = v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_datasize, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + else + goto error; + if (hdl->error) { ret = hdl->error; goto error; @@ -2354,6 +2540,16 @@ static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr) init_waitqueue_head(&dev->read_event); init_waitqueue_head(&dev->write_event); + ret = v4l2_loopback_cropcap(dev, &cropcap); + if (ret) + goto error; + + crop.type = cropcap.type; + crop.c = cropcap.defrect; + ret = v4l2_loopback_s_crop(dev, &crop, false); + if (ret) + goto error; + MARK(); return 0; @@ -2406,6 +2602,10 @@ static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops = { .vidioc_g_fmt_vid_out = &vidioc_g_fmt_out, .vidioc_try_fmt_vid_out = &vidioc_try_fmt_out, + .vidioc_cropcap = &vidioc_cropcap, + .vidioc_g_crop = &vidioc_g_crop, + .vidioc_s_crop = &vidioc_s_crop, + #ifdef V4L2L_OVERLAY .vidioc_s_fmt_vid_overlay = &vidioc_s_fmt_overlay, .vidioc_g_fmt_vid_overlay = &vidioc_g_fmt_overlay, diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index fe1811523e4a7aac70e0498e7cd70fac55e2046b..eff6ae5073c8e25164584494b849949990e8311c 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -257,7 +257,7 @@ static const struct mfd_cell da9062_devs[] = { .name = "da9062-watchdog", .num_resources = ARRAY_SIZE(da9062_wdt_resources), .resources = da9062_wdt_resources, - .of_compatible = "dlg,da9062-wdt", + .of_compatible = "dlg,da9062-watchdog", }, { .name = "da9062-thermal", diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c index 704e189ca162ab6991d9b548c7aa88d67cc7a020..672831d5ee32e1c6ba0737cb99a2f80d0e867373 100644 --- a/drivers/mfd/dln2.c +++ b/drivers/mfd/dln2.c @@ -93,6 +93,11 @@ struct dln2_mod_rx_slots { spinlock_t lock; }; +enum dln2_endpoint { + DLN2_EP_OUT = 0, + DLN2_EP_IN = 1, +}; + struct dln2_dev { struct usb_device *usb_dev; struct usb_interface *interface; @@ -729,6 +734,8 @@ static int dln2_probe(struct usb_interface *interface, const struct usb_device_id *usb_id) { struct usb_host_interface *hostif = interface->cur_altsetting; + struct usb_endpoint_descriptor *epin; + struct usb_endpoint_descriptor *epout; struct device *dev = &interface->dev; struct dln2_dev *dln2; int ret; @@ -738,12 +745,19 @@ static int dln2_probe(struct usb_interface *interface, hostif->desc.bNumEndpoints < 2) return -ENODEV; + epout = &hostif->endpoint[DLN2_EP_OUT].desc; + if (!usb_endpoint_is_bulk_out(epout)) + return -ENODEV; + epin = &hostif->endpoint[DLN2_EP_IN].desc; + if (!usb_endpoint_is_bulk_in(epin)) + return -ENODEV; + dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL); if (!dln2) return -ENOMEM; - dln2->ep_out = hostif->endpoint[0].desc.bEndpointAddress; - dln2->ep_in = hostif->endpoint[1].desc.bEndpointAddress; + dln2->ep_out = epout->bEndpointAddress; + dln2->ep_in = epin->bEndpointAddress; dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface)); dln2->interface = interface; usb_set_intfdata(interface, dln2); diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index f4037d42a60fa7bcc63f034e01779d0557597110..dd4251f105e024b4d29c745f5a0f7518da7c2006 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -32,6 +32,7 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) case RN5T618_WATCHDOGCNT: case RN5T618_DCIRQ: case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL: + case RN5T618_ADCCNT3: case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3: case RN5T618_IR_GPR: case RN5T618_IR_GPF: diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index ff296a4bf3d235a2bd860989b4464be58a79341d..dc6a9432a4b652dae27277474aab71463147642c 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -369,6 +369,7 @@ static const struct pcr_ops rts522a_pcr_ops = { void rts522a_init_params(struct rtsx_pcr *pcr) { rts5227_init_params(pcr); + pcr->ops = &rts522a_pcr_ops; pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3; } diff --git a/drivers/misc/altera-stapl/altera.c b/drivers/misc/altera-stapl/altera.c index 494e263daa748d30b9a284be67c0fd3c518eebc3..b7ee8043a133ec4d06348284685ba44aa6de2d79 100644 --- a/drivers/misc/altera-stapl/altera.c +++ b/drivers/misc/altera-stapl/altera.c @@ -2126,8 +2126,8 @@ static int altera_execute(struct altera_state *astate, return status; } -static int altera_get_note(u8 *p, s32 program_size, - s32 *offset, char *key, char *value, int length) +static int altera_get_note(u8 *p, s32 program_size, s32 *offset, + char *key, char *value, int keylen, int vallen) /* * Gets key and value of NOTE fields in the JBC file. * Can be called in two modes: if offset pointer is NULL, @@ -2184,7 +2184,7 @@ static int altera_get_note(u8 *p, s32 program_size, &p[note_table + (8 * i) + 4])]; if (value != NULL) - strlcpy(value, value_ptr, length); + strlcpy(value, value_ptr, vallen); } } @@ -2203,13 +2203,13 @@ static int altera_get_note(u8 *p, s32 program_size, strlcpy(key, &p[note_strings + get_unaligned_be32( &p[note_table + (8 * i)])], - length); + keylen); if (value != NULL) strlcpy(value, &p[note_strings + get_unaligned_be32( &p[note_table + (8 * i) + 4])], - length); + vallen); *offset = i + 1; } @@ -2463,7 +2463,7 @@ int altera_init(struct altera_config *config, const struct firmware *fw) __func__, (format_version == 2) ? "Jam STAPL" : "pre-standardized Jam 1.1"); while (altera_get_note((u8 *)fw->data, fw->size, - &offset, key, value, 256) == 0) + &offset, key, value, 32, 256) == 0) printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n", __func__, key, value); } diff --git a/drivers/misc/echo/echo.c b/drivers/misc/echo/echo.c index 9597e9523cac4d7459e1869f69a49f1c80a73b24..fff13176f9b8b1dddb6f9464622d9803d23ca1da 100644 --- a/drivers/misc/echo/echo.c +++ b/drivers/misc/echo/echo.c @@ -454,7 +454,7 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) */ ec->factor = 0; ec->shift = 0; - if ((ec->nonupdate_dwell == 0)) { + if (!ec->nonupdate_dwell) { int p, logp, shift; /* Determine: diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c index 62f76d506f0405443eeb1804b220e803339d9378..e859d94fd90382550e755bb8bdea19fa0ae5bda6 100644 --- a/drivers/misc/lkdtm_perms.c +++ b/drivers/misc/lkdtm_perms.c @@ -109,7 +109,12 @@ void lkdtm_WRITE_KERN(void) size_t size; unsigned char *ptr; - size = (unsigned long)do_overwritten - (unsigned long)do_nothing; + if ((unsigned long)do_overwritten < (unsigned long)do_nothing) + size = (unsigned long)do_nothing - + (unsigned long)do_overwritten; + else + size = (unsigned long)do_overwritten - + (unsigned long)do_nothing; ptr = (unsigned char *)do_overwritten; pr_info("attempting bad %zu byte write at %px\n", size, ptr); diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 230f1e8538dc9c16a810487eb1161ae067c05d8d..953af49dd38a531f7b9f8b45d734f2ab07b6fd74 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -466,7 +466,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, int err; int irq = 0; int id; - char name[20]; + char name[24]; enum pci_barno bar; void __iomem *base; struct device *dev = &pdev->dev; diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index f3c12b118f3ad4bee7d57b53b16165444b4d7bee..66ed5193add49d7f7e9d717305e4ad9df4f39ab1 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -52,7 +52,6 @@ #include #include #include "compat_qseecom.h" -#include #include #define QSEECOM_DEV "qseecom" @@ -8115,19 +8114,6 @@ static long qseecom_ioctl(struct file *file, qcom_ice_set_fde_flag(ice_data.flag); break; } - case QSEECOM_IOCTL_FBE_CLEAR_KEY: { - struct qseecom_ice_key_data_t key_data; - - ret = copy_from_user(&key_data, argp, sizeof(key_data)); - if (ret) { - pr_err("copy from user failed\n"); - return -EFAULT; - } - pfk_fbe_clear_key((const unsigned char *) key_data.key, - key_data.key_len, (const unsigned char *) - key_data.salt, key_data.salt_len); - break; - } default: pr_err("Invalid IOCTL: 0x%x\n", cmd); return -EINVAL; diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index d04faf312ed64d5f040e8b7f52ef7de7d1c93158..c82424ef3c7fc447674ba5e598a900b53ebe5748 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -126,7 +126,7 @@ static void get_full_task_comm(struct task_entry *task_entry, int i = 0, offset = 0, len = 0; /* save one byte for terminating null character */ int unused_len = MAX_TASK_COMM_LEN - TASK_COMM_LEN - 1; - char buf[unused_len]; + char buf[MAX_TASK_COMM_LEN - TASK_COMM_LEN - 1]; struct mm_struct *mm = task->mm; /* fill the first TASK_COMM_LEN bytes with thread name */ diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 06febb56fa5ffe29843fdcde7f4e4942d092a0a4..ba338d2a1c004dd464a38c645b4703d2c303179c 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -216,8 +216,6 @@ void mmc_cmdq_setup_queue(struct mmc_queue *mq, struct mmc_card *card) host->max_req_size / 512)); blk_queue_max_segment_size(mq->queue, host->max_seg_size); blk_queue_max_segments(mq->queue, host->max_segs); - if (host->inlinecrypt_support) - queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, mq->queue); } static struct scatterlist *mmc_alloc_sg(int sg_len, gfp_t gfp) @@ -439,6 +437,9 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, /* hook for pm qos cmdq init */ if (card->host->cmdq_ops->init) card->host->cmdq_ops->init(card->host); + if (host->cmdq_ops->cqe_crypto_update_queue) + host->cmdq_ops->cqe_crypto_update_queue(host, + mq->queue); mq->thread = kthread_run(mmc_cmdq_thread, mq, "mmc-cmdqd/%d%s", host->index, @@ -481,8 +482,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); - if (host->inlinecrypt_support) - queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, mq->queue); sema_init(&mq->thread_sem, 1); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 73e43441f4dd83c453cf99faea37321b2ba75b5d..f361eed351809c9a9a9d53fd123469abe810d7d9 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -439,17 +439,6 @@ config MMC_SDHCI_MSM If unsure, say N. -config MMC_SDHCI_MSM_ICE - bool "Qualcomm Technologies, Inc Inline Crypto Engine for SDHCI core" - depends on MMC_SDHCI_MSM && CRYPTO_DEV_QCOM_ICE - help - This selects the QTI specific additions to support Inline Crypto - Engine (ICE). ICE accelerates the crypto operations and maintains - the high SDHCI performance. - - Select this if you have ICE supported for SDHCI on QTI chipset. - If unsure, say N. - config MMC_MXC tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" depends on ARCH_MXC || PPC_MPC512x @@ -924,3 +913,20 @@ config MMC_SDHCI_XENON This selects Marvell Xenon eMMC/SD/SDIO SDHCI. If you have a controller with this interface, say Y or M here. If unsure, say N. + +config MMC_CQ_HCI_CRYPTO + bool "CQHCI Crypto Engine Support" + depends on MMC_CQ_HCI && BLK_INLINE_ENCRYPTION + help + Enable Crypto Engine Support in CQHCI. + Enabling this makes it possible for the kernel to use the crypto + capabilities of the CQHCI device (if present) to perform crypto + operations on data being transferred to/from the device. + +config MMC_CQ_HCI_CRYPTO_QTI + bool "Vendor specific CQHCI Crypto Engine Support" + depends on MMC_CQ_HCI_CRYPTO + help + Enable Vendor Crypto Engine Support in CQHCI + Enabling this allows kernel to use CQHCI crypto operations defined + and implemented by QTI. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index f079ab6fb055f2c801cf8264ca9711db184af92d..3b2f1dd243c353e2dbe57f70b0daeb7842dc907b 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -85,14 +85,14 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o -obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o -obj-$(CONFIG_MMC_SDHCI_MSM_ICE) += sdhci-msm-ice.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_CQ_HCI) += cmdq_hci.o obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o +obj-$(CONFIG_MMC_CQ_HCI_CRYPTO) += cmdq_hci-crypto.o +obj-$(CONFIG_MMC_CQ_HCI_CRYPTO_QTI) += cmdq_hci-crypto-qti.o ifeq ($(CONFIG_CB710_DEBUG),y) CFLAGS-cb710-mmc += -DDEBUG diff --git a/drivers/mmc/host/cmdq_hci-crypto-qti.c b/drivers/mmc/host/cmdq_hci-crypto-qti.c new file mode 100644 index 0000000000000000000000000000000000000000..84718e8da7f3be3f149a1756b513f99e41869c21 --- /dev/null +++ b/drivers/mmc/host/cmdq_hci-crypto-qti.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include "sdhci.h" +#include "sdhci-pltfm.h" +#include "sdhci-msm.h" +#include "cmdq_hci-crypto-qti.h" +#include + +#define RAW_SECRET_SIZE 32 +#define MINIMUM_DUN_SIZE 512 +#define MAXIMUM_DUN_SIZE 65536 + +static struct cmdq_host_crypto_variant_ops cmdq_crypto_qti_variant_ops = { + .host_init_crypto = cmdq_crypto_qti_init_crypto, + .enable = cmdq_crypto_qti_enable, + .disable = cmdq_crypto_qti_disable, + .resume = cmdq_crypto_qti_resume, + .debug = cmdq_crypto_qti_debug, +}; + +static bool ice_cap_idx_valid(struct cmdq_host *host, + unsigned int cap_idx) +{ + return cap_idx < host->crypto_capabilities.num_crypto_cap; +} + +static uint8_t get_data_unit_size_mask(unsigned int data_unit_size) +{ + if (data_unit_size < MINIMUM_DUN_SIZE || + data_unit_size > MAXIMUM_DUN_SIZE || + !is_power_of_2(data_unit_size)) + return 0; + + return data_unit_size / MINIMUM_DUN_SIZE; +} + + +void cmdq_crypto_qti_enable(struct cmdq_host *host) +{ + int err = 0; + + if (!cmdq_host_is_crypto_supported(host)) + return; + + host->caps |= CMDQ_CAP_CRYPTO_SUPPORT; + + err = crypto_qti_enable(host->crypto_vops->priv); + if (err) { + pr_err("%s: Error enabling crypto, err %d\n", + __func__, err); + cmdq_crypto_qti_disable(host); + } +} + +void cmdq_crypto_qti_disable(struct cmdq_host *host) +{ + /* cmdq_crypto_disable_spec(host) and + * crypto_qti_disable(host->crypto_vops->priv) + * are needed here? + */ +} + +static int cmdq_crypto_qti_keyslot_program(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct cmdq_host *host = keyslot_manager_private(ksm); + int err = 0; + u8 data_unit_mask; + int crypto_alg_id; + + crypto_alg_id = cmdq_crypto_cap_find(host, key->crypto_mode, + key->data_unit_size); + + if (!cmdq_is_crypto_enabled(host) || + !cmdq_keyslot_valid(host, slot) || + !ice_cap_idx_valid(host, crypto_alg_id)) { + return -EINVAL; + } + + data_unit_mask = get_data_unit_size_mask(key->data_unit_size); + + if (!(data_unit_mask & + host->crypto_cap_array[crypto_alg_id].sdus_mask)) { + return -EINVAL; + } + + err = crypto_qti_keyslot_program(host->crypto_vops->priv, key, + slot, data_unit_mask, crypto_alg_id); + if (err) + pr_err("%s: failed with error %d\n", __func__, err); + + return err; +} + +static int cmdq_crypto_qti_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + int err = 0; + struct cmdq_host *host = keyslot_manager_private(ksm); + + if (!cmdq_is_crypto_enabled(host) || + !cmdq_keyslot_valid(host, slot)) + return -EINVAL; + + err = crypto_qti_keyslot_evict(host->crypto_vops->priv, slot); + if (err) + pr_err("%s: failed with error %d\n", __func__, err); + + return err; +} + +static int cmdq_crypto_qti_derive_raw_secret(struct keyslot_manager *ksm, + const u8 *wrapped_key, unsigned int wrapped_key_size, + u8 *secret, unsigned int secret_size) +{ + int err = 0; + + if (wrapped_key_size <= RAW_SECRET_SIZE) { + pr_err("%s: Invalid wrapped_key_size: %u\n", __func__, + wrapped_key_size); + err = -EINVAL; + return err; + } + if (secret_size != RAW_SECRET_SIZE) { + pr_err("%s: Invalid secret size: %u\n", __func__, secret_size); + err = -EINVAL; + return err; + } + memcpy(secret, wrapped_key, secret_size); + return 0; +} + +static const struct keyslot_mgmt_ll_ops cmdq_crypto_qti_ksm_ops = { + .keyslot_program = cmdq_crypto_qti_keyslot_program, + .keyslot_evict = cmdq_crypto_qti_keyslot_evict, + .derive_raw_secret = cmdq_crypto_qti_derive_raw_secret +}; + +enum blk_crypto_mode_num cmdq_blk_crypto_qti_mode_num_for_alg_dusize( + enum cmdq_crypto_alg cmdq_crypto_alg, + enum cmdq_crypto_key_size key_size) +{ + /* + * Currently the only mode that eMMC and blk-crypto both support. + */ + if (cmdq_crypto_alg == CMDQ_CRYPTO_ALG_AES_XTS && + key_size == CMDQ_CRYPTO_KEY_SIZE_256) + return BLK_ENCRYPTION_MODE_AES_256_XTS; + + return BLK_ENCRYPTION_MODE_INVALID; +} + +int cmdq_host_init_crypto_qti_spec(struct cmdq_host *host, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int cap_idx = 0; + int err = 0; + unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX]; + enum blk_crypto_mode_num blk_mode_num; + + /* Default to disabling crypto */ + host->caps &= ~CMDQ_CAP_CRYPTO_SUPPORT; + + if (!(cmdq_readl(host, CQCAP) & CQ_CAP_CS)) { + pr_debug("%s no crypto capability\n", __func__); + err = -ENODEV; + goto out; + } + + /* + * Crypto Capabilities should never be 0, because the + * config_array_ptr > 04h. So we use a 0 value to indicate that + * crypto init failed, and can't be enabled. + */ + host->crypto_capabilities.reg_val = cmdq_readl(host, CQ_CCAP); + host->crypto_cfg_register = + (u32)host->crypto_capabilities.config_array_ptr * 0x100; + host->crypto_cap_array = + devm_kcalloc(mmc_dev(host->mmc), + host->crypto_capabilities.num_crypto_cap, + sizeof(host->crypto_cap_array[0]), GFP_KERNEL); + if (!host->crypto_cap_array) { + err = -ENOMEM; + pr_err("%s failed to allocate memory\n", __func__); + goto out; + } + + memset(crypto_modes_supported, 0, sizeof(crypto_modes_supported)); + + /* + * Store all the capabilities now so that we don't need to repeatedly + * access the device each time we want to know its capabilities + */ + for (cap_idx = 0; cap_idx < host->crypto_capabilities.num_crypto_cap; + cap_idx++) { + host->crypto_cap_array[cap_idx].reg_val = + cpu_to_le32(cmdq_readl(host, + CQ_CRYPTOCAP + + cap_idx * sizeof(__le32))); + blk_mode_num = cmdq_blk_crypto_qti_mode_num_for_alg_dusize( + host->crypto_cap_array[cap_idx].algorithm_id, + host->crypto_cap_array[cap_idx].key_size); + if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID) + continue; + crypto_modes_supported[blk_mode_num] |= + host->crypto_cap_array[cap_idx].sdus_mask * 512; + } + + host->ksm = keyslot_manager_create(cmdq_num_keyslots(host), ksm_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS | + BLK_CRYPTO_FEATURE_WRAPPED_KEYS, + crypto_modes_supported, host); + + if (!host->ksm) { + err = -ENOMEM; + goto out; + } + keyslot_manager_set_max_dun_bytes(host->ksm, sizeof(u32)); + + /* + * In case host controller supports cryptographic operations + * then, it uses 128bit task descriptor. Upper 64 bits of task + * descriptor would be used to pass crypto specific informaton. + */ + host->caps |= CMDQ_TASK_DESC_SZ_128; + + return 0; + +out: + /* Indicate that init failed by setting crypto_capabilities to 0 */ + host->crypto_capabilities.reg_val = 0; + return err; +} + +int cmdq_crypto_qti_init_crypto(struct cmdq_host *host, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int err = 0; + struct sdhci_host *sdhci = mmc_priv(host->mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct resource *cmdq_ice_memres = NULL; + + cmdq_ice_memres = platform_get_resource_byname(msm_host->pdev, + IORESOURCE_MEM, + "cmdq_ice"); + if (!cmdq_ice_memres) { + pr_debug("%s ICE not supported\n", __func__); + host->icemmio = NULL; + return PTR_ERR(cmdq_ice_memres); + } + + host->icemmio = devm_ioremap(&msm_host->pdev->dev, + cmdq_ice_memres->start, + resource_size(cmdq_ice_memres)); + if (!host->icemmio) { + pr_err("%s failed to remap ice regs\n", __func__); + return PTR_ERR(host->icemmio); + } + + err = cmdq_host_init_crypto_qti_spec(host, &cmdq_crypto_qti_ksm_ops); + if (err) { + pr_err("%s: Error initiating crypto capabilities, err %d\n", + __func__, err); + return err; + } + + err = crypto_qti_init_crypto(&msm_host->pdev->dev, + host->icemmio, (void **)&host->crypto_vops->priv); + if (err) { + pr_err("%s: Error initiating crypto, err %d\n", + __func__, err); + } + return err; +} + +int cmdq_crypto_qti_debug(struct cmdq_host *host) +{ + return crypto_qti_debug(host->crypto_vops->priv); +} + +void cmdq_crypto_qti_set_vops(struct cmdq_host *host) +{ + return cmdq_crypto_set_vops(host, &cmdq_crypto_qti_variant_ops); +} + +int cmdq_crypto_qti_resume(struct cmdq_host *host) +{ + return crypto_qti_resume(host->crypto_vops->priv); +} diff --git a/drivers/mmc/host/cmdq_hci-crypto-qti.h b/drivers/mmc/host/cmdq_hci-crypto-qti.h new file mode 100644 index 0000000000000000000000000000000000000000..e63465bca3e283154d8cc37042ea7bb952f24cb1 --- /dev/null +++ b/drivers/mmc/host/cmdq_hci-crypto-qti.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CMDQ_HCI_CRYPTO_QTI_H +#define _CMDQ_HCI_CRYPTO_QTI_H + +#include "cmdq_hci-crypto.h" + +void cmdq_crypto_qti_enable(struct cmdq_host *host); + +void cmdq_crypto_qti_disable(struct cmdq_host *host); + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION +int cmdq_crypto_qti_init_crypto(struct cmdq_host *host, + const struct keyslot_mgmt_ll_ops *ksm_ops); +#endif + +int cmdq_crypto_qti_debug(struct cmdq_host *host); + +void cmdq_crypto_qti_set_vops(struct cmdq_host *host); + +int cmdq_crypto_qti_resume(struct cmdq_host *host); + +#endif /* _CMDQ_HCI_CRYPTO_QTI_H */ diff --git a/drivers/mmc/host/cmdq_hci-crypto.c b/drivers/mmc/host/cmdq_hci-crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..26f84001f064c1cbb0da35c76ad44df1143aa711 --- /dev/null +++ b/drivers/mmc/host/cmdq_hci-crypto.c @@ -0,0 +1,536 @@ +/* + * Copyright 2020 Google LLC + * + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * drivers/mmc/host/cmdq-crypto.c - Qualcomm Technologies, Inc. + * + * Original source is taken from: + * https://android.googlesource.com/kernel/common/+/4bac1109a10c55d49c0aa4f7ebdc4bc53cc368e8 + * The driver caters to crypto engine support for UFS controllers. + * The crypto engine programming sequence, HW functionality and register + * offset is almost same in UFS and eMMC controllers. + */ + +#include +#include "cmdq_hci-crypto.h" +#include "../core/queue.h" + +static bool cmdq_cap_idx_valid(struct cmdq_host *host, unsigned int cap_idx) +{ + return cap_idx < host->crypto_capabilities.num_crypto_cap; +} + +static u8 get_data_unit_size_mask(unsigned int data_unit_size) +{ + if (data_unit_size < 512 || data_unit_size > 65536 || + !is_power_of_2(data_unit_size)) + return 0; + + return data_unit_size / 512; +} + +static size_t get_keysize_bytes(enum cmdq_crypto_key_size size) +{ + switch (size) { + case CMDQ_CRYPTO_KEY_SIZE_128: + return 16; + case CMDQ_CRYPTO_KEY_SIZE_192: + return 24; + case CMDQ_CRYPTO_KEY_SIZE_256: + return 32; + case CMDQ_CRYPTO_KEY_SIZE_512: + return 64; + default: + return 0; + } +} + +int cmdq_crypto_cap_find(void *host_p, enum blk_crypto_mode_num crypto_mode, + unsigned int data_unit_size) +{ + struct cmdq_host *host = host_p; + enum cmdq_crypto_alg cmdq_alg; + u8 data_unit_mask; + int cap_idx; + enum cmdq_crypto_key_size cmdq_key_size; + union cmdq_crypto_cap_entry *ccap_array = host->crypto_cap_array; + + if (!cmdq_host_is_crypto_supported(host)) + return -EINVAL; + + switch (crypto_mode) { + case BLK_ENCRYPTION_MODE_AES_256_XTS: + cmdq_alg = CMDQ_CRYPTO_ALG_AES_XTS; + cmdq_key_size = CMDQ_CRYPTO_KEY_SIZE_256; + break; + default: + return -EINVAL; + } + + data_unit_mask = get_data_unit_size_mask(data_unit_size); + + for (cap_idx = 0; cap_idx < host->crypto_capabilities.num_crypto_cap; + cap_idx++) { + if (ccap_array[cap_idx].algorithm_id == cmdq_alg && + (ccap_array[cap_idx].sdus_mask & data_unit_mask) && + ccap_array[cap_idx].key_size == cmdq_key_size) + return cap_idx; + } + + return -EINVAL; +} +EXPORT_SYMBOL(cmdq_crypto_cap_find); + +/** + * cmdq_crypto_cfg_entry_write_key - Write a key into a crypto_cfg_entry + * + * Writes the key with the appropriate format - for AES_XTS, + * the first half of the key is copied as is, the second half is + * copied with an offset halfway into the cfg->crypto_key array. + * For the other supported crypto algs, the key is just copied. + * + * @cfg: The crypto config to write to + * @key: The key to write + * @cap: The crypto capability (which specifies the crypto alg and key size) + * + * Returns 0 on success, or -EINVAL + */ +static int cmdq_crypto_cfg_entry_write_key(union cmdq_crypto_cfg_entry *cfg, + const u8 *key, + union cmdq_crypto_cap_entry cap) +{ + size_t key_size_bytes = get_keysize_bytes(cap.key_size); + + if (key_size_bytes == 0) + return -EINVAL; + + switch (cap.algorithm_id) { + case CMDQ_CRYPTO_ALG_AES_XTS: + key_size_bytes *= 2; + if (key_size_bytes > CMDQ_CRYPTO_KEY_MAX_SIZE) + return -EINVAL; + + memcpy(cfg->crypto_key, key, key_size_bytes/2); + memcpy(cfg->crypto_key + CMDQ_CRYPTO_KEY_MAX_SIZE/2, + key + key_size_bytes/2, key_size_bytes/2); + return 0; + case CMDQ_CRYPTO_ALG_BITLOCKER_AES_CBC: + /* fall through */ + case CMDQ_CRYPTO_ALG_AES_ECB: + /* fall through */ + case CMDQ_CRYPTO_ALG_ESSIV_AES_CBC: + memcpy(cfg->crypto_key, key, key_size_bytes); + return 0; + } + + return -EINVAL; +} + +static void cmdq_program_key(struct cmdq_host *host, + const union cmdq_crypto_cfg_entry *cfg, + int slot) +{ + int i; + u32 slot_offset = host->crypto_cfg_register + slot * sizeof(*cfg); + + if (host->crypto_vops && host->crypto_vops->program_key) + host->crypto_vops->program_key(host, cfg, slot); + + /* Clear the dword 16 */ + cmdq_writel(host, 0, slot_offset + 16 * sizeof(cfg->reg_val[0])); + /* Ensure that CFGE is cleared before programming the key */ + wmb(); + for (i = 0; i < 16; i++) { + cmdq_writel(host, le32_to_cpu(cfg->reg_val[i]), + slot_offset + i * sizeof(cfg->reg_val[0])); + /* Spec says each dword in key must be written sequentially */ + wmb(); + } + /* Write dword 17 */ + cmdq_writel(host, le32_to_cpu(cfg->reg_val[17]), + slot_offset + 17 * sizeof(cfg->reg_val[0])); + /* Dword 16 must be written last */ + wmb(); + /* Write dword 16 */ + cmdq_writel(host, le32_to_cpu(cfg->reg_val[16]), + slot_offset + 16 * sizeof(cfg->reg_val[0])); + /*Ensure that dword 16 is written */ + wmb(); +} + +static void cmdq_crypto_clear_keyslot(struct cmdq_host *host, int slot) +{ + union cmdq_crypto_cfg_entry cfg = { {0} }; + + cmdq_program_key(host, &cfg, slot); +} + +static void cmdq_crypto_clear_all_keyslots(struct cmdq_host *host) +{ + int slot; + + for (slot = 0; slot < cmdq_num_keyslots(host); slot++) + cmdq_crypto_clear_keyslot(host, slot); +} + +static int cmdq_crypto_keyslot_program(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct cmdq_host *host = keyslot_manager_private(ksm); + int err = 0; + u8 data_unit_mask; + union cmdq_crypto_cfg_entry cfg; + int cap_idx; + + cap_idx = cmdq_crypto_cap_find(host, key->crypto_mode, + key->data_unit_size); + + if (!cmdq_is_crypto_enabled(host) || + !cmdq_keyslot_valid(host, slot) || + !cmdq_cap_idx_valid(host, cap_idx)) + return -EINVAL; + + data_unit_mask = get_data_unit_size_mask(key->data_unit_size); + + if (!(data_unit_mask & host->crypto_cap_array[cap_idx].sdus_mask)) + return -EINVAL; + + memset(&cfg, 0, sizeof(cfg)); + cfg.data_unit_size = data_unit_mask; + cfg.crypto_cap_idx = cap_idx; + cfg.config_enable |= CMDQ_CRYPTO_CONFIGURATION_ENABLE; + + err = cmdq_crypto_cfg_entry_write_key(&cfg, key->raw, + host->crypto_cap_array[cap_idx]); + if (err) + return err; + + cmdq_program_key(host, &cfg, slot); + + memzero_explicit(&cfg, sizeof(cfg)); + + return 0; +} + +static int cmdq_crypto_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct cmdq_host *host = keyslot_manager_private(ksm); + + if (!cmdq_is_crypto_enabled(host) || + !cmdq_keyslot_valid(host, slot)) + return -EINVAL; + + /* + * Clear the crypto cfg on the device. Clearing CFGE + * might not be sufficient, so just clear the entire cfg. + */ + cmdq_crypto_clear_keyslot(host, slot); + + return 0; +} + +/* Functions implementing eMMC v5.2 specification behaviour */ +void cmdq_crypto_enable_spec(struct cmdq_host *host) +{ + if (!cmdq_host_is_crypto_supported(host)) + return; + + host->caps |= CMDQ_CAP_CRYPTO_SUPPORT; +} +EXPORT_SYMBOL(cmdq_crypto_enable_spec); + +void cmdq_crypto_disable_spec(struct cmdq_host *host) +{ + host->caps &= ~CMDQ_CAP_CRYPTO_SUPPORT; +} +EXPORT_SYMBOL(cmdq_crypto_disable_spec); + +static const struct keyslot_mgmt_ll_ops cmdq_ksm_ops = { + .keyslot_program = cmdq_crypto_keyslot_program, + .keyslot_evict = cmdq_crypto_keyslot_evict, +}; + +enum blk_crypto_mode_num cmdq_crypto_blk_crypto_mode_num_for_alg_dusize( + enum cmdq_crypto_alg cmdq_crypto_alg, + enum cmdq_crypto_key_size key_size) +{ + /* + * Currently the only mode that eMMC and blk-crypto both support. + */ + if (cmdq_crypto_alg == CMDQ_CRYPTO_ALG_AES_XTS && + key_size == CMDQ_CRYPTO_KEY_SIZE_256) + return BLK_ENCRYPTION_MODE_AES_256_XTS; + + return BLK_ENCRYPTION_MODE_INVALID; +} + +/** + * cmdq_host_init_crypto - Read crypto capabilities, init crypto fields in host + * @host: Per adapter instance + * + * Returns 0 on success. Returns -ENODEV if such capabilities don't exist, and + * -ENOMEM upon OOM. + */ +int cmdq_host_init_crypto_spec(struct cmdq_host *host, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int cap_idx = 0; + int err = 0; + unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX]; + enum blk_crypto_mode_num blk_mode_num; + + /* Default to disabling crypto */ + host->caps &= ~CMDQ_CAP_CRYPTO_SUPPORT; + + if (!(cmdq_readl(host, CQCAP) & CQ_CAP_CS)) { + pr_err("%s no crypto capability\n", __func__); + err = -ENODEV; + goto out; + } + + /* + * Crypto Capabilities should never be 0, because the + * config_array_ptr > 04h. So we use a 0 value to indicate that + * crypto init failed, and can't be enabled. + */ + host->crypto_capabilities.reg_val = cmdq_readl(host, CQ_CCAP); + host->crypto_cfg_register = + (u32)host->crypto_capabilities.config_array_ptr * 0x100; + host->crypto_cap_array = + devm_kcalloc(mmc_dev(host->mmc), + host->crypto_capabilities.num_crypto_cap, + sizeof(host->crypto_cap_array[0]), GFP_KERNEL); + if (!host->crypto_cap_array) { + err = -ENOMEM; + pr_err("%s no memory cap\n", __func__); + goto out; + } + + memset(crypto_modes_supported, 0, sizeof(crypto_modes_supported)); + + /* + * Store all the capabilities now so that we don't need to repeatedly + * access the device each time we want to know its capabilities + */ + for (cap_idx = 0; cap_idx < host->crypto_capabilities.num_crypto_cap; + cap_idx++) { + host->crypto_cap_array[cap_idx].reg_val = + cpu_to_le32(cmdq_readl(host, + CQ_CRYPTOCAP + + cap_idx * sizeof(__le32))); + blk_mode_num = cmdq_crypto_blk_crypto_mode_num_for_alg_dusize( + host->crypto_cap_array[cap_idx].algorithm_id, + host->crypto_cap_array[cap_idx].key_size); + if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID) + continue; + crypto_modes_supported[blk_mode_num] |= + host->crypto_cap_array[cap_idx].sdus_mask * 512; + } + + cmdq_crypto_clear_all_keyslots(host); + + host->ksm = keyslot_manager_create(cmdq_num_keyslots(host), ksm_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS, + crypto_modes_supported, host); + + if (!host->ksm) { + err = -ENOMEM; + goto out_free_caps; + } + /* + * In case host controller supports cryptographic operations + * then, it uses 128bit task descriptor. Upper 64 bits of task + * descriptor would be used to pass crypto specific informaton. + */ + host->caps |= CMDQ_TASK_DESC_SZ_128; + + return 0; +out_free_caps: + devm_kfree(mmc_dev(host->mmc), host->crypto_cap_array); +out: + // TODO: print error? + /* Indicate that init failed by setting crypto_capabilities to 0 */ + host->crypto_capabilities.reg_val = 0; + return err; +} +EXPORT_SYMBOL(cmdq_host_init_crypto_spec); + +void cmdq_crypto_setup_rq_keyslot_manager_spec(struct cmdq_host *host, + struct request_queue *q) +{ + if (!cmdq_host_is_crypto_supported(host) || !q) + return; + + q->ksm = host->ksm; +} +EXPORT_SYMBOL(cmdq_crypto_setup_rq_keyslot_manager_spec); + +void cmdq_crypto_destroy_rq_keyslot_manager_spec(struct cmdq_host *host, + struct request_queue *q) +{ + keyslot_manager_destroy(host->ksm); +} +EXPORT_SYMBOL(cmdq_crypto_destroy_rq_keyslot_manager_spec); + +int cmdq_prepare_crypto_desc_spec(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx) +{ + struct bio_crypt_ctx *bc; + struct request *req = mrq->req; + + if (!req->bio || + !bio_crypt_should_process(req)) { + *ice_ctx = 0; + return 0; + } + if (WARN_ON(!cmdq_is_crypto_enabled(host))) { + /* + * Upper layer asked us to do inline encryption + * but that isn't enabled, so we fail this request. + */ + return -EINVAL; + } + + bc = req->bio->bi_crypt_context; + + if (!cmdq_keyslot_valid(host, bc->bc_keyslot)) + return -EINVAL; + + if (ice_ctx) { + *ice_ctx = DATA_UNIT_NUM(bc->bc_dun[0]) | + CRYPTO_CONFIG_INDEX(bc->bc_keyslot) | + CRYPTO_ENABLE(true); + } + + return 0; +} +EXPORT_SYMBOL(cmdq_prepare_crypto_desc_spec); + +/* Crypto Variant Ops Support */ + +void cmdq_crypto_enable(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->enable) + return host->crypto_vops->enable(host); + + return cmdq_crypto_enable_spec(host); +} + +void cmdq_crypto_disable(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->disable) + return host->crypto_vops->disable(host); + + return cmdq_crypto_disable_spec(host); +} + +int cmdq_host_init_crypto(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->host_init_crypto) + return host->crypto_vops->host_init_crypto(host, + &cmdq_ksm_ops); + + return cmdq_host_init_crypto_spec(host, &cmdq_ksm_ops); +} + +void cmdq_crypto_setup_rq_keyslot_manager(struct cmdq_host *host, + struct request_queue *q) +{ + if (host->crypto_vops && host->crypto_vops->setup_rq_keyslot_manager) + return host->crypto_vops->setup_rq_keyslot_manager(host, q); + + return cmdq_crypto_setup_rq_keyslot_manager_spec(host, q); +} + +void cmdq_crypto_destroy_rq_keyslot_manager(struct cmdq_host *host, + struct request_queue *q) +{ + if (host->crypto_vops && host->crypto_vops->destroy_rq_keyslot_manager) + return host->crypto_vops->destroy_rq_keyslot_manager(host, q); + + return cmdq_crypto_destroy_rq_keyslot_manager_spec(host, q); +} + +int cmdq_crypto_get_ctx(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx) +{ + if (host->crypto_vops && host->crypto_vops->prepare_crypto_desc) + return host->crypto_vops->prepare_crypto_desc(host, mrq, + ice_ctx); + + return cmdq_prepare_crypto_desc_spec(host, mrq, ice_ctx); +} + +int cmdq_complete_crypto_desc(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx) +{ + if (host->crypto_vops && host->crypto_vops->complete_crypto_desc) + return host->crypto_vops->complete_crypto_desc(host, mrq, + ice_ctx); + + return 0; +} + +void cmdq_crypto_debug(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->debug) + host->crypto_vops->debug(host); +} + +void cmdq_crypto_set_vops(struct cmdq_host *host, + struct cmdq_host_crypto_variant_ops *crypto_vops) +{ + if (host) + host->crypto_vops = crypto_vops; +} + +int cmdq_crypto_suspend(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->suspend) + return host->crypto_vops->suspend(host); + + return 0; +} + +int cmdq_crypto_resume(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->resume) + return host->crypto_vops->resume(host); + + return 0; +} + +int cmdq_crypto_reset(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->reset) + return host->crypto_vops->reset(host); + + return 0; +} + +int cmdq_crypto_recovery_finish(struct cmdq_host *host) +{ + if (host->crypto_vops && host->crypto_vops->recovery_finish) + return host->crypto_vops->recovery_finish(host); + + /* Reset/Recovery might clear all keys, so reprogram all the keys. */ + keyslot_manager_reprogram_all_keys(host->ksm); + + return 0; +} diff --git a/drivers/mmc/host/cmdq_hci-crypto.h b/drivers/mmc/host/cmdq_hci-crypto.h new file mode 100644 index 0000000000000000000000000000000000000000..8fb44d1eff8bd4a5202a789ddf50db33753cc978 --- /dev/null +++ b/drivers/mmc/host/cmdq_hci-crypto.h @@ -0,0 +1,188 @@ +/* Copyright 2019 Google LLC + * + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CMDQ_CRYPTO_H +#define _CMDQ_CRYPTO_H + +#ifdef CONFIG_MMC_CQ_HCI_CRYPTO +#include +#include "cmdq_hci.h" + +static inline int cmdq_num_keyslots(struct cmdq_host *host) +{ + return host->crypto_capabilities.config_count + 1; +} + +static inline bool cmdq_keyslot_valid(struct cmdq_host *host, + unsigned int slot) +{ + /* + * The actual number of configurations supported is (CFGC+1), so slot + * numbers range from 0 to config_count inclusive. + */ + return slot < cmdq_num_keyslots(host); +} + +static inline bool cmdq_host_is_crypto_supported(struct cmdq_host *host) +{ + return host->crypto_capabilities.reg_val != 0; +} + +static inline bool cmdq_is_crypto_enabled(struct cmdq_host *host) +{ + return host->caps & CMDQ_CAP_CRYPTO_SUPPORT; +} + +/* Functions implementing eMMC v5.2 specification behaviour */ +int cmdq_prepare_crypto_desc_spec(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx); + +void cmdq_crypto_enable_spec(struct cmdq_host *host); + +void cmdq_crypto_disable_spec(struct cmdq_host *host); + +int cmdq_host_init_crypto_spec(struct cmdq_host *host, + const struct keyslot_mgmt_ll_ops *ksm_ops); + +void cmdq_crypto_setup_rq_keyslot_manager_spec(struct cmdq_host *host, + struct request_queue *q); + +void cmdq_crypto_destroy_rq_keyslot_manager_spec(struct cmdq_host *host, + struct request_queue *q); + +void cmdq_crypto_set_vops(struct cmdq_host *host, + struct cmdq_host_crypto_variant_ops *crypto_vops); + +/* Crypto Variant Ops Support */ + +void cmdq_crypto_enable(struct cmdq_host *host); + +void cmdq_crypto_disable(struct cmdq_host *host); + +int cmdq_host_init_crypto(struct cmdq_host *host); + +void cmdq_crypto_setup_rq_keyslot_manager(struct cmdq_host *host, + struct request_queue *q); + +void cmdq_crypto_destroy_rq_keyslot_manager(struct cmdq_host *host, + struct request_queue *q); + +int cmdq_crypto_get_ctx(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx); + +int cmdq_complete_crypto_desc(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx); + +void cmdq_crypto_debug(struct cmdq_host *host); + +int cmdq_crypto_suspend(struct cmdq_host *host); + +int cmdq_crypto_resume(struct cmdq_host *host); + +int cmdq_crypto_reset(struct cmdq_host *host); + +int cmdq_crypto_recovery_finish(struct cmdq_host *host); + +int cmdq_crypto_cap_find(void *host_p, enum blk_crypto_mode_num crypto_mode, + unsigned int data_unit_size); + +#else /* CONFIG_MMC_CQ_HCI_CRYPTO */ + +static inline bool cmdq_keyslot_valid(struct cmdq_host *host, + unsigned int slot) +{ + return false; +} + +static inline bool cmdq_host_is_crypto_supported(struct cmdq_host *host) +{ + return false; +} + +static inline bool cmdq_is_crypto_enabled(struct cmdq_host *host) +{ + return false; +} + +static inline void cmdq_crypto_enable(struct cmdq_host *host) { } + +static inline int cmdq_crypto_cap_find(void *host_p, + enum blk_crypto_mode_num crypto_mode, + unsigned int data_unit_size) +{ + return 0; +} + +static inline void cmdq_crypto_disable(struct cmdq_host *host) { } + +static inline int cmdq_host_init_crypto(struct cmdq_host *host) +{ + return 0; +} + +static inline void cmdq_crypto_setup_rq_keyslot_manager( + struct cmdq_host *host, + struct request_queue *q) { } + +static inline void +cmdq_crypto_destroy_rq_keyslot_manager(struct cmdq_host *host, + struct request_queue *q) { } + +static inline int cmdq_crypto_get_ctx(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx) +{ + *ice_ctx = 0; + return 0; +} + +static inline int cmdq_complete_crypto_desc(struct cmdq_host *host, + struct mmc_request *mrq, + u64 *ice_ctx) +{ + return 0; +} + +static inline void cmdq_crypto_debug(struct cmdq_host *host) { } + +static inline void cmdq_crypto_set_vops(struct cmdq_host *host, + struct cmdq_host_crypto_variant_ops *crypto_vops) { } + +static inline int cmdq_crypto_suspend(struct cmdq_host *host) +{ + return 0; +} + +static inline int cmdq_crypto_resume(struct cmdq_host *host) +{ + return 0; +} + +static inline int cmdq_crypto_reset(struct cmdq_host *host) +{ + return 0; +} + +static inline int cmdq_crypto_recovery_finish(struct cmdq_host *host) +{ + return 0; +} + +#endif /* CONFIG_MMC_CMDQ_CRYPTO */ +#endif /* _CMDQ_CRYPTO_H */ + + diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 8571e3171c0cc5c0d58f268a6352cc05c9106325..2d182bcb401f12edb517609eb79ecbcff4b14958 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,8 +29,10 @@ #include #include "cmdq_hci.h" +#include "cmdq_hci-crypto.h" #include "sdhci.h" #include "sdhci-msm.h" +#include "../core/queue.h" #define DCMD_SLOT 31 #define NUM_SLOTS 32 @@ -277,6 +279,8 @@ static void cmdq_dumpregs(struct cmdq_host *cq_host) cmdq_readl(cq_host, CQ_VENDOR_CFG + offset)); pr_err(DRV_NAME ": ===========================================\n"); + cmdq_crypto_debug(cq_host); + cmdq_dump_task_history(cq_host); if (cq_host->ops->dump_vendor_regs) cq_host->ops->dump_vendor_regs(mmc); @@ -376,7 +380,6 @@ static int cmdq_enable(struct mmc_host *mmc) { int err = 0; u32 cqcfg; - u32 cqcap = 0; bool dcmd_enable; struct cmdq_host *cq_host = mmc_cmdq_private(mmc); @@ -405,18 +408,10 @@ static int cmdq_enable(struct mmc_host *mmc) cqcfg = ((cq_host->caps & CMDQ_TASK_DESC_SZ_128 ? CQ_TASK_DESC_SZ : 0) | (dcmd_enable ? CQ_DCMD : 0)); - cqcap = cmdq_readl(cq_host, CQCAP); - if (cqcap & CQCAP_CS) { - /* - * In case host controller supports cryptographic operations - * then, it uses 128bit task descriptor. Upper 64 bits of task - * descriptor would be used to pass crypto specific informaton. - */ - cq_host->caps |= CMDQ_CAP_CRYPTO_SUPPORT | - CMDQ_TASK_DESC_SZ_128; + if (cmdq_host_is_crypto_supported(cq_host)) { + cmdq_crypto_enable(cq_host); cqcfg |= CQ_ICE_ENABLE; - /* - * For SDHC v5.0 onwards, ICE 3.0 specific registers are added + /* For SDHC v5.0 onwards, ICE 3.0 specific registers are added * in CQ register space, due to which few CQ registers are * shifted. Set offset_changed boolean to use updated address. */ @@ -492,6 +487,9 @@ static void cmdq_disable_nosync(struct mmc_host *mmc, bool soft) { struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); + if (cmdq_host_is_crypto_supported(cq_host)) + cmdq_crypto_disable(cq_host); + if (soft) { cmdq_writel(cq_host, cmdq_readl( cq_host, CQCFG) & ~(CQ_ENABLE), @@ -531,6 +529,8 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft) cmdq_disable(mmc, true); + cmdq_crypto_reset(cq_host); + if (cq_host->ops->reset) { ret = cq_host->ops->reset(mmc); if (ret) { @@ -560,6 +560,29 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft) mmc_host_clr_cq_disable(mmc); } +static inline void cmdq_prep_crypto_desc(struct cmdq_host *cq_host, + u64 *task_desc, u64 ice_ctx) +{ + u64 *ice_desc = NULL; + + if (cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) { + /* + * Get the address of ice context for the given task descriptor. + * ice context is present in the upper 64bits of task descriptor + * ice_conext_base_address = task_desc + 8-bytes + */ + ice_desc = (u64 *)((u8 *)task_desc + + CQ_TASK_DESC_ICE_PARAM_OFFSET); + memset(ice_desc, 0, CQ_TASK_DESC_ICE_PARAMS_SIZE); + + /* + * Assign upper 64bits data of task descritor with ice context + */ + if (ice_ctx) + *ice_desc = ice_ctx; + } +} + static void cmdq_prep_task_desc(struct mmc_request *mrq, u64 *data, bool intr, bool qbr) { @@ -738,30 +761,6 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc, upper_32_bits(*task_desc)); } -static inline -void cmdq_prep_crypto_desc(struct cmdq_host *cq_host, u64 *task_desc, - u64 ice_ctx) -{ - u64 *ice_desc = NULL; - - if (cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) { - /* - * Get the address of ice context for the given task descriptor. - * ice context is present in the upper 64bits of task descriptor - * ice_conext_base_address = task_desc + 8-bytes - */ - ice_desc = (__le64 *)((u8 *)task_desc + - CQ_TASK_DESC_TASK_PARAMS_SIZE); - memset(ice_desc, 0, CQ_TASK_DESC_ICE_PARAMS_SIZE); - - /* - * Assign upper 64bits data of task descritor with ice context - */ - if (ice_ctx) - *ice_desc = cpu_to_le64(ice_ctx); - } -} - static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -804,14 +803,12 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) goto ring_doorbell; } - if (cq_host->ops->crypto_cfg) { - err = cq_host->ops->crypto_cfg(mmc, mrq, tag, &ice_ctx); - if (err) { - mmc->err_stats[MMC_ERR_ICE_CFG]++; - pr_err("%s: failed to configure crypto: err %d tag %d\n", - mmc_hostname(mmc), err, tag); - goto ice_err; - } + err = cmdq_crypto_get_ctx(cq_host, mrq, &ice_ctx); + if (err) { + mmc->err_stats[MMC_ERR_ICE_CFG]++; + pr_err("%s: failed to retrieve crypto ctx for tag %d\n", + mmc_hostname(mmc), tag); + goto ice_err; } task_desc = (__le64 __force *)get_desc(cq_host, tag); @@ -828,7 +825,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) if (err) { pr_err("%s: %s: failed to setup tx desc: %d\n", mmc_hostname(mmc), __func__, err); - goto desc_err; + goto out; } cq_host->mrq_slot[tag] = mrq; @@ -850,20 +847,10 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq) return err; -desc_err: - if (cq_host->ops->crypto_cfg_end) { - err = cq_host->ops->crypto_cfg_end(mmc, mrq); - if (err) { - pr_err("%s: failed to end ice config: err %d tag %d\n", - mmc_hostname(mmc), err, tag); - } - } - if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && - cq_host->ops->crypto_cfg_reset) - cq_host->ops->crypto_cfg_reset(mmc, tag); ice_err: if (err) cmdq_runtime_pm_put(cq_host); + out: return err; } @@ -873,7 +860,6 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) struct mmc_request *mrq; struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); int offset = 0; - int err = 0; if (cq_host->offset_changed) offset = CQ_V5_VENDOR_CFG; @@ -881,6 +867,8 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) if (tag == cq_host->dcmd_slot) mrq->cmd->resp[0] = cmdq_readl(cq_host, CQCRDCT); + cmdq_complete_crypto_desc(cq_host, mrq, NULL); + if (mrq->cmdq_req->cmdq_req_flags & DCMD) cmdq_writel(cq_host, cmdq_readl(cq_host, CQ_VENDOR_CFG + offset) | @@ -888,18 +876,6 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) cmdq_runtime_pm_put(cq_host); - if (!(mrq->cmdq_req->cmdq_req_flags & DCMD)) { - if (cq_host->ops->crypto_cfg_end) { - err = cq_host->ops->crypto_cfg_end(mmc, mrq); - if (err) { - pr_err("%s: failed to end ice config: err %d tag %d\n", - mmc_hostname(mmc), err, tag); - } - } - } - if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && - cq_host->ops->crypto_cfg_reset) - cq_host->ops->crypto_cfg_reset(mmc, tag); mrq->done(mrq); } @@ -1360,6 +1336,20 @@ static int cmdq_late_init(struct mmc_host *mmc) return 0; } +static void cqhci_crypto_update_queue(struct mmc_host *mmc, + struct request_queue *queue) +{ + struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); + + if (cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) { + if (queue) + cmdq_crypto_setup_rq_keyslot_manager(cq_host, queue); + else + pr_err("%s can not register keyslot manager\n", + __func__); + } +} + static const struct mmc_cmdq_host_ops cmdq_host_ops = { .init = cmdq_late_init, .enable = cmdq_enable, @@ -1369,6 +1359,7 @@ static const struct mmc_cmdq_host_ops cmdq_host_ops = { .halt = cmdq_halt, .reset = cmdq_reset, .dumpstate = cmdq_dumpstate, + .cqe_crypto_update_queue = cqhci_crypto_update_queue, }; struct cmdq_host *cmdq_pltfm_init(struct platform_device *pdev) @@ -1423,6 +1414,10 @@ int cmdq_init(struct cmdq_host *cq_host, struct mmc_host *mmc, if (!cq_host->mrq_slot) return -ENOMEM; + err = cmdq_host_init_crypto(cq_host); + if (err) + pr_err("%s: CMDQ Crypto init failed err %d\n", err); + init_completion(&cq_host->halt_comp); return err; } diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h index 03c78d7a891c80b9c82b62b12d70b1fecffa29de..79e7acc69e6aba99d809e3afe9b79e64e8938dd2 100644 --- a/drivers/mmc/host/cmdq_hci.h +++ b/drivers/mmc/host/cmdq_hci.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,13 +12,17 @@ #ifndef LINUX_MMC_CQ_HCI_H #define LINUX_MMC_CQ_HCI_H #include +#include +#include /* registers */ /* version */ #define CQVER 0x00 /* capabilities */ #define CQCAP 0x04 -#define CQCAP_CS (1 << 28) +#define CQ_CAP_CS (1 << 28) +#define CQ_CCAP 0x100 +#define CQ_CRYPTOCAP 0x104 /* configuration */ #define CQCFG 0x08 #define CQ_DCMD 0x00001000 @@ -144,6 +148,14 @@ #define DAT_LENGTH(x) ((x & 0xFFFF) << 16) #define DAT_ADDR_LO(x) ((x & 0xFFFFFFFF) << 32) #define DAT_ADDR_HI(x) ((x & 0xFFFFFFFF) << 0) +#define DATA_UNIT_NUM(x) (((u64)(x) & 0xFFFFFFFF) << 0) +#define CRYPTO_CONFIG_INDEX(x) (((u64)(x) & 0xFF) << 32) +#define CRYPTO_ENABLE(x) (((u64)(x) & 0x1) << 47) + +/* ICE context is present in the upper 64bits of task descriptor */ +#define CQ_TASK_DESC_ICE_PARAM_OFFSET 8 +/* ICE descriptor size */ +#define CQ_TASK_DESC_ICE_PARAMS_SIZE 8 /* * Add new macro for updated CQ vendor specific @@ -153,8 +165,88 @@ #define CQ_VENDOR_CFG 0x100 #define CMDQ_SEND_STATUS_TRIGGER (1 << 31) -#define CQ_TASK_DESC_TASK_PARAMS_SIZE 8 -#define CQ_TASK_DESC_ICE_PARAMS_SIZE 8 +struct cmdq_host; + +/* CCAP - Crypto Capability 100h */ +union cmdq_crypto_capabilities { + __le32 reg_val; + struct { + u8 num_crypto_cap; + u8 config_count; + u8 reserved; + u8 config_array_ptr; + }; +}; + +enum cmdq_crypto_key_size { + CMDQ_CRYPTO_KEY_SIZE_INVALID = 0x0, + CMDQ_CRYPTO_KEY_SIZE_128 = 0x1, + CMDQ_CRYPTO_KEY_SIZE_192 = 0x2, + CMDQ_CRYPTO_KEY_SIZE_256 = 0x3, + CMDQ_CRYPTO_KEY_SIZE_512 = 0x4, +}; + +enum cmdq_crypto_alg { + CMDQ_CRYPTO_ALG_AES_XTS = 0x0, + CMDQ_CRYPTO_ALG_BITLOCKER_AES_CBC = 0x1, + CMDQ_CRYPTO_ALG_AES_ECB = 0x2, + CMDQ_CRYPTO_ALG_ESSIV_AES_CBC = 0x3, +}; + +/* x-CRYPTOCAP - Crypto Capability X */ +union cmdq_crypto_cap_entry { + __le32 reg_val; + struct { + u8 algorithm_id; + u8 sdus_mask; /* Supported data unit size mask */ + u8 key_size; + u8 reserved; + }; +}; + +#define CMDQ_CRYPTO_CONFIGURATION_ENABLE (1 << 7) +#define CMDQ_CRYPTO_KEY_MAX_SIZE 64 + +/* x-CRYPTOCFG - Crypto Configuration X */ +union cmdq_crypto_cfg_entry { + __le32 reg_val[32]; + struct { + u8 crypto_key[CMDQ_CRYPTO_KEY_MAX_SIZE]; + u8 data_unit_size; + u8 crypto_cap_idx; + u8 reserved_1; + u8 config_enable; + u8 reserved_multi_host; + u8 reserved_2; + u8 vsb[2]; + u8 reserved_3[56]; + }; +}; + +struct cmdq_host_crypto_variant_ops { + void (*setup_rq_keyslot_manager)(struct cmdq_host *host, + struct request_queue *q); + void (*destroy_rq_keyslot_manager)(struct cmdq_host *host, + struct request_queue *q); +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + int (*host_init_crypto)(struct cmdq_host *host, + const struct keyslot_mgmt_ll_ops *ksm_ops); +#endif + void (*enable)(struct cmdq_host *host); + void (*disable)(struct cmdq_host *host); + int (*suspend)(struct cmdq_host *host); + int (*resume)(struct cmdq_host *host); + int (*debug)(struct cmdq_host *host); + int (*prepare_crypto_desc)(struct cmdq_host *host, + struct mmc_request *mrq, u64 *ice_ctx); + int (*complete_crypto_desc)(struct cmdq_host *host, + struct mmc_request *mrq, u64 *ice_ctx); + int (*reset)(struct cmdq_host *host); + int (*recovery_finish)(struct cmdq_host *host); + int (*program_key)(struct cmdq_host *host, + const union cmdq_crypto_cfg_entry *cfg, int slot); + void *priv; +}; struct task_history { u64 task; @@ -164,6 +256,7 @@ struct task_history { struct cmdq_host { const struct cmdq_host_ops *ops; void __iomem *mmio; + void __iomem *icemmio; struct mmc_host *mmc; /* 64 bit DMA */ @@ -208,6 +301,15 @@ struct cmdq_host { struct completion halt_comp; struct mmc_request **mrq_slot; void *private; + const struct cmdq_host_crypto_variant_ops *crypto_vops; +#ifdef CONFIG_MMC_CQ_HCI_CRYPTO + union cmdq_crypto_capabilities crypto_capabilities; + union cmdq_crypto_cap_entry *crypto_cap_array; + u32 crypto_cfg_register; +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct keyslot_manager *ksm; +#endif /* CONFIG_BLK_INLINE_ENCRYPTION */ +#endif /* CONFIG_SCSI_CQHCI_CRYPTO */ }; struct cmdq_host_ops { @@ -222,10 +324,6 @@ struct cmdq_host_ops { void (*enhanced_strobe_mask)(struct mmc_host *mmc, bool set); int (*reset)(struct mmc_host *mmc); void (*post_cqe_halt)(struct mmc_host *mmc); - int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq, - u32 slot, u64 *ice_ctx); - int (*crypto_cfg_end)(struct mmc_host *mmc, struct mmc_request *mrq); - void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot); }; static inline void cmdq_writel(struct cmdq_host *host, u32 val, int reg) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index ea254d00541f12c0cc9b0b8bbf0db885febd3cb1..24795454d106617e6614656b4a9d4fa4b85b095f 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1154,17 +1154,22 @@ static void mmc_spi_initsequence(struct mmc_spi_host *host) * SPI protocol. Another is that when chipselect is released while * the card returns BUSY status, the clock must issue several cycles * with chipselect high before the card will stop driving its output. + * + * SPI_CS_HIGH means "asserted" here. In some cases like when using + * GPIOs for chip select, SPI_CS_HIGH is set but this will be logically + * inverted by gpiolib, so if we want to ascertain to drive it high + * we should toggle the default with an XOR as we do here. */ - host->spi->mode |= SPI_CS_HIGH; + host->spi->mode ^= SPI_CS_HIGH; if (spi_setup(host->spi) != 0) { /* Just warn; most cards work without it. */ dev_warn(&host->spi->dev, "can't change chip-select polarity\n"); - host->spi->mode &= ~SPI_CS_HIGH; + host->spi->mode ^= SPI_CS_HIGH; } else { mmc_spi_readbytes(host, 18); - host->spi->mode &= ~SPI_CS_HIGH; + host->spi->mode ^= SPI_CS_HIGH; if (spi_setup(host->spi) != 0) { /* Wot, we can't get the same setup we had before? */ dev_err(&host->spi->dev, diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c deleted file mode 100644 index 317d8c3bfb0e7b56acae83812be91c09a6cec206..0000000000000000000000000000000000000000 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sdhci-msm-ice.h" - -static void sdhci_msm_ice_error_cb(void *host_ctrl, u32 error) -{ - struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl; - - dev_err(&msm_host->pdev->dev, "%s: Error in ice operation 0x%x", - __func__, error); - - if (msm_host->ice.state == SDHCI_MSM_ICE_STATE_ACTIVE) - msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED; -} - -static struct platform_device *sdhci_msm_ice_get_pdevice(struct device *dev) -{ - struct device_node *node; - struct platform_device *ice_pdev = NULL; - - node = of_parse_phandle(dev->of_node, SDHC_MSM_CRYPTO_LABEL, 0); - if (!node) { - dev_dbg(dev, "%s: sdhc-msm-crypto property not specified\n", - __func__); - goto out; - } - ice_pdev = qcom_ice_get_pdevice(node); -out: - return ice_pdev; -} - -static -struct qcom_ice_variant_ops *sdhci_msm_ice_get_vops(struct device *dev) -{ - struct qcom_ice_variant_ops *ice_vops = NULL; - struct device_node *node; - - node = of_parse_phandle(dev->of_node, SDHC_MSM_CRYPTO_LABEL, 0); - if (!node) { - dev_dbg(dev, "%s: sdhc-msm-crypto property not specified\n", - __func__); - goto out; - } - ice_vops = qcom_ice_get_variant_ops(node); - of_node_put(node); -out: - return ice_vops; -} - -static -void sdhci_msm_enable_ice_hci(struct sdhci_host *host, bool enable) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - u32 config = 0; - u32 ice_cap = 0; - - /* - * Enable the cryptographic support inside SDHC. - * This is a global config which needs to be enabled - * all the time. - * Only when it it is enabled, the ICE_HCI capability - * will get reflected in CQCAP register. - */ - config = readl_relaxed(host->ioaddr + HC_VENDOR_SPECIFIC_FUNC4); - - if (enable) - config &= ~DISABLE_CRYPTO; - else - config |= DISABLE_CRYPTO; - writel_relaxed(config, host->ioaddr + HC_VENDOR_SPECIFIC_FUNC4); - - /* - * CQCAP register is in different register space from above - * ice global enable register. So a mb() is required to ensure - * above write gets completed before reading the CQCAP register. - */ - mb(); - - /* - * Check if ICE HCI capability support is present - * If present, enable it. - */ - ice_cap = readl_relaxed(msm_host->cryptoio + ICE_CQ_CAPABILITIES); - if (ice_cap & ICE_HCI_SUPPORT) { - config = readl_relaxed(msm_host->cryptoio + ICE_CQ_CONFIG); - - if (enable) - config |= CRYPTO_GENERAL_ENABLE; - else - config &= ~CRYPTO_GENERAL_ENABLE; - writel_relaxed(config, msm_host->cryptoio + ICE_CQ_CONFIG); - } -} - -int sdhci_msm_ice_get_dev(struct sdhci_host *host) -{ - struct device *sdhc_dev; - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - - if (!msm_host || !msm_host->pdev) { - pr_err("%s: invalid msm_host %p or msm_host->pdev\n", - __func__, msm_host); - return -EINVAL; - } - - sdhc_dev = &msm_host->pdev->dev; - msm_host->ice.vops = sdhci_msm_ice_get_vops(sdhc_dev); - msm_host->ice.pdev = sdhci_msm_ice_get_pdevice(sdhc_dev); - - if (msm_host->ice.pdev == ERR_PTR(-EPROBE_DEFER)) { - dev_err(sdhc_dev, "%s: ICE device not probed yet\n", - __func__); - msm_host->ice.pdev = NULL; - msm_host->ice.vops = NULL; - return -EPROBE_DEFER; - } - - if (!msm_host->ice.pdev) { - dev_dbg(sdhc_dev, "%s: invalid platform device\n", __func__); - msm_host->ice.vops = NULL; - return -ENODEV; - } - if (!msm_host->ice.vops) { - dev_dbg(sdhc_dev, "%s: invalid ice vops\n", __func__); - msm_host->ice.pdev = NULL; - return -ENODEV; - } - msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED; - return 0; -} - -static -int sdhci_msm_ice_pltfm_init(struct sdhci_msm_host *msm_host) -{ - struct resource *ice_memres = NULL; - struct platform_device *pdev = msm_host->pdev; - int err = 0; - - if (!msm_host->ice_hci_support) - goto out; - /* - * ICE HCI registers are present in cmdq register space. - * So map the cmdq mem for accessing ICE HCI registers. - */ - ice_memres = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "cmdq_mem"); - if (!ice_memres) { - dev_err(&pdev->dev, "Failed to get iomem resource for ice\n"); - err = -EINVAL; - goto out; - } - msm_host->cryptoio = devm_ioremap(&pdev->dev, - ice_memres->start, - resource_size(ice_memres)); - if (!msm_host->cryptoio) { - dev_err(&pdev->dev, "Failed to remap registers\n"); - err = -ENOMEM; - } -out: - return err; -} - -int sdhci_msm_ice_init(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - - if (msm_host->ice.vops->init) { - err = sdhci_msm_ice_pltfm_init(msm_host); - if (err) - goto out; - - if (msm_host->ice_hci_support) - sdhci_msm_enable_ice_hci(host, true); - - err = msm_host->ice.vops->init(msm_host->ice.pdev, - msm_host, - sdhci_msm_ice_error_cb); - if (err) { - pr_err("%s: ice init err %d\n", - mmc_hostname(host->mmc), err); - sdhci_msm_ice_print_regs(host); - if (msm_host->ice_hci_support) - sdhci_msm_enable_ice_hci(host, false); - goto out; - } - msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE; - } - -out: - return err; -} - -void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot) -{ - writel_relaxed(SDHCI_MSM_ICE_ENABLE_BYPASS, - host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot); -} - -static -int sdhci_msm_ice_get_cfg(struct sdhci_msm_host *msm_host, struct request *req, - unsigned int *bypass, short *key_index) -{ - int err = 0; - struct ice_data_setting ice_set; - - memset(&ice_set, 0, sizeof(struct ice_data_setting)); - if (msm_host->ice.vops->config_start) { - err = msm_host->ice.vops->config_start( - msm_host->ice.pdev, - req, &ice_set, false); - if (err) { - pr_err("%s: ice config failed %d\n", - mmc_hostname(msm_host->mmc), err); - return err; - } - } - /* if writing data command */ - if (rq_data_dir(req) == WRITE) - *bypass = ice_set.encr_bypass ? - SDHCI_MSM_ICE_ENABLE_BYPASS : - SDHCI_MSM_ICE_DISABLE_BYPASS; - /* if reading data command */ - else if (rq_data_dir(req) == READ) - *bypass = ice_set.decr_bypass ? - SDHCI_MSM_ICE_ENABLE_BYPASS : - SDHCI_MSM_ICE_DISABLE_BYPASS; - *key_index = ice_set.crypto_data.key_index; - return err; -} - -static -void sdhci_msm_ice_update_cfg(struct sdhci_host *host, u64 lba, u32 slot, - unsigned int bypass, short key_index, u32 cdu_sz) -{ - unsigned int ctrl_info_val = 0; - - /* Configure ICE index */ - ctrl_info_val = - (key_index & - MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX) - << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX; - - /* Configure data unit size of transfer request */ - ctrl_info_val |= - (cdu_sz & - MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU) - << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU; - - /* Configure ICE bypass mode */ - ctrl_info_val |= - (bypass & MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS) - << OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS; - - writel_relaxed((lba & 0xFFFFFFFF), - host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n + 16 * slot); - writel_relaxed(((lba >> 32) & 0xFFFFFFFF), - host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n + 16 * slot); - writel_relaxed(ctrl_info_val, - host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n + 16 * slot); - /* Ensure ICE registers are configured before issuing SDHCI request */ - mb(); -} - -static inline -void sdhci_msm_ice_hci_update_cmdq_cfg(u64 dun, unsigned int bypass, - short key_index, u64 *ice_ctx) -{ - /* - * The naming convention got changed between ICE2.0 and ICE3.0 - * registers fields. Below is the equivalent names for - * ICE3.0 Vs ICE2.0: - * Data Unit Number(DUN) == Logical Base address(LBA) - * Crypto Configuration index (CCI) == Key Index - * Crypto Enable (CE) == !BYPASS - */ - if (ice_ctx) - *ice_ctx = DATA_UNIT_NUM(dun) | - CRYPTO_CONFIG_INDEX(key_index) | - CRYPTO_ENABLE(!bypass); -} - -static -void sdhci_msm_ice_hci_update_noncq_cfg(struct sdhci_host *host, - u64 dun, unsigned int bypass, short key_index) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - unsigned int crypto_params = 0; - /* - * The naming convention got changed between ICE2.0 and ICE3.0 - * registers fields. Below is the equivalent names for - * ICE3.0 Vs ICE2.0: - * Data Unit Number(DUN) == Logical Base address(LBA) - * Crypto Configuration index (CCI) == Key Index - * Crypto Enable (CE) == !BYPASS - */ - /* Configure ICE bypass mode */ - crypto_params |= - ((!bypass) & MASK_SDHCI_MSM_ICE_HCI_PARAM_CE) - << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE; - /* Configure Crypto Configure Index (CCI) */ - crypto_params |= (key_index & - MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI) - << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI; - - writel_relaxed((crypto_params & 0xFFFFFFFF), - msm_host->cryptoio + ICE_NONCQ_CRYPTO_PARAMS); - - /* Update DUN */ - writel_relaxed((dun & 0xFFFFFFFF), - msm_host->cryptoio + ICE_NONCQ_CRYPTO_DUN); - /* Ensure ICE registers are configured before issuing SDHCI request */ - mb(); -} - -int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, - u32 slot) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - short key_index = 0; - u64 dun = 0; - unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS; - u32 cdu_sz = SDHCI_MSM_ICE_TR_DATA_UNIT_512_B; - struct request *req; - - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - WARN_ON(!mrq); - if (!mrq) - return -EINVAL; - req = mrq->req; - if (req && req->bio) { -#ifdef CONFIG_PFK - if (bio_dun(req->bio)) { - dun = bio_dun(req->bio); - cdu_sz = SDHCI_MSM_ICE_TR_DATA_UNIT_4_KB; - } else { - dun = req->__sector; - } -#else - dun = req->__sector; -#endif - err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index); - if (err) - return err; - pr_debug("%s: %s: slot %d bypass %d key_index %d\n", - mmc_hostname(host->mmc), - (rq_data_dir(req) == WRITE) ? "WRITE" : "READ", - slot, bypass, key_index); - } - - if (msm_host->ice_hci_support) { - /* For ICE HCI / ICE3.0 */ - sdhci_msm_ice_hci_update_noncq_cfg(host, dun, bypass, - key_index); - } else { - /* For ICE versions earlier to ICE3.0 */ - sdhci_msm_ice_update_cfg(host, dun, slot, bypass, key_index, - cdu_sz); - } - return 0; -} - -int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, - struct mmc_request *mrq, u32 slot, u64 *ice_ctx) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - short key_index = 0; - u64 dun = 0; - unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS; - struct request *req; - u32 cdu_sz = SDHCI_MSM_ICE_TR_DATA_UNIT_512_B; - - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - WARN_ON(!mrq); - if (!mrq) - return -EINVAL; - req = mrq->req; - if (req && req->bio) { -#ifdef CONFIG_PFK - if (bio_dun(req->bio)) { - dun = bio_dun(req->bio); - cdu_sz = SDHCI_MSM_ICE_TR_DATA_UNIT_4_KB; - } else { - dun = req->__sector; - } -#else - dun = req->__sector; -#endif - err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index); - if (err) - return err; - pr_debug("%s: %s: slot %d bypass %d key_index %d\n", - mmc_hostname(host->mmc), - (rq_data_dir(req) == WRITE) ? "WRITE" : "READ", - slot, bypass, key_index); - } - - if (msm_host->ice_hci_support) { - /* For ICE HCI / ICE3.0 */ - sdhci_msm_ice_hci_update_cmdq_cfg(dun, bypass, key_index, - ice_ctx); - } else { - /* For ICE versions earlier to ICE3.0 */ - sdhci_msm_ice_update_cfg(host, dun, slot, bypass, key_index, - cdu_sz); - } - return 0; -} - -int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - struct request *req; - - if (!host->is_crypto_en) - return 0; - - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - req = mrq->req; - if (req) { - if (msm_host->ice.vops->config_end) { - err = msm_host->ice.vops->config_end(req); - if (err) { - pr_err("%s: ice config end failed %d\n", - mmc_hostname(host->mmc), err); - return err; - } - } - } - - return 0; -} - -int sdhci_msm_ice_reset(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state before reset %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - if (msm_host->ice.vops->reset) { - err = msm_host->ice.vops->reset(msm_host->ice.pdev); - if (err) { - pr_err("%s: ice reset failed %d\n", - mmc_hostname(host->mmc), err); - sdhci_msm_ice_print_regs(host); - return err; - } - } - - /* If ICE HCI support is present then re-enable it */ - if (msm_host->ice_hci_support) - sdhci_msm_enable_ice_hci(host, true); - - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state after reset %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - return 0; -} - -int sdhci_msm_ice_resume(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - - if (msm_host->ice.state != - SDHCI_MSM_ICE_STATE_SUSPENDED) { - pr_err("%s: ice is in invalid state before resume %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - if (msm_host->ice.vops->resume) { - err = msm_host->ice.vops->resume(msm_host->ice.pdev); - if (err) { - pr_err("%s: ice resume failed %d\n", - mmc_hostname(host->mmc), err); - return err; - } - } - - msm_host->ice.state = SDHCI_MSM_ICE_STATE_ACTIVE; - return 0; -} - -int sdhci_msm_ice_suspend(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int err = 0; - - if (msm_host->ice.state != - SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state before resume %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - if (msm_host->ice.vops->suspend) { - err = msm_host->ice.vops->suspend(msm_host->ice.pdev); - if (err) { - pr_err("%s: ice suspend failed %d\n", - mmc_hostname(host->mmc), err); - return -EINVAL; - } - } - msm_host->ice.state = SDHCI_MSM_ICE_STATE_SUSPENDED; - return 0; -} - -int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - int stat = -EINVAL; - - if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { - pr_err("%s: ice is in invalid state %d\n", - mmc_hostname(host->mmc), msm_host->ice.state); - return -EINVAL; - } - - if (msm_host->ice.vops->status) { - *ice_status = 0; - stat = msm_host->ice.vops->status(msm_host->ice.pdev); - if (stat < 0) { - pr_err("%s: ice get sts failed %d\n", - mmc_hostname(host->mmc), stat); - return -EINVAL; - } - *ice_status = stat; - } - return 0; -} - -void sdhci_msm_ice_print_regs(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - - if (msm_host->ice.vops->debug) - msm_host->ice.vops->debug(msm_host->ice.pdev); -} diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h deleted file mode 100644 index b256e285250d7d709caedabeafe64632cd9ff22c..0000000000000000000000000000000000000000 --- a/drivers/mmc/host/sdhci-msm-ice.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __SDHCI_MSM_ICE_H__ -#define __SDHCI_MSM_ICE_H__ - -#include -#include -#include -#include - -#include "sdhci-msm.h" - -#define SDHC_MSM_CRYPTO_LABEL "sdhc-msm-crypto" -/* Timeout waiting for ICE initialization, that requires TZ access */ -#define SDHCI_MSM_ICE_COMPLETION_TIMEOUT_MS 500 - -/* - * SDHCI host controller ICE registers. There are n [0..31] - * of each of these registers - */ -#define NUM_SDHCI_MSM_ICE_CTRL_INFO_n_REGS 32 - -#define CORE_VENDOR_SPEC_ICE_CTRL 0x300 -#define CORE_VENDOR_SPEC_ICE_CTRL_INFO_1_n 0x304 -#define CORE_VENDOR_SPEC_ICE_CTRL_INFO_2_n 0x308 -#define CORE_VENDOR_SPEC_ICE_CTRL_INFO_3_n 0x30C - -/* ICE3.0 register which got added cmdq reg space */ -#define ICE_CQ_CAPABILITIES 0x04 -#define ICE_HCI_SUPPORT (1 << 28) -#define ICE_CQ_CONFIG 0x08 -#define CRYPTO_GENERAL_ENABLE (1 << 1) -#define ICE_NONCQ_CRYPTO_PARAMS 0x70 -#define ICE_NONCQ_CRYPTO_DUN 0x74 - -/* ICE3.0 register which got added hc reg space */ -#define HC_VENDOR_SPECIFIC_FUNC4 0x260 -#define DISABLE_CRYPTO (1 << 15) -#define HC_VENDOR_SPECIFIC_ICE_CTRL 0x800 -#define ICE_SW_RST_EN (1 << 0) - -/* SDHCI MSM ICE CTRL Info register offset */ -enum { - OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0, - OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 1, - OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 6, - OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0, - OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE = 8, -}; - -/* SDHCI MSM ICE CTRL Info register masks */ -enum { - MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0x1, - MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1F, - MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x7, - MASK_SDHCI_MSM_ICE_HCI_PARAM_CE = 0x1, - MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0xff -}; - -/* SDHCI MSM ICE encryption/decryption bypass state */ -enum { - SDHCI_MSM_ICE_DISABLE_BYPASS = 0, - SDHCI_MSM_ICE_ENABLE_BYPASS = 1, -}; - -/* SDHCI MSM ICE Crypto Data Unit of target DUN of Transfer Request */ -enum { - SDHCI_MSM_ICE_TR_DATA_UNIT_512_B = 0, - SDHCI_MSM_ICE_TR_DATA_UNIT_1_KB = 1, - SDHCI_MSM_ICE_TR_DATA_UNIT_2_KB = 2, - SDHCI_MSM_ICE_TR_DATA_UNIT_4_KB = 3, - SDHCI_MSM_ICE_TR_DATA_UNIT_8_KB = 4, - SDHCI_MSM_ICE_TR_DATA_UNIT_16_KB = 5, - SDHCI_MSM_ICE_TR_DATA_UNIT_32_KB = 6, - SDHCI_MSM_ICE_TR_DATA_UNIT_64_KB = 7, -}; - -/* SDHCI MSM ICE internal state */ -enum { - SDHCI_MSM_ICE_STATE_DISABLED = 0, - SDHCI_MSM_ICE_STATE_ACTIVE = 1, - SDHCI_MSM_ICE_STATE_SUSPENDED = 2, -}; - -/* crypto context fields in cmdq data command task descriptor */ -#define DATA_UNIT_NUM(x) (((u64)(x) & 0xFFFFFFFF) << 0) -#define CRYPTO_CONFIG_INDEX(x) (((u64)(x) & 0xFF) << 32) -#define CRYPTO_ENABLE(x) (((u64)(x) & 0x1) << 47) - -#ifdef CONFIG_MMC_SDHCI_MSM_ICE -int sdhci_msm_ice_get_dev(struct sdhci_host *host); -int sdhci_msm_ice_init(struct sdhci_host *host); -void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot); -int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, - u32 slot); -int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, - struct mmc_request *mrq, u32 slot, u64 *ice_ctx); -int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq); -int sdhci_msm_ice_reset(struct sdhci_host *host); -int sdhci_msm_ice_resume(struct sdhci_host *host); -int sdhci_msm_ice_suspend(struct sdhci_host *host); -int sdhci_msm_ice_get_status(struct sdhci_host *host, int *ice_status); -void sdhci_msm_ice_print_regs(struct sdhci_host *host); -#else -inline int sdhci_msm_ice_get_dev(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - - if (msm_host) { - msm_host->ice.pdev = NULL; - msm_host->ice.vops = NULL; - } - return -ENODEV; -} -inline int sdhci_msm_ice_init(struct sdhci_host *host) -{ - return 0; -} - -inline void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot) -{ -} - -inline int sdhci_msm_ice_cfg(struct sdhci_host *host, - struct mmc_request *mrq, u32 slot) -{ - return 0; -} -static inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, - struct mmc_request *mrq, u32 slot, u64 *ice_ctx) -{ - return 0; -} -static inline int sdhci_msm_ice_cfg_end(struct sdhci_host *host, - struct mmc_request *mrq) -{ - return 0; -} -inline int sdhci_msm_ice_reset(struct sdhci_host *host) -{ - return 0; -} -inline int sdhci_msm_ice_resume(struct sdhci_host *host) -{ - return 0; -} -inline int sdhci_msm_ice_suspend(struct sdhci_host *host) -{ - return 0; -} -inline int sdhci_msm_ice_get_status(struct sdhci_host *host, - int *ice_status) -{ - return 0; -} -inline void sdhci_msm_ice_print_regs(struct sdhci_host *host) -{ -} -#endif /* CONFIG_MMC_SDHCI_MSM_ICE */ -#endif /* __SDHCI_MSM_ICE_H__ */ diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a6bd35e37a31df9a76d01257a91808f4dec3d271..29a87b31b6de51b81bcb83684b220610b7c6a04d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -42,8 +42,8 @@ #include #include "sdhci-msm.h" -#include "sdhci-msm-ice.h" #include "cmdq_hci.h" +#include "cmdq_hci-crypto-qti.h" #define QOS_REMOVE_DELAY_MS 10 #define CORE_POWER 0x0 @@ -2055,26 +2055,20 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, } } - if (msm_host->ice.pdev) { - if (sdhci_msm_dt_get_array(dev, "qcom,ice-clk-rates", - &ice_clk_table, &ice_clk_table_len, 0)) { - dev_err(dev, "failed parsing supported ice clock rates\n"); - goto out; - } - if (!ice_clk_table || !ice_clk_table_len) { - dev_err(dev, "Invalid clock table\n"); - goto out; - } - if (ice_clk_table_len != 2) { - dev_err(dev, "Need max and min frequencies in the table\n"); - goto out; - } - pdata->sup_ice_clk_table = ice_clk_table; - pdata->sup_ice_clk_cnt = ice_clk_table_len; - pdata->ice_clk_max = pdata->sup_ice_clk_table[0]; - pdata->ice_clk_min = pdata->sup_ice_clk_table[1]; - dev_dbg(dev, "supported ICE clock rates (Hz): max: %u min: %u\n", + if (!sdhci_msm_dt_get_array(dev, "qcom,ice-clk-rates", + &ice_clk_table, &ice_clk_table_len, 0)) { + if (ice_clk_table && ice_clk_table_len) { + if (ice_clk_table_len != 2) { + dev_err(dev, "Need max and min frequencies\n"); + goto out; + } + pdata->sup_ice_clk_table = ice_clk_table; + pdata->sup_ice_clk_cnt = ice_clk_table_len; + pdata->ice_clk_max = pdata->sup_ice_clk_table[0]; + pdata->ice_clk_min = pdata->sup_ice_clk_table[1]; + dev_dbg(dev, "ICE clock rates (Hz): max: %u min: %u\n", pdata->ice_clk_max, pdata->ice_clk_min); + } } pdata->vreg_data = devm_kzalloc(dev, sizeof(struct @@ -3782,7 +3776,6 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) int i, index = 0; u32 test_bus_val = 0; u32 debug_reg[MAX_TEST_BUS] = {0}; - u32 sts = 0; sdhci_msm_cache_debug_data(host); pr_info("----------- VENDOR REGISTER DUMP -----------\n"); @@ -3855,28 +3848,10 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) pr_info(" Test bus[%d to %d]: 0x%08x 0x%08x 0x%08x 0x%08x\n", i, i + 3, debug_reg[i], debug_reg[i+1], debug_reg[i+2], debug_reg[i+3]); - if (host->is_crypto_en) { - sdhci_msm_ice_get_status(host, &sts); - pr_info("%s: ICE status %x\n", mmc_hostname(host->mmc), sts); - sdhci_msm_ice_print_regs(host); - } } static void sdhci_msm_reset(struct sdhci_host *host, u8 mask) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; - - /* Set ICE core to be reset in sync with SDHC core */ - if (msm_host->ice.pdev) { - if (msm_host->ice_hci_support) - writel_relaxed(1, host->ioaddr + - HC_VENDOR_SPECIFIC_ICE_CTRL); - else - writel_relaxed(1, - host->ioaddr + CORE_VENDOR_SPEC_ICE_CTRL); - } - sdhci_reset(host, mask); } @@ -4516,11 +4491,6 @@ static int sdhci_msm_notify_load(struct sdhci_host *host, enum mmc_load state) } static struct sdhci_ops sdhci_msm_ops = { - .crypto_engine_cfg = sdhci_msm_ice_cfg, - .crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg, - .crypto_engine_cfg_end = sdhci_msm_ice_cfg_end, - .crypto_cfg_reset = sdhci_msm_ice_cfg_reset, - .crypto_engine_reset = sdhci_msm_ice_reset, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, .check_power_status = sdhci_msm_check_power_status, .platform_execute_tuning = sdhci_msm_execute_tuning, @@ -4646,7 +4616,6 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, msm_host->caps_0 = caps; if ((major == 1) && (minor >= 0x6b)) { - msm_host->ice_hci_support = true; host->cdr_support = true; } @@ -4676,6 +4645,13 @@ static void sdhci_msm_cmdq_init(struct sdhci_host *host, } else { msm_host->mmc->caps2 |= MMC_CAP2_CMD_QUEUE; } + /* + * Set the vendor specific ops needed for ICE. + * Default implementation if the ops are not set. + */ +#ifdef CONFIG_MMC_CQ_HCI_CRYPTO_QTI + cmdq_crypto_qti_set_vops(host->cq_host); +#endif } #else static void sdhci_msm_cmdq_init(struct sdhci_host *host, @@ -4750,31 +4726,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->mmc = host->mmc; msm_host->pdev = pdev; - /* get the ice device vops if present */ - ret = sdhci_msm_ice_get_dev(host); - if (ret == -EPROBE_DEFER) { - /* - * SDHCI driver might be probed before ICE driver does. - * In that case we would like to return EPROBE_DEFER code - * in order to delay its probing. - */ - dev_err(&pdev->dev, "%s: required ICE device not probed yet err = %d\n", - __func__, ret); - goto pltfm_free; - - } else if (ret == -ENODEV) { - /* - * ICE device is not enabled in DTS file. No need for further - * initialization of ICE driver. - */ - dev_warn(&pdev->dev, "%s: ICE device is not enabled", - __func__); - } else if (ret) { - dev_err(&pdev->dev, "%s: sdhci_msm_ice_get_dev failed %d\n", - __func__, ret); - goto pltfm_free; - } - /* Extract platform data */ if (pdev->dev.of_node) { ret = of_alias_get_id(pdev->dev.of_node, "sdhc"); @@ -4849,26 +4800,24 @@ static int sdhci_msm_probe(struct platform_device *pdev) } } - if (msm_host->ice.pdev) { - /* Setup SDC ICE clock */ - msm_host->ice_clk = devm_clk_get(&pdev->dev, "ice_core_clk"); - if (!IS_ERR(msm_host->ice_clk)) { - /* ICE core has only one clock frequency for now */ - ret = clk_set_rate(msm_host->ice_clk, - msm_host->pdata->ice_clk_max); - if (ret) { - dev_err(&pdev->dev, "ICE_CLK rate set failed (%d) for %u\n", - ret, - msm_host->pdata->ice_clk_max); - goto bus_aggr_clk_disable; - } - ret = clk_prepare_enable(msm_host->ice_clk); - if (ret) - goto bus_aggr_clk_disable; - - msm_host->ice_clk_rate = - msm_host->pdata->ice_clk_max; + /* Setup SDC ICE clock */ + msm_host->ice_clk = devm_clk_get(&pdev->dev, "ice_core_clk"); + if (!IS_ERR(msm_host->ice_clk)) { + /* ICE core has only one clock frequency for now */ + ret = clk_set_rate(msm_host->ice_clk, + msm_host->pdata->ice_clk_max); + if (ret) { + dev_err(&pdev->dev, "ICE_CLK rate set failed (%d) for %u\n", + ret, + msm_host->pdata->ice_clk_max); + goto bus_aggr_clk_disable; } + ret = clk_prepare_enable(msm_host->ice_clk); + if (ret) + goto bus_aggr_clk_disable; + + msm_host->ice_clk_rate = + msm_host->pdata->ice_clk_max; } /* Setup SDC MMC clock */ @@ -5117,22 +5066,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa; - /* Initialize ICE if present */ - if (msm_host->ice.pdev) { - ret = sdhci_msm_ice_init(host); - if (ret) { - dev_err(&pdev->dev, "%s: SDHCi ICE init failed (%d)\n", - mmc_hostname(host->mmc), ret); - ret = -EINVAL; - goto vreg_deinit; - } - host->is_crypto_en = true; - msm_host->mmc->inlinecrypt_support = true; - /* Packed commands cannot be encrypted/decrypted using ICE */ - msm_host->mmc->caps2 &= ~(MMC_CAP2_PACKED_WR | - MMC_CAP2_PACKED_WR_CONTROL); - } - init_completion(&msm_host->pwr_irq_completion); if (gpio_is_valid(msm_host->pdata->status_gpio)) { @@ -5413,7 +5346,6 @@ static int sdhci_msm_runtime_suspend(struct device *dev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; ktime_t start = ktime_get(); - int ret; if (host->mmc->card && mmc_card_sdio(host->mmc->card)) goto defer_disable_host_irq; @@ -5433,12 +5365,6 @@ static int sdhci_msm_runtime_suspend(struct device *dev) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); } - if (host->is_crypto_en) { - ret = sdhci_msm_ice_suspend(host); - if (ret < 0) - pr_err("%s: failed to suspend crypto engine %d\n", - mmc_hostname(host->mmc), ret); - } trace_sdhci_msm_runtime_suspend(mmc_hostname(host->mmc), 0, ktime_to_us(ktime_sub(ktime_get(), start))); return 0; @@ -5450,21 +5376,6 @@ static int sdhci_msm_runtime_resume(struct device *dev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; ktime_t start = ktime_get(); - int ret; - - if (host->is_crypto_en) { - ret = sdhci_msm_enable_controller_clock(host); - if (ret) { - pr_err("%s: Failed to enable reqd clocks\n", - mmc_hostname(host->mmc)); - goto skip_ice_resume; - } - ret = sdhci_msm_ice_resume(host); - if (ret) - pr_err("%s: failed to resume crypto engine %d\n", - mmc_hostname(host->mmc), ret); - } -skip_ice_resume: if (host->mmc->card && mmc_card_sdio(host->mmc->card)) goto defer_enable_host_irq; diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index 66e48622498b9c1228cf8d6bedbd6bbd16949c15..8a52f8e9e20123b5add62088ebd0aad3ad3a7331 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -171,12 +171,6 @@ struct sdhci_msm_bus_vote { struct device_attribute max_bus_bw; }; -struct sdhci_msm_ice_data { - struct qcom_ice_variant_ops *vops; - struct platform_device *pdev; - int state; -}; - struct sdhci_msm_regs_restore { bool is_supported; bool is_valid; @@ -221,8 +215,6 @@ struct sdhci_msm_debug_data { struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ - void __iomem *cryptoio; /* ICE HCI mapped address */ - bool ice_hci_support; int pwr_irq; /* power irq */ struct clk *clk; /* main SD/MMC bus clock */ struct clk *pclk; /* SDHC peripheral bus clock */ @@ -256,7 +248,6 @@ struct sdhci_msm_host { bool enhanced_strobe; bool rclk_delay_fix; u32 caps_0; - struct sdhci_msm_ice_data ice; u32 ice_clk_rate; struct sdhci_msm_pm_qos_group *pm_qos; int pm_qos_prev_cpu; diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 564e7be21e068c6d01db48e72f286936f84e87fb..78c9ac33b562166c1731bec085ee49b83d1a80b6 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -125,7 +125,8 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask) { sdhci_reset(host, mask); - if (host->mmc->caps & MMC_CAP_NONREMOVABLE) + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) + || mmc_gpio_get_cd(host->mmc) >= 0) sdhci_at91_set_force_card_detect(host); } @@ -331,19 +332,22 @@ static int sdhci_at91_probe(struct platform_device *pdev) priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); if (IS_ERR(priv->mainck)) { dev_err(&pdev->dev, "failed to get baseclk\n"); - return PTR_ERR(priv->mainck); + ret = PTR_ERR(priv->mainck); + goto sdhci_pltfm_free; } priv->hclock = devm_clk_get(&pdev->dev, "hclock"); if (IS_ERR(priv->hclock)) { dev_err(&pdev->dev, "failed to get hclock\n"); - return PTR_ERR(priv->hclock); + ret = PTR_ERR(priv->hclock); + goto sdhci_pltfm_free; } priv->gck = devm_clk_get(&pdev->dev, "multclk"); if (IS_ERR(priv->gck)) { dev_err(&pdev->dev, "failed to get multclk\n"); - return PTR_ERR(priv->gck); + ret = PTR_ERR(priv->gck); + goto sdhci_pltfm_free; } ret = sdhci_at91_set_clks_presets(&pdev->dev); @@ -401,8 +405,11 @@ static int sdhci_at91_probe(struct platform_device *pdev) * detection procedure using the SDMCC_CD signal is bypassed. * This bit is reset when a software reset for all command is performed * so we need to implement our own reset function to set back this bit. + * + * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line. */ - if (host->mmc->caps & MMC_CAP_NONREMOVABLE) + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) + || mmc_gpio_get_cd(host->mmc) >= 0) sdhci_at91_set_force_card_detect(host); pm_runtime_put_autosuspend(&pdev->dev); diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 0e386f5cc83650c2b164e40027934c5b63800ca7..4bc89551229b8afde3471aca76a96aa07d78e3b7 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -490,6 +490,9 @@ static int intel_select_drive_strength(struct mmc_card *card, struct sdhci_pci_slot *slot = sdhci_priv(host); struct intel_host *intel_host = sdhci_pci_priv(slot); + if (!(mmc_driver_type_mask(intel_host->drv_strength) & card_drv)) + return 0; + return intel_host->drv_strength; } diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index a0b5089b3274821b6e84f16e57ffebd08a184cae..fafb02644efde7726ff663d15834477e0b5e4a28 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -238,6 +238,16 @@ static void xenon_voltage_switch(struct sdhci_host *host) { /* Wait for 5ms after set 1.8V signal enable bit */ usleep_range(5000, 5500); + + /* + * For some reason the controller's Host Control2 register reports + * the bit representing 1.8V signaling as 0 when read after it was + * written as 1. Subsequent read reports 1. + * + * Since this may cause some issues, do an empty read of the Host + * Control2 register here to circumvent this. + */ + sdhci_readw(host, SDHCI_HOST_CONTROL2); } static const struct sdhci_ops sdhci_xenon_ops = { diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 90ff537636b1e7283f0b726ce676deede009752a..efd37a9d94f7b9ea4b86c9c49277fea803dc8a0d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1834,50 +1834,6 @@ static int sdhci_get_tuning_cmd(struct sdhci_host *host) return MMC_SEND_TUNING_BLOCK; } -static int sdhci_crypto_cfg(struct sdhci_host *host, struct mmc_request *mrq, - u32 slot) -{ - int err = 0; - - if (host->mmc->inlinecrypt_reset_needed && - host->ops->crypto_engine_reset) { - err = host->ops->crypto_engine_reset(host); - if (err) { - pr_err("%s: crypto reset failed\n", - mmc_hostname(host->mmc)); - goto out; - } - host->mmc->inlinecrypt_reset_needed = false; - } - - if (host->ops->crypto_engine_cfg) { - err = host->ops->crypto_engine_cfg(host, mrq, slot); - if (err) { - pr_err("%s: failed to configure crypto\n", - mmc_hostname(host->mmc)); - goto out; - } - } -out: - return err; -} - -static int sdhci_crypto_cfg_end(struct sdhci_host *host, - struct mmc_request *mrq) -{ - int err = 0; - - if (host->ops->crypto_engine_cfg_end) { - err = host->ops->crypto_engine_cfg_end(host, mrq); - if (err) { - pr_err("%s: failed to configure crypto\n", - mmc_hostname(host->mmc)); - return err; - } - } - return 0; -} - static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host; @@ -1944,13 +1900,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_get_tuning_cmd(host)); } - if (host->is_crypto_en) { - spin_unlock_irqrestore(&host->lock, flags); - if (sdhci_crypto_cfg(host, mrq, 0)) - goto end_req; - spin_lock_irqsave(&host->lock, flags); - } - if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) sdhci_send_command(host, mrq->sbc); else @@ -1960,11 +1909,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) mmiowb(); spin_unlock_irqrestore(&host->lock, flags); return; -end_req: - mrq->cmd->error = -EIO; - if (mrq->data) - mrq->data->error = -EIO; - mmc_request_done(host->mmc, mrq); } void sdhci_set_bus_width(struct sdhci_host *host, int width) @@ -3009,7 +2953,6 @@ static bool sdhci_request_done(struct sdhci_host *host) mmiowb(); spin_unlock_irqrestore(&host->lock, flags); - sdhci_crypto_cfg_end(host, mrq); mmc_request_done(host->mmc, mrq); return false; @@ -4087,59 +4030,6 @@ static void sdhci_cmdq_post_cqe_halt(struct mmc_host *mmc) SDHCI_INT_RESPONSE, SDHCI_INT_ENABLE); sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS); } -static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc, - struct mmc_request *mrq, u32 slot, u64 *ice_ctx) -{ - struct sdhci_host *host = mmc_priv(mmc); - int err = 0; - - if (!host->is_crypto_en) - return 0; - - if (mmc->inlinecrypt_reset_needed && host->ops->crypto_engine_reset) { - err = host->ops->crypto_engine_reset(host); - if (err) { - pr_err("%s: crypto reset failed\n", - mmc_hostname(host->mmc)); - goto out; - } - mmc->inlinecrypt_reset_needed = false; - } - - if (host->ops->crypto_engine_cmdq_cfg) { - err = host->ops->crypto_engine_cmdq_cfg(host, mrq, - slot, ice_ctx); - if (err) { - pr_err("%s: failed to configure crypto\n", - mmc_hostname(host->mmc)); - goto out; - } - } -out: - return err; -} - -static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc, - struct mmc_request *mrq) -{ - struct sdhci_host *host = mmc_priv(mmc); - - if (!host->is_crypto_en) - return 0; - - return sdhci_crypto_cfg_end(host, mrq); -} - -static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) -{ - struct sdhci_host *host = mmc_priv(mmc); - - if (!host->is_crypto_en) - return; - - if (host->ops->crypto_cfg_reset) - host->ops->crypto_cfg_reset(host, slot); -} #else static void sdhci_cmdq_set_transfer_params(struct mmc_host *mmc) { @@ -4184,23 +4074,6 @@ static void sdhci_cmdq_clear_set_dumpregs(struct mmc_host *mmc, bool set) static void sdhci_cmdq_post_cqe_halt(struct mmc_host *mmc) { -} - -static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc, - struct mmc_request *mrq, u32 slot, u64 *ice_ctx) -{ - return 0; -} - -static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc, - struct mmc_request *mrq) -{ - return 0; -} - -static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) -{ - } #endif @@ -4213,9 +4086,6 @@ static const struct cmdq_host_ops sdhci_cmdq_ops = { .enhanced_strobe_mask = sdhci_enhanced_strobe_mask, .post_cqe_halt = sdhci_cmdq_post_cqe_halt, .set_transfer_params = sdhci_cmdq_set_transfer_params, - .crypto_cfg = sdhci_cmdq_crypto_cfg, - .crypto_cfg_end = sdhci_cmdq_crypto_cfg_end, - .crypto_cfg_reset = sdhci_cmdq_crypto_cfg_reset, }; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f2cf328764d913d8f095d51ff54de65e1fdf3df4..47f05e16d68532180039b95839168227a99adff5 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -653,7 +653,6 @@ struct sdhci_host { enum sdhci_power_policy power_policy; bool sdio_irq_async_status; - bool is_crypto_en; u32 auto_cmd_err_sts; struct ratelimit_state dbg_dump_rs; @@ -695,14 +694,6 @@ struct sdhci_ops { unsigned int (*get_ro)(struct sdhci_host *host); void (*reset)(struct sdhci_host *host, u8 mask); int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); - int (*crypto_engine_cfg)(struct sdhci_host *host, - struct mmc_request *mrq, u32 slot); - int (*crypto_engine_cmdq_cfg)(struct sdhci_host *host, - struct mmc_request *mrq, u32 slot, u64 *ice_ctx); - int (*crypto_engine_cfg_end)(struct sdhci_host *host, - struct mmc_request *mrq); - int (*crypto_engine_reset)(struct sdhci_host *host); - void (*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot); void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); void (*hw_reset)(struct sdhci_host *host); void (*adma_workaround)(struct sdhci_host *host, u32 intmask); diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index e773dc6fdd3c67106ecaea95c0b7969ed9a66f1e..1f0d83086cb092ed1b050a4ea989f4f755cbd30e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1883,7 +1883,11 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, continue; } - if (time_after(jiffies, timeo) && !chip_ready(map, adr)) + /* + * We check "time_after" and "!chip_good" before checking "chip_good" to avoid + * the failure due to scheduling. + */ + if (time_after(jiffies, timeo) && !chip_good(map, adr, datum)) break; if (chip_good(map, adr, datum)) { diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index 8cb1feb3dcd1dc8bdd7ce69f74c2d5a0cee7aeaa..6d80804d3310e968ee75d2b213ee20e182650bab 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -26,6 +26,8 @@ #define MAX_DESC 16 #define SMEM_AARM_PARTITION_TABLE 9 #define SMEM_APPS 0 +#define ONE_CODEWORD_SIZE 516 + static bool enable_euclean; static bool enable_perfstats; @@ -1054,8 +1056,9 @@ static int msm_nand_flash_onfi_probe(struct msm_nand_info *info) flash->blksize = onfi_param_page_ptr->number_of_pages_per_block * flash->pagesize; flash->oobsize = onfi_param_page_ptr->number_of_spare_bytes_per_page; - flash->density = onfi_param_page_ptr->number_of_blocks_per_logical_unit - * flash->blksize; + flash->density = onfi_param_page_ptr->number_of_logical_units * + onfi_param_page_ptr->number_of_blocks_per_logical_unit * + flash->blksize; flash->ecc_correctability = onfi_param_page_ptr->number_of_bits_ecc_correctability; @@ -1183,10 +1186,16 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read, err = -EINVAL; goto out; } - args->page_count = ops->len / (mtd->writesize + mtd->oobsize); + if (ops->len <= ONE_CODEWORD_SIZE) + args->page_count = 1; + else + args->page_count = ops->len / + (mtd->writesize + mtd->oobsize); } else if (ops->mode == MTD_OPS_AUTO_OOB) { - if (ops->datbuf && (ops->len % mtd->writesize) != 0) { + if (ops->datbuf && (ops->len % + ((ops->len <= ONE_CODEWORD_SIZE) ? + ONE_CODEWORD_SIZE : mtd->writesize)) != 0) { /* when ops->datbuf is NULL, ops->len can be ooblen */ pr_err("unsupported data len %d for AUTO mode\n", ops->len); @@ -1199,7 +1208,10 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read, if ((args->page_count == 0) && (ops->ooblen)) args->page_count = 1; } else if (ops->datbuf) { - args->page_count = ops->len / mtd->writesize; + if (ops->len <= ONE_CODEWORD_SIZE) + args->page_count = 1; + else + args->page_count = ops->len / mtd->writesize; } } @@ -1245,12 +1257,20 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip, struct msm_nand_rw_params *args, struct msm_nand_rw_reg_data *data) { + /* + * While reading one codeword, CW_PER_PAGE bits of QPIC_NAND_DEV0_CFG0 + * should be set to 0, which implies 1 codeword per page. 'n' below, + * is used to configure cfg0 for reading one full page or one single + * codeword. + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; + if (args->read) { if (ops->mode != MTD_OPS_RAW) { data->cmd = MSM_NAND_CMD_PAGE_READ_ECC; data->cfg0 = (chip->cfg0 & ~(7U << CW_PER_PAGE)) | - (((args->cwperpage-1) - args->start_sector) + (((args->cwperpage-n) - args->start_sector) << CW_PER_PAGE); data->cfg1 = chip->cfg1; data->ecc_bch_cfg = chip->ecc_bch_cfg; @@ -1258,7 +1278,7 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip, data->cmd = MSM_NAND_CMD_PAGE_READ_ALL; data->cfg0 = (chip->cfg0_raw & ~(7U << CW_PER_PAGE)) | - (((args->cwperpage-1) - args->start_sector) + (((args->cwperpage-n) - args->start_sector) << CW_PER_PAGE); data->cfg1 = chip->cfg1_raw; data->ecc_bch_cfg = chip->ecc_cfg_raw; @@ -1302,6 +1322,11 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, uint32_t offset, size, last_read; struct sps_command_element *curr_ce, *start_ce; uint32_t *flags_ptr, *num_ce_ptr; + /* + * Variable to configure read_location register parameters + * while reading one codeword or one full page + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; if (curr_cw == args->start_sector) { curr_ce = start_ce = &cmd_list->setup_desc.ce[0]; @@ -1394,10 +1419,15 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) { offset = 0; - size = (curr_cw < (args->cwperpage - 1)) ? 516 : - (512 - ((args->cwperpage - 1) << 2)); - last_read = (curr_cw < (args->cwperpage - 1)) ? 1 : - (ops->oobbuf ? 0 : 1); + if (ops->len <= ONE_CODEWORD_SIZE) { + size = ONE_CODEWORD_SIZE; + last_read = 1; + } else { + size = (curr_cw < (args->cwperpage - 1)) ? 516 : + (512 - ((args->cwperpage - 1) << 2)); + last_read = (curr_cw < (args->cwperpage - 1)) ? + 1 : (ops->oobbuf ? 0 : 1); + } rdata = (offset << 0) | (size << 16) | (last_read << 31); @@ -1413,7 +1443,7 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, curr_ce++; } } - if (curr_cw == (args->cwperpage - 1) && ops->oobbuf) { + if (curr_cw == (args->cwperpage - n) && ops->oobbuf) { offset = 512 - ((args->cwperpage - 1) << 2); size = (args->cwperpage) << 2; if (size > args->oob_len_cmd) @@ -1471,6 +1501,11 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, uint32_t sectordatasize, sectoroobsize; uint32_t sps_flags = 0; int err = 0; + /* + * Variable to configure sectordatasize and sectoroobsize + * while reading one codeword or one full page. + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; if (args->read) data_pipe_handle = info->sps.data_prod.handle; @@ -1479,7 +1514,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, if (ops->mode == MTD_OPS_RAW) { if (ecc_parity_bytes && args->read) { - if (curr_cw == (args->cwperpage - 1)) + if (curr_cw == (args->cwperpage - n)) sps_flags |= SPS_IOVEC_FLAG_INT; /* read only ecc bytes */ @@ -1494,7 +1529,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, sectordatasize = chip->cw_size; if (!args->read) sps_flags = SPS_IOVEC_FLAG_EOT; - if (curr_cw == (args->cwperpage - 1)) + if (curr_cw == (args->cwperpage - n)) sps_flags |= SPS_IOVEC_FLAG_INT; err = sps_transfer_one(data_pipe_handle, @@ -1507,8 +1542,13 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, } } else if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) { - sectordatasize = (curr_cw < (args->cwperpage - 1)) - ? 516 : (512 - ((args->cwperpage - 1) << 2)); + if (ops->len <= ONE_CODEWORD_SIZE) + sectordatasize = ONE_CODEWORD_SIZE; + else + sectordatasize = + (curr_cw < (args->cwperpage - 1)) + ? 516 : + (512 - ((args->cwperpage - 1) << 2)); if (!args->read) { sps_flags = SPS_IOVEC_FLAG_EOT; @@ -1516,7 +1556,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, ops->oobbuf) sps_flags = 0; } - if ((curr_cw == (args->cwperpage - 1)) && !ops->oobbuf) + if ((curr_cw == (args->cwperpage - n)) && !ops->oobbuf) sps_flags |= SPS_IOVEC_FLAG_INT; err = sps_transfer_one(data_pipe_handle, @@ -1528,7 +1568,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, args->data_dma_addr_curr += sectordatasize; } - if (ops->oobbuf && (curr_cw == (args->cwperpage - 1))) { + if (ops->oobbuf && (curr_cw == (args->cwperpage - n))) { sectoroobsize = args->cwperpage << 2; if (sectoroobsize > args->oob_len_data) sectoroobsize = args->oob_len_data; @@ -1984,7 +2024,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, total_ecc_byte_cnt, DMA_FROM_DEVICE); /* check for bit flips in ecc data */ ecc_temp = ecc; - for (n = rw_params->start_sector; n < cwperpage; n++) { + for (n = rw_params->start_sector; !err && n < cwperpage; n++) { int last_pos = 0, next_pos = 0; int ecc_bytes_percw_in_bits = (chip->ecc_parity_bytes * 8); @@ -1995,7 +2035,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > MAX_ECC_BIT_FLIPS) { + if (num_zero_bits > info->flash_dev.ecc_capability) { *erased_page = false; goto free_mem; } @@ -2007,7 +2047,8 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) + if ((n == cwperpage) && + (num_zero_bits <= info->flash_dev.ecc_capability)) *erased_page = true; free_mem: kfree(ecc); @@ -2651,7 +2692,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, total_ecc_byte_cnt, DMA_FROM_DEVICE); /* check for bit flips in ecc data */ ecc_temp = ecc; - for (n = rw_params->start_sector; n < cwperpage; n++) { + for (n = rw_params->start_sector; !err && n < cwperpage; n++) { int last_pos = 0, next_pos = 0; int ecc_bytes_percw_in_bits = (chip->ecc_parity_bytes * 8); @@ -2662,7 +2703,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > MAX_ECC_BIT_FLIPS) { + if (num_zero_bits > info->flash_dev.ecc_capability) { *erased_page = false; goto free_mem; } @@ -2674,7 +2715,8 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) + if ((n == cwperpage) && + (num_zero_bits <= info->flash_dev.ecc_capability)) *erased_page = true; free_mem: kfree(ecc); @@ -2755,6 +2797,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, data.addr0 = (rw_params.page << 16) | rw_params.oob_col; data.addr1 = (rw_params.page >> 16) & 0xff; + if (ops->len <= ONE_CODEWORD_SIZE) + cwperpage = 1; + for (n = rw_params.start_sector; n < cwperpage; n++) { struct sps_command_element *curr_ce, *start_ce; @@ -2832,7 +2877,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } else if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) submitted_num_desc = cwperpage - - rw_params.start_sector; + rw_params.start_sector; if (ops->oobbuf) submitted_num_desc++; } @@ -3052,7 +3097,10 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } validate_mtd_params_failed: if (ops->mode != MTD_OPS_RAW) - ops->retlen = mtd->writesize * pages_read; + if (ops->len <= ONE_CODEWORD_SIZE) + ops->retlen = ONE_CODEWORD_SIZE; + else + ops->retlen = mtd->writesize * pages_read; else ops->retlen = (mtd->writesize + mtd->oobsize) * pages_read; ops->oobretlen = ops->ooblen - rw_params.oob_len_data; @@ -3125,8 +3173,11 @@ static int msm_nand_read_partial_page(struct mtd_info *mtd, ops->datbuf = no_copy ? actual_buf : bounce_buf; if (info->nand_chip.caps & MSM_NAND_CAP_PAGE_SCOPE_READ) err = msm_nand_read_pagescope(mtd, aligned_from, ops); - else + else { + if ((len <= ONE_CODEWORD_SIZE) && (offset == 0)) + ops->len = ONE_CODEWORD_SIZE; err = msm_nand_read_oob(mtd, aligned_from, ops); + } if (err == -EUCLEAN) { is_euclean = 1; err = 0; diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 7287696a21f91df6a875dc32a112e6206c855de1..d312c1b5a78e1ad0bfd0ae91971b315fb88fc7fa 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -247,22 +247,25 @@ static int phram_setup(const char *val) ret = parse_num64(&start, token[1]); if (ret) { - kfree(name); parse_err("illegal start address\n"); + goto error; } ret = parse_num64(&len, token[2]); if (ret) { - kfree(name); parse_err("illegal device length\n"); + goto error; } ret = register_device(name, start, len); - if (!ret) - pr_info("%s device: %#llx at %#llx\n", name, len, start); - else - kfree(name); + if (ret) + goto error; + + pr_info("%s device: %#llx at %#llx\n", name, len, start); + return 0; +error: + kfree(name); return ret; } diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 018c75faadb3d30c2de119608536b1335d175fa4..e1c283ccbbded16fae4a9ba4d2fd50855fbb79e2 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -81,7 +81,6 @@ struct mtd_info *lpddr_cmdset(struct map_info *map) shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips, GFP_KERNEL); if (!shared) { - kfree(lpddr); kfree(mtd); return NULL; } diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 63e8527f7b65d07887342d78694bcef4baeb7fb1..18aba1cf8accb4d480cc6fa1235b2b352fd06518 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -73,7 +73,7 @@ static int self_check_seen(struct ubi_device *ubi, unsigned long *seen) return 0; for (pnum = 0; pnum < ubi->peb_count; pnum++) { - if (test_bit(pnum, seen) && ubi->lookuptbl[pnum]) { + if (!test_bit(pnum, seen) && ubi->lookuptbl[pnum]) { ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum); ret = -EINVAL; } @@ -1147,7 +1147,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, struct rb_node *tmp_rb; int ret, i, j, free_peb_count, used_peb_count, vol_count; int scrub_peb_count, erase_peb_count; - unsigned long *seen_pebs = NULL; + unsigned long *seen_pebs; fm_raw = ubi->fm_buf; memset(ubi->fm_buf, 0, ubi->fm_size); @@ -1161,7 +1161,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, dvbuf = new_fm_vbuf(ubi, UBI_FM_DATA_VOLUME_ID); if (!dvbuf) { ret = -ENOMEM; - goto out_kfree; + goto out_free_avbuf; } avhdr = ubi_get_vid_hdr(avbuf); @@ -1170,7 +1170,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, seen_pebs = init_seen(ubi); if (IS_ERR(seen_pebs)) { ret = PTR_ERR(seen_pebs); - goto out_kfree; + goto out_free_dvbuf; } spin_lock(&ubi->volumes_lock); @@ -1338,7 +1338,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avbuf); if (ret) { ubi_err(ubi, "unable to write vid_hdr to fastmap SB!"); - goto out_kfree; + goto out_free_seen; } for (i = 0; i < new_fm->used_blocks; i++) { @@ -1360,7 +1360,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, if (ret) { ubi_err(ubi, "unable to write vid_hdr to PEB %i!", new_fm->e[i]->pnum); - goto out_kfree; + goto out_free_seen; } } @@ -1370,7 +1370,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, if (ret) { ubi_err(ubi, "unable to write fastmap to PEB %i!", new_fm->e[i]->pnum); - goto out_kfree; + goto out_free_seen; } } @@ -1380,10 +1380,13 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ret = self_check_seen(ubi, seen_pebs); dbg_bld("fastmap written!"); -out_kfree: - ubi_free_vid_buf(avbuf); - ubi_free_vid_buf(dvbuf); +out_free_seen: free_seen(seen_pebs); +out_free_dvbuf: + ubi_free_vid_buf(dvbuf); +out_free_avbuf: + ubi_free_vid_buf(avbuf); + out: return ret; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 60666db318867912c086d5ae06ab6a275d780c42..0b79ddec15b73bbb32a3f4983c9aa114a44c9903 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -71,11 +71,6 @@ struct arp_pkt { }; #pragma pack() -static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb) -{ - return (struct arp_pkt *)skb_network_header(skb); -} - /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], bool strict_match); @@ -574,10 +569,11 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) spin_unlock(&bond->mode_lock); } -static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond) +static struct slave *rlb_choose_channel(struct sk_buff *skb, + struct bonding *bond, + const struct arp_pkt *arp) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct arp_pkt *arp = arp_pkt(skb); struct slave *assigned_slave, *curr_active_slave; struct rlb_client_info *client_info; u32 hash_index = 0; @@ -674,8 +670,12 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon */ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { - struct arp_pkt *arp = arp_pkt(skb); struct slave *tx_slave = NULL; + struct arp_pkt *arp; + + if (!pskb_network_may_pull(skb, sizeof(*arp))) + return NULL; + arp = (struct arp_pkt *)skb_network_header(skb); /* Don't modify or load balance ARPs that do not originate locally * (e.g.,arrive via a bridge). @@ -685,7 +685,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) if (arp->op_code == htons(ARPOP_REPLY)) { /* the arp must be sent on the selected rx channel */ - tx_slave = rlb_choose_channel(skb, bond); + tx_slave = rlb_choose_channel(skb, bond, arp); if (tx_slave) bond_hw_addr_copy(arp->mac_src, tx_slave->dev->dev_addr, tx_slave->dev->addr_len); @@ -696,7 +696,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) * When the arp reply is received the entry will be updated * with the correct unicast address of the client. */ - rlb_choose_channel(skb, bond); + rlb_choose_channel(skb, bond, arp); /* The ARP reply packets must be delayed so that * they can cancel out the influence of the ARP request. @@ -1403,26 +1403,31 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) bool do_tx_balance = true; u32 hash_index = 0; const u8 *hash_start = NULL; - struct ipv6hdr *ip6hdr; skb_reset_mac_header(skb); eth_data = eth_hdr(skb); switch (ntohs(skb->protocol)) { case ETH_P_IP: { - const struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph; if (ether_addr_equal_64bits(eth_data->h_dest, mac_bcast) || - (iph->daddr == ip_bcast) || - (iph->protocol == IPPROTO_IGMP)) { + (!pskb_network_may_pull(skb, sizeof(*iph)))) { + do_tx_balance = false; + break; + } + iph = ip_hdr(skb); + if (iph->daddr == ip_bcast || iph->protocol == IPPROTO_IGMP) { do_tx_balance = false; break; } hash_start = (char *)&(iph->daddr); hash_size = sizeof(iph->daddr); - } break; - case ETH_P_IPV6: + } + case ETH_P_IPV6: { + const struct ipv6hdr *ip6hdr; + /* IPv6 doesn't really use broadcast mac address, but leave * that here just in case. */ @@ -1439,7 +1444,11 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) break; } - /* Additianally, DAD probes should not be tx-balanced as that + if (!pskb_network_may_pull(skb, sizeof(*ip6hdr))) { + do_tx_balance = false; + break; + } + /* Additionally, DAD probes should not be tx-balanced as that * will lead to false positives for duplicate addresses and * prevent address configuration from working. */ @@ -1449,17 +1458,26 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) break; } - hash_start = (char *)&(ipv6_hdr(skb)->daddr); - hash_size = sizeof(ipv6_hdr(skb)->daddr); + hash_start = (char *)&ip6hdr->daddr; + hash_size = sizeof(ip6hdr->daddr); break; - case ETH_P_IPX: - if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) { + } + case ETH_P_IPX: { + const struct ipxhdr *ipxhdr; + + if (pskb_network_may_pull(skb, sizeof(*ipxhdr))) { + do_tx_balance = false; + break; + } + ipxhdr = (struct ipxhdr *)skb_network_header(skb); + + if (ipxhdr->ipx_checksum != IPX_NO_CHECKSUM) { /* something is wrong with this packet */ do_tx_balance = false; break; } - if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) { + if (ipxhdr->ipx_type != IPX_TYPE_NCP) { /* The only protocol worth balancing in * this family since it has an "ARP" like * mechanism @@ -1468,9 +1486,11 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) break; } + eth_data = eth_hdr(skb); hash_start = (char *)eth_data->h_dest; hash_size = ETH_ALEN; break; + } case ETH_P_ARP: do_tx_balance = false; if (bond_info->rlb_enabled) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index d92113db4fb97e146388bdcccd60f5898ddc278b..05ad5ed145a3a98efb54b0c1176ec545a10501a9 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -867,6 +867,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, + [IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, }; static int can_validate(struct nlattr *tb[], struct nlattr *data[], diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 35564a9561b7828be777e5b288afb77f88e95ce8..c5a616395c49036d168abd8b9d94c982e53d7744 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -147,7 +147,7 @@ static void slc_bump(struct slcan *sl) u32 tmpid; char *cmd = sl->rbuff; - cf.can_id = 0; + memset(&cf, 0, sizeof(cf)); switch (*cmd) { case 'r': @@ -186,8 +186,6 @@ static void slc_bump(struct slcan *sl) else return; - *(u64 *) (&cf.data) = 0; /* clear payload */ - /* RTR frames may have a dlc > 0 but they never have any data bytes */ if (!(cf.can_id & CAN_RTR_FLAG)) { for (i = 0; i < cf.can_dlc; i++) { @@ -621,7 +619,10 @@ static int slcan_open(struct tty_struct *tty) tty->disc_data = NULL; clear_bit(SLF_INUSE, &sl->flags); slc_free_netdev(sl->dev); + /* do not call free_netdev before rtnl_unlock */ + rtnl_unlock(); free_netdev(sl->dev); + return err; err_exit: rtnl_unlock(); diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 434e6dced6b7f982b257b042877b358d9e4e0af1..274d369151107a464b5c8ad5a5bd8e31b3545af8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1094,6 +1094,7 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, u16 vid, struct b53_arl_entry *ent, u8 *idx, bool is_valid) { + DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); unsigned int i; int ret; @@ -1101,6 +1102,8 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, if (ret) return ret; + bitmap_zero(free_bins, dev->num_arl_entries); + /* Read the bins */ for (i = 0; i < dev->num_arl_entries; i++) { u64 mac_vid; @@ -1112,13 +1115,21 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, B53_ARLTBL_DATA_ENTRY(i), &fwd_entry); b53_arl_to_entry(ent, mac_vid, fwd_entry); - if (!(fwd_entry & ARLTBL_VALID)) + if (!(fwd_entry & ARLTBL_VALID)) { + set_bit(i, free_bins); continue; + } if ((mac_vid & ARLTBL_MAC_MASK) != mac) continue; *idx = i; + return 0; } + if (bitmap_weight(free_bins, dev->num_arl_entries) == 0) + return -ENOSPC; + + *idx = find_first_bit(free_bins, dev->num_arl_entries); + return -ENOENT; } @@ -1148,10 +1159,21 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, if (op) return ret; - /* We could not find a matching MAC, so reset to a new entry */ - if (ret) { + switch (ret) { + case -ENOSPC: + dev_dbg(dev->dev, "{%pM,%.4d} no space left in ARL\n", + addr, vid); + return is_valid ? ret : 0; + case -ENOENT: + /* We could not find a matching MAC, so reset to a new entry */ + dev_dbg(dev->dev, "{%pM,%.4d} not found, using idx: %d\n", + addr, vid, idx); fwd_entry = 0; - idx = 1; + break; + default: + dev_dbg(dev->dev, "{%pM,%.4d} found, using idx: %d\n", + addr, vid, idx); + break; } memset(&ent, 0, sizeof(ent)); diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index e5c86d44667af1fd9f68a550f169a322989f39bd..247aef92b7594ac5bf48b3b552ddf69bd254d708 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -294,7 +294,7 @@ * * BCM5325 and BCM5365 share most definitions below */ -#define B53_ARLTBL_MAC_VID_ENTRY(n) (0x10 * (n)) +#define B53_ARLTBL_MAC_VID_ENTRY(n) ((0x10 * (n)) + 0x10) #define ARLTBL_MAC_MASK 0xffffffffffffULL #define ARLTBL_VID_S 48 #define ARLTBL_VID_MASK_25 0xff @@ -306,13 +306,16 @@ #define ARLTBL_VALID_25 BIT(63) /* ARL Table Data Entry N Registers (32 bit) */ -#define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x08) +#define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x18) #define ARLTBL_DATA_PORT_ID_MASK 0x1ff #define ARLTBL_TC(tc) ((3 & tc) << 11) #define ARLTBL_AGE BIT(14) #define ARLTBL_STATIC BIT(15) #define ARLTBL_VALID BIT(16) +/* Maximum number of bin entries in the ARL for all switches */ +#define B53_ARLTBL_MAX_BIN_ENTRIES 4 + /* ARL Search Control Register (8 bit) */ #define B53_ARL_SRCH_CTL 0x50 #define B53_ARL_SRCH_CTL_25 0x20 diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 05440b72726151e0e8d2d961880df8dcceaff28d..b40ebc27e1ece2f25c86459f6343a43e11973cdb 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -137,7 +137,8 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) /* Force link status for IMP port */ reg = core_readl(priv, offset); - reg |= (MII_SW_OR | LINK_STS | GMII_SPEED_UP_2G); + reg |= (MII_SW_OR | LINK_STS); + reg &= ~GMII_SPEED_UP_2G; core_writel(priv, reg, offset); /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */ @@ -1111,6 +1112,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) const struct bcm_sf2_of_data *data; struct b53_platform_data *pdata; struct dsa_switch_ops *ops; + struct device_node *ports; struct bcm_sf2_priv *priv; struct b53_device *dev; struct dsa_switch *ds; @@ -1173,7 +1175,11 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) */ set_bit(0, priv->cfp.used); - bcm_sf2_identify_ports(priv, dn->child); + ports = of_find_node_by_name(dn, "ports"); + if (ports) { + bcm_sf2_identify_ports(priv, ports); + of_node_put(ports); + } priv->irq0 = irq_of_parse_and_map(dn, 0); priv->irq1 = irq_of_parse_and_map(dn, 1); diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 7f8d269dd75ad347fd616c0230c1adb452d9bac5..814618c0b6328d58cfbcae2035967ba56c657ef4 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -130,17 +130,14 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port, (fs->m_ext.vlan_etype || fs->m_ext.data[1])) return -EINVAL; - if (fs->location != RX_CLS_LOC_ANY && fs->location >= CFP_NUM_RULES) + if (fs->location != RX_CLS_LOC_ANY && + fs->location > bcm_sf2_cfp_rule_size(priv)) return -EINVAL; if (fs->location != RX_CLS_LOC_ANY && test_bit(fs->location, priv->cfp.used)) return -EBUSY; - if (fs->location != RX_CLS_LOC_ANY && - fs->location > bcm_sf2_cfp_rule_size(priv)) - return -EINVAL; - ip_frag = be32_to_cpu(fs->m_ext.data[0]); /* We do not support discarding packets, check that the @@ -333,7 +330,7 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, int ret; u32 reg; - if (loc >= CFP_NUM_RULES) + if (loc > bcm_sf2_cfp_rule_size(priv)) return -EINVAL; /* Refuse deletion of unused rules, and the default reserved rule */ diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 3b073e15223731c82c4a4a31d9638a1e5c86342e..58c16aa00a705ce981f4b56e4a8a7b613df2c992 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -549,7 +549,7 @@ mt7530_mib_reset(struct dsa_switch *ds) static void mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable) { - u32 mask = PMCR_TX_EN | PMCR_RX_EN; + u32 mask = PMCR_TX_EN | PMCR_RX_EN | PMCR_FORCE_LNK; if (enable) mt7530_set(priv, MT7530_PMCR_P(port), mask); diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 10e6053f667123f2473fbdee232025515a8be88d..dc9149a32f412a0be72cc22afdf3edf1b01ef694 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -199,6 +199,11 @@ static inline void comp_ctxt_release(struct ena_com_admin_queue *queue, static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *queue, u16 command_id, bool capture) { + if (unlikely(!queue->comp_ctx)) { + pr_err("Completion context is NULL\n"); + return NULL; + } + if (unlikely(command_id >= queue->q_depth)) { pr_err("command id is larger than the queue size. cmd_id: %u queue size %d\n", command_id, queue->q_depth); @@ -843,6 +848,24 @@ static int ena_com_get_feature(struct ena_com_dev *ena_dev, 0); } +static void ena_com_hash_key_fill_default_key(struct ena_com_dev *ena_dev) +{ + struct ena_admin_feature_rss_flow_hash_control *hash_key = + (ena_dev->rss).hash_key; + + netdev_rss_key_fill(&hash_key->key, sizeof(hash_key->key)); + /* The key is stored in the device in u32 array + * as well as the API requires the key to be passed in this + * format. Thus the size of our array should be divided by 4 + */ + hash_key->keys_num = sizeof(hash_key->key) / sizeof(u32); +} + +int ena_com_get_current_hash_function(struct ena_com_dev *ena_dev) +{ + return ena_dev->rss.hash_func; +} + static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) { struct ena_rss *rss = &ena_dev->rss; @@ -2069,15 +2092,16 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, switch (func) { case ENA_ADMIN_TOEPLITZ: - if (key_len > sizeof(hash_key->key)) { - pr_err("key len (%hu) is bigger than the max supported (%zu)\n", - key_len, sizeof(hash_key->key)); - return -EINVAL; + if (key) { + if (key_len != sizeof(hash_key->key)) { + pr_err("key len (%hu) doesn't equal the supported size (%zu)\n", + key_len, sizeof(hash_key->key)); + return -EINVAL; + } + memcpy(hash_key->key, key, key_len); + rss->hash_init_val = init_val; + hash_key->keys_num = key_len >> 2; } - - memcpy(hash_key->key, key, key_len); - rss->hash_init_val = init_val; - hash_key->keys_num = key_len >> 2; break; case ENA_ADMIN_CRC32: rss->hash_init_val = init_val; @@ -2114,7 +2138,11 @@ int ena_com_get_hash_function(struct ena_com_dev *ena_dev, if (unlikely(rc)) return rc; - rss->hash_func = get_resp.u.flow_hash_func.selected_func; + /* ffs() returns 1 in case the lsb is set */ + rss->hash_func = ffs(get_resp.u.flow_hash_func.selected_func); + if (rss->hash_func) + rss->hash_func--; + if (func) *func = rss->hash_func; @@ -2402,6 +2430,8 @@ int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 indr_tbl_log_size) if (unlikely(rc)) goto err_hash_key; + ena_com_hash_key_fill_default_key(ena_dev); + rc = ena_com_hash_ctrl_init(ena_dev); if (unlikely(rc)) goto err_hash_ctrl; diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 7b784f8a06a6608c37f2c458b8172961ceed08f3..7272fb0d858d0af11222d569890608d1356cb39d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "ena_common_defs.h" #include "ena_admin_defs.h" @@ -631,6 +632,14 @@ int ena_com_rss_init(struct ena_com_dev *ena_dev, u16 log_size); */ void ena_com_rss_destroy(struct ena_com_dev *ena_dev); +/* ena_com_get_current_hash_function - Get RSS hash function + * @ena_dev: ENA communication layer struct + * + * Return the current hash function. + * @return: 0 or one of the ena_admin_hash_functions values. + */ +int ena_com_get_current_hash_function(struct ena_com_dev *ena_dev); + /* ena_com_fill_hash_function - Fill RSS hash function * @ena_dev: ENA communication layer struct * @func: The hash function (Toeplitz or crc) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index a2f02c23fe141014556a9cb5d24cd4bd856f8f8e..d29e256bf6104fd5fce5bef769eb60299d1dfc4d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -648,6 +648,28 @@ static u32 ena_get_rxfh_key_size(struct net_device *netdev) return ENA_HASH_KEY_SIZE; } +static int ena_indirection_table_get(struct ena_adapter *adapter, u32 *indir) +{ + struct ena_com_dev *ena_dev = adapter->ena_dev; + int i, rc; + + if (!indir) + return 0; + + rc = ena_com_indirect_table_get(ena_dev, indir); + if (rc) + return rc; + + /* Our internal representation of the indices is: even indices + * for Tx and uneven indices for Rx. We need to convert the Rx + * indices to be consecutive + */ + for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) + indir[i] = ENA_IO_RXQ_IDX_TO_COMBINED_IDX(indir[i]); + + return rc; +} + static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) { @@ -656,11 +678,25 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 func; int rc; - rc = ena_com_indirect_table_get(adapter->ena_dev, indir); + rc = ena_indirection_table_get(adapter, indir); if (rc) return rc; + /* We call this function in order to check if the device + * supports getting/setting the hash function. + */ rc = ena_com_get_hash_function(adapter->ena_dev, &ena_func, key); + + if (rc) { + if (rc == -EOPNOTSUPP) { + key = NULL; + hfunc = NULL; + rc = 0; + } + + return rc; + } + if (rc) return rc; @@ -669,7 +705,7 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, func = ETH_RSS_HASH_TOP; break; case ENA_ADMIN_CRC32: - func = ETH_RSS_HASH_XOR; + func = ETH_RSS_HASH_CRC32; break; default: netif_err(adapter, drv, netdev, @@ -712,10 +748,13 @@ static int ena_set_rxfh(struct net_device *netdev, const u32 *indir, } switch (hfunc) { + case ETH_RSS_HASH_NO_CHANGE: + func = ena_com_get_current_hash_function(ena_dev); + break; case ETH_RSS_HASH_TOP: func = ENA_ADMIN_TOEPLITZ; break; - case ETH_RSS_HASH_XOR: + case ETH_RSS_HASH_CRC32: func = ENA_ADMIN_CRC32; break; default: @@ -816,6 +855,7 @@ static const struct ethtool_ops ena_ethtool_ops = { .get_channels = ena_get_channels, .get_tunable = ena_get_tunable, .set_tunable = ena_set_tunable, + .get_ts_info = ethtool_op_get_ts_info, }; void ena_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 518ff393a026b7f86be9a27ae98396ffa8e6bab4..d9ece9ac6f53c68d10f24f4321db58cc1642d72f 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2803,8 +2803,8 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter) if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT) return; - keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies + - adapter->keep_alive_timeout); + keep_alive_expired = adapter->last_keep_alive_jiffies + + adapter->keep_alive_timeout; if (unlikely(time_is_before_jiffies(keep_alive_expired))) { netif_err(adapter, drv, adapter->netdev, "Keep alive watchdog timeout.\n"); @@ -2906,7 +2906,7 @@ static void ena_timer_service(unsigned long data) } /* Reset the timer */ - mod_timer(&adapter->timer_service, jiffies + HZ); + mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ)); } static int ena_calc_io_queue_num(struct pci_dev *pdev, diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 3404376c28ca3805564667488152bbc7da9c6329..5a72267b858b16d980f49b9cfca136cea2f363c0 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -113,6 +113,8 @@ #define ENA_IO_TXQ_IDX(q) (2 * (q)) #define ENA_IO_RXQ_IDX(q) (2 * (q) + 1) +#define ENA_IO_TXQ_IDX_TO_COMBINED_IDX(q) ((q) / 2) +#define ENA_IO_RXQ_IDX_TO_COMBINED_IDX(q) (((q) - 1) / 2) #define ENA_MGMNT_IRQ_IDX 0 #define ENA_IO_IRQ_FIRST_IDX 1 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index c65d2cdcc7cfb312eee6467f390f56f5a7540003..8556962e682442f676b1cdf1062dda0f9737cfee 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -515,7 +515,7 @@ static void xgbe_isr_task(unsigned long data) xgbe_disable_rx_tx_ints(pdata); /* Turn on polling */ - __napi_schedule_irqoff(&pdata->napi); + __napi_schedule(&pdata->napi); } } else { /* Don't clear Rx/Tx status if doing per channel DMA diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 50dd6bf176d034721590bf15c2abfab88dd5285a..3a489b2b99c99fe0fb644f74575c71be0c8584f0 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -2034,7 +2034,7 @@ static int xgene_enet_probe(struct platform_device *pdev) int ret; ndev = alloc_etherdev_mqs(sizeof(struct xgene_enet_pdata), - XGENE_NUM_RX_RING, XGENE_NUM_TX_RING); + XGENE_NUM_TX_RING, XGENE_NUM_RX_RING); if (!ndev) return -ENOMEM; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index a69f5f1ad32a8e0c8c9195ef60266332af344acb..7a900f76c9ac3615b4f43f538f88fae0d4d8a492 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -519,8 +519,10 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self, dx_buff->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(aq_nic_get_dev(self), dx_buff->pa))) + if (unlikely(dma_mapping_error(aq_nic_get_dev(self), dx_buff->pa))) { + ret = 0; goto exit; + } first = dx_buff; dx_buff->len_pkt = skb->len; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 69b2f99b0c19d568c3dd6b08f81b7cda7c78218c..123ee5c11bc0c9a0371b935f5e6e60338e0a194d 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -645,7 +645,8 @@ static struct sk_buff *bcm_sysport_rx_refill(struct bcm_sysport_priv *priv, dma_addr_t mapping; /* Allocate a new SKB for a new packet */ - skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH); + skb = __netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH, + GFP_ATOMIC | __GFP_NOWARN); if (!skb) { priv->mib.alloc_rx_buff_failed++; netif_err(priv, rx_err, ndev, "SKB alloc failed\n"); @@ -2329,6 +2330,9 @@ static int bcm_sysport_resume(struct device *d) umac_reset(priv); + /* Disable the UniMAC RX/TX */ + umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0); + /* We may have been suspended and never received a WOL event that * would turn off MPD detection, take care of that now */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7461e7b9eaae5db3d62c67a016c195871852bbd8..5163da01e54f8d0688cc77e38ac2c23135c24680 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5375,7 +5375,7 @@ static void bnxt_setup_msix(struct bnxt *bp) int tcs, i; tcs = netdev_get_num_tc(dev); - if (tcs > 1) { + if (tcs) { int i, off, count; for (i = 0; i < tcs; i++) { @@ -7310,13 +7310,13 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu) struct bnxt *bp = netdev_priv(dev); if (netif_running(dev)) - bnxt_close_nic(bp, false, false); + bnxt_close_nic(bp, true, false); dev->mtu = new_mtu; bnxt_set_ring_params(bp); if (netif_running(dev)) - return bnxt_open_nic(bp, false, false); + return bnxt_open_nic(bp, true, false); return 0; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c index fed37cd9ae1d464af02335c072b4b3676b024e0b..125e22ffe2ae86f0c23ea25cde377fe3b823aff8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c @@ -387,24 +387,26 @@ static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) { struct bnxt *bp = netdev_priv(dev); struct ieee_ets *my_ets = bp->ieee_ets; + int rc; ets->ets_cap = bp->max_tc; if (!my_ets) { - int rc; - if (bp->dcbx_cap & DCB_CAP_DCBX_HOST) return 0; my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL); if (!my_ets) - return 0; + return -ENOMEM; rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets); if (rc) - return 0; + goto error; rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets); if (rc) - return 0; + goto error; + + /* cache result */ + bp->ieee_ets = my_ets; } ets->cbs = my_ets->cbs; @@ -413,6 +415,9 @@ static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); return 0; +error: + kfree(my_ets); + return rc; } static int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 3e3044fe320665123450ab60809acbdc6db95e53..38391230ca8604fded464552868d3b8ca44f470b 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -973,6 +973,8 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev, if (netif_running(dev)) bcmgenet_update_mib_counters(priv); + dev->netdev_ops->ndo_get_stats(dev); + for (i = 0; i < BCMGENET_STATS_LEN; i++) { const struct bcmgenet_stats *s; char *p; @@ -1672,7 +1674,8 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, dma_addr_t mapping; /* Allocate a new Rx skb */ - skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT); + skb = __netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT, + GFP_ATOMIC | __GFP_NOWARN); if (!skb) { priv->mib.alloc_rx_buff_failed++; netif_err(priv, rx_err, priv->dev, @@ -3215,6 +3218,7 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) dev->stats.rx_packets = rx_packets; dev->stats.rx_errors = rx_errors; dev->stats.rx_missed_errors = rx_errors; + dev->stats.rx_dropped = rx_dropped; return &dev->stats; } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 5aff1b460151daee92b05a01edaac5d92c6b5c87..b01b242c2bf00430a1aac057e9a26ec384783866 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -66,7 +66,11 @@ /* Max length of transmit frame must be a multiple of 8 bytes */ #define MACB_TX_LEN_ALIGN 8 #define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) -#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) +/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a + * false amba_error in TX path from the DMA assuming there is not enough + * space in the SRAM (16KB) even when there is. + */ +#define GEM_MAX_TX_LEN (unsigned int)(0x3FC0) #define GEM_MTU_MIN_SIZE ETH_MIN_MTU #define MACB_NETIF_LSO NETIF_F_TSO @@ -1577,16 +1581,14 @@ static netdev_features_t macb_features_check(struct sk_buff *skb, /* Validate LSO compatibility */ - /* there is only one buffer */ - if (!skb_is_nonlinear(skb)) + /* there is only one buffer or protocol is not UDP */ + if (!skb_is_nonlinear(skb) || (ip_hdr(skb)->protocol != IPPROTO_UDP)) return features; /* length of header */ hdrlen = skb_transport_offset(skb); - if (ip_hdr(skb)->protocol == IPPROTO_TCP) - hdrlen += tcp_hdrlen(skb); - /* For LSO: + /* For UFO only: * When software supplies two or more payload buffers all payload buffers * apart from the last must be a multiple of 8 bytes in size. */ diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 586e355933108884db4e01bb950801a6740814e0..d678f088925c6d4d8fc669fb5ebca4eb1585ba8f 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -234,10 +234,19 @@ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) lmac = &bgx->lmac[lmacid]; cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG); - if (enable) + if (enable) { cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN; - else + + /* enable TX FIFO Underflow interrupt */ + bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_INT_ENA_W1S, + GMI_TXX_INT_UNDFLW); + } else { cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN); + + /* Disable TX FIFO Underflow interrupt */ + bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_INT_ENA_W1C, + GMI_TXX_INT_UNDFLW); + } bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg); if (bgx->is_rgx) @@ -1340,6 +1349,48 @@ static int bgx_init_phy(struct bgx *bgx) return bgx_init_of_phy(bgx); } +static irqreturn_t bgx_intr_handler(int irq, void *data) +{ + struct bgx *bgx = (struct bgx *)data; + u64 status, val; + int lmac; + + for (lmac = 0; lmac < bgx->lmac_count; lmac++) { + status = bgx_reg_read(bgx, lmac, BGX_GMP_GMI_TXX_INT); + if (status & GMI_TXX_INT_UNDFLW) { + pci_err(bgx->pdev, "BGX%d lmac%d UNDFLW\n", + bgx->bgx_id, lmac); + val = bgx_reg_read(bgx, lmac, BGX_CMRX_CFG); + val &= ~CMR_EN; + bgx_reg_write(bgx, lmac, BGX_CMRX_CFG, val); + val |= CMR_EN; + bgx_reg_write(bgx, lmac, BGX_CMRX_CFG, val); + } + /* clear interrupts */ + bgx_reg_write(bgx, lmac, BGX_GMP_GMI_TXX_INT, status); + } + + return IRQ_HANDLED; +} + +static void bgx_register_intr(struct pci_dev *pdev) +{ + struct bgx *bgx = pci_get_drvdata(pdev); + int ret; + + ret = pci_alloc_irq_vectors(pdev, BGX_LMAC_VEC_OFFSET, + BGX_LMAC_VEC_OFFSET, PCI_IRQ_ALL_TYPES); + if (ret < 0) { + pci_err(pdev, "Req for #%d msix vectors failed\n", + BGX_LMAC_VEC_OFFSET); + return; + } + ret = pci_request_irq(pdev, GMPX_GMI_TX_INT, bgx_intr_handler, NULL, + bgx, "BGX%d", bgx->bgx_id); + if (ret) + pci_free_irq(pdev, GMPX_GMI_TX_INT, bgx); +} + static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err; @@ -1355,7 +1406,7 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, bgx); - err = pci_enable_device(pdev); + err = pcim_enable_device(pdev); if (err) { dev_err(dev, "Failed to enable PCI device\n"); pci_set_drvdata(pdev, NULL); @@ -1409,6 +1460,8 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bgx_init_hw(bgx); + bgx_register_intr(pdev); + /* Enable all LMACs */ for (lmac = 0; lmac < bgx->lmac_count; lmac++) { err = bgx_lmac_enable(bgx, lmac); @@ -1425,6 +1478,7 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_enable: bgx_vnic[bgx->bgx_id] = NULL; + pci_free_irq(pdev, GMPX_GMI_TX_INT, bgx); err_release_regions: pci_release_regions(pdev); err_disable_device: @@ -1442,6 +1496,8 @@ static void bgx_remove(struct pci_dev *pdev) for (lmac = 0; lmac < bgx->lmac_count; lmac++) bgx_lmac_disable(bgx, lmac); + pci_free_irq(pdev, GMPX_GMI_TX_INT, bgx); + bgx_vnic[bgx->bgx_id] = NULL; pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index 23acdc5ab896306f3f1e6d2fbc7d8afb58273888..adaa3bfa5f6cbbe8ac2af9c86820bcca23c3794e 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h @@ -179,6 +179,15 @@ #define BGX_GMP_GMI_TXX_BURST 0x38228 #define BGX_GMP_GMI_TXX_MIN_PKT 0x38240 #define BGX_GMP_GMI_TXX_SGMII_CTL 0x38300 +#define BGX_GMP_GMI_TXX_INT 0x38500 +#define BGX_GMP_GMI_TXX_INT_W1S 0x38508 +#define BGX_GMP_GMI_TXX_INT_ENA_W1C 0x38510 +#define BGX_GMP_GMI_TXX_INT_ENA_W1S 0x38518 +#define GMI_TXX_INT_PTP_LOST BIT_ULL(4) +#define GMI_TXX_INT_LATE_COL BIT_ULL(3) +#define GMI_TXX_INT_XSDEF BIT_ULL(2) +#define GMI_TXX_INT_XSCOL BIT_ULL(1) +#define GMI_TXX_INT_UNDFLW BIT_ULL(0) #define BGX_MSIX_VEC_0_29_ADDR 0x400000 /* +(0..29) << 4 */ #define BGX_MSIX_VEC_0_29_CTL 0x400008 diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c index 9f9d6cae39d555057ba63ac6ee874d0884c0c51d..ff7e58a8c90fb59c14472ecaf85ecae5c9febd36 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c @@ -246,6 +246,9 @@ static int cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta) FW_PTP_CMD_PORTID_V(0)); c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); c.u.ts.sc = FW_PTP_SC_ADJ_FTIME; + c.u.ts.sign = (delta < 0) ? 1 : 0; + if (delta < 0) + delta = -delta; c.u.ts.tm = cpu_to_be64(delta); err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); @@ -308,32 +311,17 @@ static int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) */ static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { - struct adapter *adapter = (struct adapter *)container_of(ptp, - struct adapter, ptp_clock_info); - struct fw_ptp_cmd c; + struct adapter *adapter = container_of(ptp, struct adapter, + ptp_clock_info); u64 ns; - int err; - memset(&c, 0, sizeof(c)); - c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | - FW_CMD_REQUEST_F | - FW_CMD_READ_F | - FW_PTP_CMD_PORTID_V(0)); - c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); - c.u.ts.sc = FW_PTP_SC_GET_TIME; - - err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), &c); - if (err < 0) { - dev_err(adapter->pdev_dev, - "PTP: %s error %d\n", __func__, -err); - return err; - } + ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A)); + ns |= (u64)t4_read_reg(adapter, + T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32; /* convert to timespec*/ - ns = be64_to_cpu(c.u.ts.tm); *ts = ns_to_timespec64(ns); - - return err; + return 0; } /** diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 39bcf27902e4b286f981c89a1c26e7709c6dcf2b..0f126ce4645f30c6f51130271dcff33ed400f33a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3609,7 +3609,7 @@ int t4_phy_fw_ver(struct adapter *adap, int *phy_fw_ver) FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_VERSION)); ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); - if (ret < 0) + if (ret) return ret; *phy_fw_ver = val; return 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index dac90837842bf1b20e93f8d0810dada4e5c34292..d3df6962cf433d8ad9a0ded83fea9677f2f72c0e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1810,6 +1810,9 @@ #define MAC_PORT_CFG2_A 0x818 +#define MAC_PORT_PTP_SUM_LO_A 0x990 +#define MAC_PORT_PTP_SUM_HI_A 0x994 + #define MPS_CMN_CTL_A 0x9000 #define COUNTPAUSEMCRX_S 5 diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 19f374b180fc1ca0a8f537421e5d39fa76001475..52a3b32390a9c821e3fb047cc4c1dc1ec7eae385 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1972,10 +1972,10 @@ static int enic_stop(struct net_device *netdev) napi_disable(&enic->napi[i]); netif_carrier_off(netdev); - netif_tx_disable(netdev); if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) for (i = 0; i < enic->wq_count; i++) napi_disable(&enic->napi[enic_cq_wq(enic, i)]); + netif_tx_disable(netdev); if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) enic_dev_del_station_addr(enic); diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c index 07e10a45beaafdb3f129561e69b764189692f4a4..cd5309668186ab8a818f6ca9bb4c6180ec1a5d40 100644 --- a/drivers/net/ethernet/dec/tulip/dmfe.c +++ b/drivers/net/ethernet/dec/tulip/dmfe.c @@ -2224,15 +2224,16 @@ static int __init dmfe_init_module(void) if (cr6set) dmfe_cr6_user_set = cr6set; - switch(mode) { - case DMFE_10MHF: + switch (mode) { + case DMFE_10MHF: case DMFE_100MHF: case DMFE_10MFD: case DMFE_100MFD: case DMFE_1M_HPNA: dmfe_media_mode = mode; break; - default:dmfe_media_mode = DMFE_AUTO; + default: + dmfe_media_mode = DMFE_AUTO; break; } diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c index 7fc248efc4baa4e259945978e741d767a4aa1b63..9779555eea25b943622cd26e2425de64c987bb5b 100644 --- a/drivers/net/ethernet/dec/tulip/uli526x.c +++ b/drivers/net/ethernet/dec/tulip/uli526x.c @@ -1819,8 +1819,8 @@ static int __init uli526x_init_module(void) if (cr6set) uli526x_cr6_user_set = cr6set; - switch (mode) { - case ULI526X_10MHF: + switch (mode) { + case ULI526X_10MHF: case ULI526X_100MHF: case ULI526X_10MFD: case ULI526X_100MFD: diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 39b8b6730e77cc448e5a9f38fdb2b9d3e77ba266..67246d42c3d9feecec0f08b9022f20611639b797 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2646,9 +2646,7 @@ static inline u16 dpaa_get_headroom(struct dpaa_buffer_layout *bl) headroom = (u16)(bl->priv_data_size + DPAA_PARSE_RESULTS_SIZE + DPAA_TIME_STAMP_SIZE + DPAA_HASH_RESULTS_SIZE); - return DPAA_FD_DATA_ALIGNMENT ? ALIGN(headroom, - DPAA_FD_DATA_ALIGNMENT) : - headroom; + return ALIGN(headroom, DPAA_FD_DATA_ALIGNMENT); } static int dpaa_eth_probe(struct platform_device *pdev) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 62bc19bedb0692108d6e1a9affae6d40121523c6..8ba915cc4c2e4e40de46b5ec432541d1379dfc18 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2478,15 +2478,15 @@ fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec) return -EINVAL; } - cycle = fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr); + cycle = fec_enet_us_to_itr_clock(ndev, ec->rx_coalesce_usecs); if (cycle > 0xFFFF) { pr_err("Rx coalesced usec exceed hardware limitation\n"); return -EINVAL; } - cycle = fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr); + cycle = fec_enet_us_to_itr_clock(ndev, ec->tx_coalesce_usecs); if (cycle > 0xFFFF) { - pr_err("Rx coalesced usec exceed hardware limitation\n"); + pr_err("Tx coalesced usec exceed hardware limitation\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig index 8870a9a798ca4e0245e6b05ac8d4ee2cf8499b46..91437b94bfcb6a65a8fc8f499be23e8c4c77727a 100644 --- a/drivers/net/ethernet/freescale/fman/Kconfig +++ b/drivers/net/ethernet/freescale/fman/Kconfig @@ -8,3 +8,31 @@ config FSL_FMAN help Freescale Data-Path Acceleration Architecture Frame Manager (FMan) support + +config DPAA_ERRATUM_A050385 + bool + depends on ARM64 && FSL_DPAA + default y + help + DPAA FMan erratum A050385 software workaround implementation: + align buffers, data start, SG fragment length to avoid FMan DMA + splits. + FMAN DMA read or writes under heavy traffic load may cause FMAN + internal resource leak thus stopping further packet processing. + The FMAN internal queue can overflow when FMAN splits single + read or write transactions into multiple smaller transactions + such that more than 17 AXI transactions are in flight from FMAN + to interconnect. When the FMAN internal queue overflows, it can + stall further packet processing. The issue can occur with any + one of the following three conditions: + 1. FMAN AXI transaction crosses 4K address boundary (Errata + A010022) + 2. FMAN DMA address for an AXI transaction is not 16 byte + aligned, i.e. the last 4 bits of an address are non-zero + 3. Scatter Gather (SG) frames have more than one SG buffer in + the SG list and any one of the buffers, except the last + buffer in the SG list has data size that is not a multiple + of 16 bytes, i.e., other than 16, 32, 48, 64, etc. + With any one of the above three conditions present, there is + likelihood of stalled FMAN packet processing, especially under + stress with multiple ports injecting line-rate traffic. diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 97425d94e280d6d12431085e53a0eebed5f12a8e..9080d2332d030d133a656cf702fad5918afcea46 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -1,5 +1,6 @@ /* * Copyright 2008-2015 Freescale Semiconductor Inc. + * Copyright 2020 NXP * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -566,6 +567,10 @@ struct fman_cfg { u32 qmi_def_tnums_thresh; }; +#ifdef CONFIG_DPAA_ERRATUM_A050385 +static bool fman_has_err_a050385; +#endif + static irqreturn_t fman_exceptions(struct fman *fman, enum fman_exceptions exception) { @@ -2517,6 +2522,14 @@ struct fman *fman_bind(struct device *fm_dev) } EXPORT_SYMBOL(fman_bind); +#ifdef CONFIG_DPAA_ERRATUM_A050385 +bool fman_has_errata_a050385(void) +{ + return fman_has_err_a050385; +} +EXPORT_SYMBOL(fman_has_errata_a050385); +#endif + static irqreturn_t fman_err_irq(int irq, void *handle) { struct fman *fman = (struct fman *)handle; @@ -2843,6 +2856,11 @@ static struct fman *read_dts_node(struct platform_device *of_dev) goto fman_free; } +#ifdef CONFIG_DPAA_ERRATUM_A050385 + fman_has_err_a050385 = + of_property_read_bool(fm_node, "fsl,erratum-a050385"); +#endif + return fman; fman_node_put: diff --git a/drivers/net/ethernet/freescale/fman/fman.h b/drivers/net/ethernet/freescale/fman/fman.h index bfa02e0014ae01f4a08a600e0ba27a856c0371f6..693401994fa2dd4d8d49462a28304d043c2d3ce4 100644 --- a/drivers/net/ethernet/freescale/fman/fman.h +++ b/drivers/net/ethernet/freescale/fman/fman.h @@ -1,5 +1,6 @@ /* * Copyright 2008-2015 Freescale Semiconductor Inc. + * Copyright 2020 NXP * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -397,6 +398,10 @@ u16 fman_get_max_frm(void); int fman_get_rx_extra_headroom(void); +#ifdef CONFIG_DPAA_ERRATUM_A050385 +bool fman_has_errata_a050385(void); +#endif + struct fman *fman_bind(struct device *dev); #endif /* __FM_H */ diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 27d0e3b9833cd6dbd7e9262d4f3474b862068aaf..e4a2c74a9b47e74021b94a3ce6b1e7416675d20e 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2685,13 +2685,17 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) skb_dirtytx = tx_queue->skb_dirtytx; while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) { + bool do_tstamp; + + do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en; frags = skb_shinfo(skb)->nr_frags; /* When time stamping, one additional TxBD must be freed. * Also, we need to dma_unmap_single() the TxPAL. */ - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) + if (unlikely(do_tstamp)) nr_txbds = frags + 2; else nr_txbds = frags + 1; @@ -2705,7 +2709,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) (lstatus & BD_LENGTH_MASK)) break; - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { + if (unlikely(do_tstamp)) { next = next_txbd(bdp, base, tx_ring_size); buflen = be16_to_cpu(next->length) + GMAC_FCB_LEN + GMAC_TXPAL_LEN; @@ -2715,7 +2719,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), buflen, DMA_TO_DEVICE); - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { + if (unlikely(do_tstamp)) { struct skb_shared_hwtstamps shhwtstamps; u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) & ~0x7UL); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c index 7d95f0866fb0bdc66ef5fb3b8f8ab14c79232ad3..e1de97effcd240694ad17c1348654db632d612b1 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c @@ -398,7 +398,8 @@ static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq, spin_unlock_bh(&cmdq->cmdq_lock); - if (!wait_for_completion_timeout(&done, CMDQ_TIMEOUT)) { + if (!wait_for_completion_timeout(&done, + msecs_to_jiffies(CMDQ_TIMEOUT))) { spin_lock_bh(&cmdq->cmdq_lock); if (cmdq->errcode[curr_prod_idx] == &errcode) diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c index 79b56744708427eb741a1fc8f964f28beb3f0961..5763e333a9afe58ccc0c851b049569cbd5fd1985 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c @@ -312,6 +312,7 @@ static int set_hw_ioctxt(struct hinic_hwdev *hwdev, unsigned int rq_depth, } hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif); + hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwif); hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT; hw_ioctxt.cmdq_depth = 0; @@ -372,50 +373,6 @@ static int wait_for_db_state(struct hinic_hwdev *hwdev) return -EFAULT; } -static int wait_for_io_stopped(struct hinic_hwdev *hwdev) -{ - struct hinic_cmd_io_status cmd_io_status; - struct hinic_hwif *hwif = hwdev->hwif; - struct pci_dev *pdev = hwif->pdev; - struct hinic_pfhwdev *pfhwdev; - unsigned long end; - u16 out_size; - int err; - - if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) { - dev_err(&pdev->dev, "Unsupported PCI Function type\n"); - return -EINVAL; - } - - pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); - - cmd_io_status.func_idx = HINIC_HWIF_FUNC_IDX(hwif); - - end = jiffies + msecs_to_jiffies(IO_STATUS_TIMEOUT); - do { - err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM, - HINIC_COMM_CMD_IO_STATUS_GET, - &cmd_io_status, sizeof(cmd_io_status), - &cmd_io_status, &out_size, - HINIC_MGMT_MSG_SYNC); - if ((err) || (out_size != sizeof(cmd_io_status))) { - dev_err(&pdev->dev, "Failed to get IO status, ret = %d\n", - err); - return err; - } - - if (cmd_io_status.status == IO_STOPPED) { - dev_info(&pdev->dev, "IO stopped\n"); - return 0; - } - - msleep(20); - } while (time_before(jiffies, end)); - - dev_err(&pdev->dev, "Wait for IO stopped - Timeout\n"); - return -ETIMEDOUT; -} - /** * clear_io_resource - set the IO resources as not active in the NIC * @hwdev: the NIC HW device @@ -435,11 +392,8 @@ static int clear_io_resources(struct hinic_hwdev *hwdev) return -EINVAL; } - err = wait_for_io_stopped(hwdev); - if (err) { - dev_err(&pdev->dev, "IO has not stopped yet\n"); - return err; - } + /* sleep 100ms to wait for firmware stopping I/O */ + msleep(100); cmd_clear_io_res.func_idx = HINIC_HWIF_FUNC_IDX(hwif); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h index 0f5563f3b77988c69d91205ec31396d6326fec78..a011fd2d262702fa539a1ecf75236c1aa461551b 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h @@ -104,8 +104,8 @@ struct hinic_cmd_hw_ioctxt { u8 rsvd2; u8 rsvd3; + u8 ppf_idx; u8 rsvd4; - u8 rsvd5; u16 rq_depth; u16 rx_buf_sz_idx; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h index 5b4760c0e9f531301db219de567198b01b81c995..f683ccbdfca021632455a557e7fccf3827f7460f 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.h @@ -146,6 +146,7 @@ #define HINIC_HWIF_FUNC_IDX(hwif) ((hwif)->attr.func_idx) #define HINIC_HWIF_PCI_INTF(hwif) ((hwif)->attr.pci_intf_idx) #define HINIC_HWIF_PF_IDX(hwif) ((hwif)->attr.pf_idx) +#define HINIC_HWIF_PPF_IDX(hwif) ((hwif)->attr.ppf_idx) #define HINIC_FUNC_TYPE(hwif) ((hwif)->attr.func_type) #define HINIC_IS_PF(hwif) (HINIC_FUNC_TYPE(hwif) == HINIC_PF) diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c index 278dc13f3dae8ccda357cf866adb01ada0d11786..9fcf2e5e000395100a7977f02dfb3b66c02307eb 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c @@ -52,7 +52,7 @@ #define MSG_NOT_RESP 0xFFFF -#define MGMT_MSG_TIMEOUT 1000 +#define MGMT_MSG_TIMEOUT 5000 #define mgmt_to_pfhwdev(pf_mgmt) \ container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt) @@ -276,7 +276,8 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt, goto unlock_sync_msg; } - if (!wait_for_completion_timeout(recv_done, MGMT_MSG_TIMEOUT)) { + if (!wait_for_completion_timeout(recv_done, + msecs_to_jiffies(MGMT_MSG_TIMEOUT))) { dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id); err = -ETIMEDOUT; goto unlock_sync_msg; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a0c64b30f81a7a5b7b400304e1e8844f34ac32a9..a115e51dc2115543bbbd4baec899c5ead8bc8ef1 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2759,11 +2759,10 @@ static int mvneta_poll(struct napi_struct *napi, int budget) /* For the case where the last mvneta_poll did not process all * RX packets */ - rx_queue = fls(((cause_rx_tx >> 8) & 0xff)); - cause_rx_tx |= pp->neta_armada3700 ? pp->cause_rx_tx : port->cause_rx_tx; + rx_queue = fls(((cause_rx_tx >> 8) & 0xff)); if (rx_queue) { rx_queue = rx_queue - 1; if (pp->bm_priv) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index 51e6846da72bccf32a2360ff7093c7a5a616eb03..3c04f3d5de2dc4cacde08fdd2cd8d872dd7087f0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -225,7 +225,7 @@ mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled, start_again: err = devlink_dpipe_entry_ctx_prepare(dump_ctx); if (err) - return err; + goto err_ctx_prepare; j = 0; for (; i < rif_count; i++) { struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); @@ -257,6 +257,7 @@ mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled, return 0; err_entry_append: err_entry_get: +err_ctx_prepare: rtnl_unlock(); devlink_dpipe_entry_clear(&entry); return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 8aace9a06a5d8e7e396bc5504619dacc556278f2..ea47047265053f0dea0d7e6f3cc8713253b12980 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -112,9 +112,11 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, u8 prio = tcf_vlan_push_prio(a); u16 vid = tcf_vlan_push_vid(a); - return mlxsw_sp_acl_rulei_act_vlan(mlxsw_sp, rulei, - action, vid, - proto, prio); + err = mlxsw_sp_acl_rulei_act_vlan(mlxsw_sp, rulei, + action, vid, + proto, prio); + if (err) + return err; } else { dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n"); return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index adbe0a6fe0db912dc12831a74f7bd824ad4ff87f..1b0e1fc7825f9138d6792ad93122e9cad7688904 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -475,21 +475,47 @@ static int msg_enable; */ /** - * ks_rdreg8 - read 8 bit register from device + * ks_check_endian - Check whether endianness of the bus is correct * @ks : The chip information - * @offset: The register address * - * Read a 8bit register from the chip, returning the result + * The KS8851-16MLL EESK pin allows selecting the endianness of the 16bit + * bus. To maintain optimum performance, the bus endianness should be set + * such that it matches the endianness of the CPU. */ -static u8 ks_rdreg8(struct ks_net *ks, int offset) + +static int ks_check_endian(struct ks_net *ks) { - u16 data; - u8 shift_bit = offset & 0x03; - u8 shift_data = (offset & 1) << 3; - ks->cmd_reg_cache = (u16) offset | (u16)(BE0 << shift_bit); - iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); - data = ioread16(ks->hw_addr); - return (u8)(data >> shift_data); + u16 cider; + + /* + * Read CIDER register first, however read it the "wrong" way around. + * If the endian strap on the KS8851-16MLL in incorrect and the chip + * is operating in different endianness than the CPU, then the meaning + * of BE[3:0] byte-enable bits is also swapped such that: + * BE[3,2,1,0] becomes BE[1,0,3,2] + * + * Luckily for us, the byte-enable bits are the top four MSbits of + * the address register and the CIDER register is at offset 0xc0. + * Hence, by reading address 0xc0c0, which is not impacted by endian + * swapping, we assert either BE[3:2] or BE[1:0] while reading the + * CIDER register. + * + * If the bus configuration is correct, reading 0xc0c0 asserts + * BE[3:2] and this read returns 0x0000, because to read register + * with bottom two LSbits of address set to 0, BE[1:0] must be + * asserted. + * + * If the bus configuration is NOT correct, reading 0xc0c0 asserts + * BE[1:0] and this read returns non-zero 0x8872 value. + */ + iowrite16(BE3 | BE2 | KS_CIDER, ks->hw_addr_cmd); + cider = ioread16(ks->hw_addr); + if (!cider) + return 0; + + netdev_err(ks->netdev, "incorrect EESK endian strap setting\n"); + + return -EINVAL; } /** @@ -507,22 +533,6 @@ static u16 ks_rdreg16(struct ks_net *ks, int offset) return ioread16(ks->hw_addr); } -/** - * ks_wrreg8 - write 8bit register value to chip - * @ks: The chip information - * @offset: The register address - * @value: The value to write - * - */ -static void ks_wrreg8(struct ks_net *ks, int offset, u8 value) -{ - u8 shift_bit = (offset & 0x03); - u16 value_write = (u16)(value << ((offset & 1) << 3)); - ks->cmd_reg_cache = (u16)offset | (BE0 << shift_bit); - iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); - iowrite16(value_write, ks->hw_addr); -} - /** * ks_wrreg16 - write 16bit register value to chip * @ks: The chip information @@ -642,8 +652,7 @@ static void ks_read_config(struct ks_net *ks) u16 reg_data = 0; /* Regardless of bus width, 8 bit read should always work.*/ - reg_data = ks_rdreg8(ks, KS_CCR) & 0x00FF; - reg_data |= ks_rdreg8(ks, KS_CCR+1) << 8; + reg_data = ks_rdreg16(ks, KS_CCR); /* addr/data bus are multiplexed */ ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED; @@ -747,7 +756,7 @@ static inline void ks_read_qmu(struct ks_net *ks, u16 *buf, u32 len) /* 1. set sudo DMA mode */ ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI); - ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA); /* 2. read prepend data */ /** @@ -764,7 +773,7 @@ static inline void ks_read_qmu(struct ks_net *ks, u16 *buf, u32 len) ks_inblk(ks, buf, ALIGN(len, 4)); /* 4. reset sudo DMA Mode */ - ks_wrreg8(ks, KS_RXQCR, ks->rc_rxqcr); + ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); } /** @@ -866,14 +875,17 @@ static irqreturn_t ks_irq(int irq, void *pw) { struct net_device *netdev = pw; struct ks_net *ks = netdev_priv(netdev); + unsigned long flags; u16 status; + spin_lock_irqsave(&ks->statelock, flags); /*this should be the first in IRQ handler */ ks_save_cmd_reg(ks); status = ks_rdreg16(ks, KS_ISR); if (unlikely(!status)) { ks_restore_cmd_reg(ks); + spin_unlock_irqrestore(&ks->statelock, flags); return IRQ_NONE; } @@ -899,6 +911,7 @@ static irqreturn_t ks_irq(int irq, void *pw) ks->netdev->stats.rx_over_errors++; /* this should be the last in IRQ handler*/ ks_restore_cmd_reg(ks); + spin_unlock_irqrestore(&ks->statelock, flags); return IRQ_HANDLED; } @@ -968,6 +981,7 @@ static int ks_net_stop(struct net_device *netdev) /* shutdown RX/TX QMU */ ks_disable_qmu(ks); + ks_disable_int(ks); /* set powermode to soft power down to save power */ ks_set_powermode(ks, PMECR_PM_SOFTDOWN); @@ -997,13 +1011,13 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) ks->txh.txw[1] = cpu_to_le16(len); /* 1. set sudo-DMA mode */ - ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA); /* 2. write status/lenth info */ ks_outblk(ks, ks->txh.txw, 4); /* 3. write pkt data */ ks_outblk(ks, (u16 *)pdata, ALIGN(len, 4)); /* 4. reset sudo-DMA mode */ - ks_wrreg8(ks, KS_RXQCR, ks->rc_rxqcr); + ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ ks_wrreg16(ks, KS_TXQCR, TXQCR_METFE); /* 6. wait until TXQCR_METFE is auto-cleared */ @@ -1024,10 +1038,9 @@ static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) { netdev_tx_t retv = NETDEV_TX_OK; struct ks_net *ks = netdev_priv(netdev); + unsigned long flags; - disable_irq(netdev->irq); - ks_disable_int(ks); - spin_lock(&ks->statelock); + spin_lock_irqsave(&ks->statelock, flags); /* Extra space are required: * 4 byte for alignment, 4 for status/length, 4 for CRC @@ -1041,9 +1054,7 @@ static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); } else retv = NETDEV_TX_BUSY; - spin_unlock(&ks->statelock); - ks_enable_int(ks); - enable_irq(netdev->irq); + spin_unlock_irqrestore(&ks->statelock, flags); return retv; } @@ -1572,6 +1583,10 @@ static int ks8851_probe(struct platform_device *pdev) goto err_free; } + err = ks_check_endian(ks); + if (err) + goto err_free; + netdev->irq = platform_get_irq(pdev, 0); if ((int)netdev->irq < 0) { diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.h b/drivers/net/ethernet/neterion/vxge/vxge-config.h index cfa970417f818036bc83d6ed22deeb47cea28e90..fe4a4315d20d465416df53773e0475ccbab9ed18 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.h +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.h @@ -2065,7 +2065,7 @@ vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask); if ((level >= VXGE_ERR && VXGE_COMPONENT_LL & VXGE_DEBUG_ERR_MASK) || \ (level >= VXGE_TRACE && VXGE_COMPONENT_LL & VXGE_DEBUG_TRACE_MASK))\ if ((mask & VXGE_DEBUG_MASK) == mask) \ - printk(fmt "\n", __VA_ARGS__); \ + printk(fmt "\n", ##__VA_ARGS__); \ } while (0) #else #define vxge_debug_ll(level, mask, fmt, ...) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.h b/drivers/net/ethernet/neterion/vxge/vxge-main.h index 3a79d93b8445308663b5b02f06e172762faba708..5b535aa10d23e263c324cd961be90e3fad0f26b7 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.h +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.h @@ -454,49 +454,49 @@ int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override); #if (VXGE_DEBUG_LL_CONFIG & VXGE_DEBUG_MASK) #define vxge_debug_ll_config(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, ##__VA_ARGS__) #else #define vxge_debug_ll_config(level, fmt, ...) #endif #if (VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) #define vxge_debug_init(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, ##__VA_ARGS__) #else #define vxge_debug_init(level, fmt, ...) #endif #if (VXGE_DEBUG_TX & VXGE_DEBUG_MASK) #define vxge_debug_tx(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, ##__VA_ARGS__) #else #define vxge_debug_tx(level, fmt, ...) #endif #if (VXGE_DEBUG_RX & VXGE_DEBUG_MASK) #define vxge_debug_rx(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, ##__VA_ARGS__) #else #define vxge_debug_rx(level, fmt, ...) #endif #if (VXGE_DEBUG_MEM & VXGE_DEBUG_MASK) #define vxge_debug_mem(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, ##__VA_ARGS__) #else #define vxge_debug_mem(level, fmt, ...) #endif #if (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK) #define vxge_debug_entryexit(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, ##__VA_ARGS__) #else #define vxge_debug_entryexit(level, fmt, ...) #endif #if (VXGE_DEBUG_INTR & VXGE_DEBUG_MASK) #define vxge_debug_intr(level, fmt, ...) \ - vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, __VA_ARGS__) + vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, ##__VA_ARGS__) #else #define vxge_debug_intr(level, fmt, ...) #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index c4e8bf0773fe980c5e0e10ebdb0507dd6a697e87..6024b832b4d95693f02e6aad6117503a9ace33db 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -3151,26 +3151,20 @@ static void qed_chain_free_single(struct qed_dev *cdev, static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) { - void **pp_virt_addr_tbl = p_chain->pbl.pp_virt_addr_tbl; + struct addr_tbl_entry *pp_addr_tbl = p_chain->pbl.pp_addr_tbl; u32 page_cnt = p_chain->page_cnt, i, pbl_size; - u8 *p_pbl_virt = p_chain->pbl_sp.p_virt_table; - if (!pp_virt_addr_tbl) + if (!pp_addr_tbl) return; - if (!p_pbl_virt) - goto out; - for (i = 0; i < page_cnt; i++) { - if (!pp_virt_addr_tbl[i]) + if (!pp_addr_tbl[i].virt_addr || !pp_addr_tbl[i].dma_map) break; dma_free_coherent(&cdev->pdev->dev, QED_CHAIN_PAGE_SIZE, - pp_virt_addr_tbl[i], - *(dma_addr_t *)p_pbl_virt); - - p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE; + pp_addr_tbl[i].virt_addr, + pp_addr_tbl[i].dma_map); } pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; @@ -3180,9 +3174,9 @@ static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) pbl_size, p_chain->pbl_sp.p_virt_table, p_chain->pbl_sp.p_phys_table); -out: - vfree(p_chain->pbl.pp_virt_addr_tbl); - p_chain->pbl.pp_virt_addr_tbl = NULL; + + vfree(p_chain->pbl.pp_addr_tbl); + p_chain->pbl.pp_addr_tbl = NULL; } void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain) @@ -3283,19 +3277,19 @@ qed_chain_alloc_pbl(struct qed_dev *cdev, { u32 page_cnt = p_chain->page_cnt, size, i; dma_addr_t p_phys = 0, p_pbl_phys = 0; - void **pp_virt_addr_tbl = NULL; + struct addr_tbl_entry *pp_addr_tbl; u8 *p_pbl_virt = NULL; void *p_virt = NULL; - size = page_cnt * sizeof(*pp_virt_addr_tbl); - pp_virt_addr_tbl = vzalloc(size); - if (!pp_virt_addr_tbl) + size = page_cnt * sizeof(*pp_addr_tbl); + pp_addr_tbl = vzalloc(size); + if (!pp_addr_tbl) return -ENOMEM; /* The allocation of the PBL table is done with its full size, since it * is expected to be successive. * qed_chain_init_pbl_mem() is called even in a case of an allocation - * failure, since pp_virt_addr_tbl was previously allocated, and it + * failure, since tbl was previously allocated, and it * should be saved to allow its freeing during the error flow. */ size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; @@ -3309,8 +3303,7 @@ qed_chain_alloc_pbl(struct qed_dev *cdev, p_chain->b_external_pbl = true; } - qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, - pp_virt_addr_tbl); + qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, pp_addr_tbl); if (!p_pbl_virt) return -ENOMEM; @@ -3329,7 +3322,8 @@ qed_chain_alloc_pbl(struct qed_dev *cdev, /* Fill the PBL table with the physical address of the page */ *(dma_addr_t *)p_pbl_virt = p_phys; /* Keep the virtual address of the page */ - p_chain->pbl.pp_virt_addr_tbl[i] = p_virt; + p_chain->pbl.pp_addr_tbl[i].virt_addr = p_virt; + p_chain->pbl.pp_addr_tbl[i].dma_map = p_phys; p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE; } diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index adb700512baa90ee252b0ca6a28c707ae527375f..a80531b5aeccdd9bf786a46365f8b4db866af289 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -156,6 +156,8 @@ struct qede_rdma_dev { struct list_head entry; struct list_head rdma_event_list; struct workqueue_struct *rdma_wq; + struct kref refcnt; + struct completion event_comp; }; struct qede_ptp; diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c index 1900bf7e67d1297dc9b24648e99d0ec50f779305..cd12fb919ad574ba5f46207d0315518f652631f7 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -57,6 +57,9 @@ static void _qede_rdma_dev_add(struct qede_dev *edev) static int qede_rdma_create_wq(struct qede_dev *edev) { INIT_LIST_HEAD(&edev->rdma_info.rdma_event_list); + kref_init(&edev->rdma_info.refcnt); + init_completion(&edev->rdma_info.event_comp); + edev->rdma_info.rdma_wq = create_singlethread_workqueue("rdma_wq"); if (!edev->rdma_info.rdma_wq) { DP_NOTICE(edev, "qedr: Could not create workqueue\n"); @@ -81,8 +84,23 @@ static void qede_rdma_cleanup_event(struct qede_dev *edev) } } +static void qede_rdma_complete_event(struct kref *ref) +{ + struct qede_rdma_dev *rdma_dev = + container_of(ref, struct qede_rdma_dev, refcnt); + + /* no more events will be added after this */ + complete(&rdma_dev->event_comp); +} + static void qede_rdma_destroy_wq(struct qede_dev *edev) { + /* Avoid race with add_event flow, make sure it finishes before + * we start accessing the list and cleaning up the work + */ + kref_put(&edev->rdma_info.refcnt, qede_rdma_complete_event); + wait_for_completion(&edev->rdma_info.event_comp); + qede_rdma_cleanup_event(edev); destroy_workqueue(edev->rdma_info.rdma_wq); } @@ -287,15 +305,24 @@ static void qede_rdma_add_event(struct qede_dev *edev, if (!edev->rdma_info.qedr_dev) return; + /* We don't want the cleanup flow to start while we're allocating and + * scheduling the work + */ + if (!kref_get_unless_zero(&edev->rdma_info.refcnt)) + return; /* already being destroyed */ + event_node = qede_rdma_get_free_event_node(edev); if (!event_node) - return; + goto out; event_node->event = event; event_node->ptr = edev; INIT_WORK(&event_node->work, qede_rdma_handle_event); queue_work(edev->rdma_info.rdma_wq, &event_node->work); + +out: + kref_put(&edev->rdma_info.refcnt, qede_rdma_complete_event); } void qede_rdma_dev_event_open(struct qede_dev *edev) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 07f9067affc65ea4d73543c18016174217c1971a..cda5b0a9e9489b71c19871c3193332a88127771b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1720,7 +1720,7 @@ static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_d ahw->reset.seq_error = 0; ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL); - if (p_dev->ahw->reset.buff == NULL) + if (ahw->reset.buff == NULL) return -ENOMEM; p_buff = p_dev->ahw->reset.buff; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 390323cadb9228a62c39549fe165721e5a9b6472..99d66239907dd7adf87df9b02d531344a1cc1a62 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -183,6 +183,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, data_format = RMNET_INGRESS_FORMAT_IP_ROUTE | RMNET_EGRESS_FORMAT_IP_ROUTE; + if (!tb[IFLA_LINK]) { + NL_SET_ERR_MSG_MOD(extack, "link not specified"); + return -EINVAL; + } + real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev || !dev) return -ENODEV; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c index 3ee89fdd8c54bfb6df67bf0f627cc2efb2741994..2e658278fa709b3483fea331325b10e76b4cda56 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c @@ -103,6 +103,7 @@ EXPORT_SYMBOL(rmnet_descriptor_add_frag); int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc, int start, u8 *nexthdrp, __be16 *fragp) { + u32 frag_size = skb_frag_size(&frag_desc->frag); u8 nexthdr = *nexthdrp; *fragp = 0; @@ -114,11 +115,17 @@ int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc, if (nexthdr == NEXTHDR_NONE) return -EINVAL; - hp = rmnet_frag_data_ptr(frag_desc) + start; + if (start >= frag_size) + return -EINVAL; + hp = rmnet_frag_data_ptr(frag_desc) + start; if (nexthdr == NEXTHDR_FRAGMENT) { __be16 *fp; + if (start + offsetof(struct frag_hdr, frag_off) >= + frag_size) + return -EINVAL; + fp = rmnet_frag_data_ptr(frag_desc) + start + offsetof(struct frag_hdr, frag_off); *fragp = *fp; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 89831adb8eb75c51e00f7e919880601d8e57fa55..6d27eec85fcef920f07c3c280d0df6e6d088e4d7 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -2284,7 +2284,7 @@ static int __init sxgbe_cmdline_opt(char *str) if (!str || !*str) return -EINVAL; while ((opt = strsep(&str, ",")) != NULL) { - if (!strncmp(opt, "eee_timer:", 6)) { + if (!strncmp(opt, "eee_timer:", 10)) { if (kstrtoint(opt + 10, 0, &eee_timer)) goto err; } diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index b9cb697b281847a83aa511c577a6c790516f8012..e0d4c1e850cfe42cf8c84c9cf49b43c816009b1f 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -505,6 +505,7 @@ efx_copy_channel(const struct efx_channel *old_channel) if (tx_queue->channel) tx_queue->channel = channel; tx_queue->buffer = NULL; + tx_queue->cb_page = NULL; memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); } diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 42d35a87bcc9f4e3ba83980473fc44a566640b59..f4f52a64f450a0edb8639c6fcf60597446dde6ec 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -948,7 +948,7 @@ static void smc911x_phy_configure(struct work_struct *work) if (lp->ctl_rspeed != 100) my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); - if (!lp->ctl_rfduplx) + if (!lp->ctl_rfduplx) my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); /* Update our Auto-Neg Advertisement Register */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index b54efdad26d5fb274893c5d2f93c12db66ade2c3..3e5177bad9c7b9af56b3682c23aed9dab2cd45e2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -23,14 +23,22 @@ #include #include #include - #include "stmmac.h" #include "stmmac_platform.h" #include "dwmac-qcom-ethqos.h" #include "stmmac_ptp.h" #include "dwmac-qcom-ipa-offload.h" +#define PHY_LOOPBACK_1000 0x4140 +#define PHY_LOOPBACK_100 0x6100 +#define PHY_LOOPBACK_10 0x4100 + static void __iomem *tlmm_central_base_addr; +static void ethqos_rgmii_io_macro_loopback(struct qcom_ethqos *ethqos, + int mode); +static int phy_digital_loopback_config( + struct qcom_ethqos *ethqos, int speed, int config); + bool phy_intr_en; static struct ethqos_emac_por emac_por[] = { @@ -60,7 +68,7 @@ int stmmac_enable_ipc_low; char tmp_buff[MAX_PROC_SIZE]; static struct qmp_pkt pkt; static char qmp_buf[MAX_QMP_MSG_SIZE + 1] = {0}; -static struct ip_params pparams = {"", "", "", ""}; +static struct ip_params pparams; static void qcom_ethqos_read_iomacro_por_values(struct qcom_ethqos *ethqos) { @@ -77,7 +85,7 @@ static void qcom_ethqos_read_iomacro_por_values(struct qcom_ethqos *ethqos) ethqos->por[i].offset); } -static inline unsigned int dwmac_qcom_get_eth_type(unsigned char *buf) +unsigned int dwmac_qcom_get_eth_type(unsigned char *buf) { return ((((u16)buf[QTAG_ETH_TYPE_OFFSET] << 8) | @@ -617,9 +625,10 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 0, SDCC_HC_REG_DLL_CONFIG); - /* Set DLL_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, - SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); + if (!ethqos->io_macro.rx_dll_bypass) + /* Set DLL_EN */ + rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, + SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); if (ethqos->emac_ver != EMAC_HW_v2_3_2 && ethqos->emac_ver != EMAC_HW_v2_1_2) { @@ -664,8 +673,9 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) if (ethqos->emac_ver != EMAC_HW_v2_3_2 && ethqos->emac_ver != EMAC_HW_v2_1_2) { - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, - 0, SDCC_HC_REG_DLL_CONFIG2); + if (!ethqos->io_macro.rx_dll_bypass) + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, + 0, SDCC_HC_REG_DLL_CONFIG2); rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); @@ -715,15 +725,19 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) RGMII_IO_MACRO_CONFIG2); /* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */ - if (ethqos->emac_ver == EMAC_HW_v2_3_2) + if (ethqos->emac_ver == EMAC_HW_v2_3_2) { rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 69, SDCC_HC_REG_DDR_CONFIG); - else if (ethqos->emac_ver == EMAC_HW_v2_1_2) + } else if (ethqos->emac_ver == EMAC_HW_v2_1_2) { rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 52, SDCC_HC_REG_DDR_CONFIG); - else - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, - 57, SDCC_HC_REG_DDR_CONFIG); + } else { + if (!ethqos->io_macro.rx_dll_bypass) + rgmii_updatel(ethqos, + SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 57, SDCC_HC_REG_DDR_CONFIG); + } + rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_HC_REG_DDR_CONFIG); @@ -757,8 +771,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) BIT(6), RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - if (ethqos->emac_ver == EMAC_HW_v2_3_2 || - ethqos->emac_ver == EMAC_HW_v2_1_2) + if (ethqos->io_macro.rx_prog_swap) rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); @@ -812,8 +825,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - if (ethqos->emac_ver == EMAC_HW_v2_3_2 || - ethqos->emac_ver == EMAC_HW_v2_1_2) + if (ethqos->io_macro.rx_prog_swap) rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); @@ -877,33 +889,56 @@ static int ethqos_configure(struct qcom_ethqos *ethqos) SDCC_HC_REG_DLL_CONFIG); if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) { - /* Set DLL_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, - SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); + if (ethqos->io_macro.rx_dll_bypass) { + /* Set DLL_CLOCK_DISABLE */ + rgmii_updatel(ethqos, + SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, + SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, + SDCC_HC_REG_DLL_CONFIG2); - /* Set CK_OUT_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, - SDCC_DLL_CONFIG_CK_OUT_EN, - SDCC_HC_REG_DLL_CONFIG); - - /* Set USR_CTL bit 26 with mask of 3 bits */ - rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), SDCC_USR_CTL); - - /* wait for DLL LOCK */ - do { - mdelay(1); - dll_lock = rgmii_readl(ethqos, SDC4_STATUS); - if (dll_lock & SDC4_STATUS_DLL_LOCK) - break; - retry--; - } while (retry > 0); - if (!retry) - dev_err(ðqos->pdev->dev, - "Timeout while waiting for DLL lock\n"); - } + /* Clear DLL_EN */ + rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, + 0, SDCC_HC_REG_DLL_CONFIG); + + /* Set PDN */ + rgmii_updatel(ethqos, + SDCC_DLL_CONFIG_PDN, + SDCC_DLL_CONFIG_PDN, + SDCC_HC_REG_DLL_CONFIG); + + /* Set USR_CTL bit 30 */ + rgmii_updatel(ethqos, BIT(30), BIT(30), SDCC_USR_CTL); + } else { + /* Set DLL_EN */ + rgmii_updatel(ethqos, + SDCC_DLL_CONFIG_DLL_EN, + SDCC_DLL_CONFIG_DLL_EN, + SDCC_HC_REG_DLL_CONFIG); + + /* Set CK_OUT_EN */ + rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, + SDCC_DLL_CONFIG_CK_OUT_EN, + SDCC_HC_REG_DLL_CONFIG); + + /* Set USR_CTL bit 26 with mask of 3 bits */ + rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), + SDCC_USR_CTL); + + /* wait for DLL LOCK */ + do { + mdelay(1); + dll_lock = rgmii_readl(ethqos, SDC4_STATUS); + if (dll_lock & SDC4_STATUS_DLL_LOCK) + break; + retry--; + } while (retry > 0); + if (!retry) + dev_err(ðqos->pdev->dev, + "Timeout while waiting for DLL lock\n"); + } - if (ethqos->speed == SPEED_1000) ethqos_dll_configure(ethqos); + } ethqos_rgmii_macro_init(ethqos); @@ -926,6 +961,12 @@ static int ethqos_mdio_read(struct stmmac_priv *priv, int phyaddr, int phyreg) u32 v; int data; u32 value = MII_BUSY; + struct qcom_ethqos *ethqos = priv->plat->bsp_priv; + + if (ethqos->phy_state == PHY_IS_OFF) { + ETHQOSINFO("Phy is in off state reading is not possible\n"); + return -EOPNOTSUPP; + } value |= (phyaddr << priv->hw->mii.addr_shift) & priv->hw->mii.addr_mask; @@ -1042,9 +1083,15 @@ static irqreturn_t ETHQOS_PHY_ISR(int irq, void *dev_data) return IRQ_HANDLED; } -static int ethqos_phy_intr_enable(struct qcom_ethqos *ethqos) +int ethqos_phy_intr_enable(struct stmmac_priv *priv) { int ret = 0; + struct qcom_ethqos *ethqos = priv->plat->bsp_priv; + + if (ethqos_phy_intr_config(ethqos)) { + ret = 1; + return ret; + } INIT_WORK(ðqos->emac_phy_work, ethqos_defer_phy_isr_work); init_completion(ðqos->clk_enable_done); @@ -1056,7 +1103,6 @@ static int ethqos_phy_intr_enable(struct qcom_ethqos *ethqos) ethqos->phy_intr); return ret; } - phy_intr_en = true; return ret; } @@ -1102,6 +1148,10 @@ static ssize_t read_phy_reg_dump(struct file *file, char __user *user_buf, ETHQOSERR("NULL Pointer\n"); return -EINVAL; } + if (ethqos->phy_state == PHY_IS_OFF) { + ETHQOSINFO("Phy is in off state phy dump is not possible\n"); + return -EOPNOTSUPP; + } buf = kzalloc(buf_len, GFP_KERNEL); if (!buf) @@ -1198,6 +1248,487 @@ static ssize_t read_rgmii_reg_dump(struct file *file, return ret_cnt; } +static ssize_t read_phy_off(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + unsigned int len = 0, buf_len = 2000; + char *buf; + ssize_t ret_cnt; + struct qcom_ethqos *ethqos = file->private_data; + + if (!ethqos) { + ETHQOSERR("NULL Pointer\n"); + return -EINVAL; + } + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (ethqos->current_phy_mode == DISABLE_PHY_IMMEDIATELY) + len += scnprintf(buf + len, buf_len - len, + "Disable phy immediately enabled\n"); + else if (ethqos->current_phy_mode == ENABLE_PHY_IMMEDIATELY) + len += scnprintf(buf + len, buf_len - len, + "Enable phy immediately enabled\n"); + else if (ethqos->current_phy_mode == DISABLE_PHY_AT_SUSPEND_ONLY) { + len += scnprintf(buf + len, buf_len - len, + "Disable Phy at suspend\n"); + len += scnprintf(buf + len, buf_len - len, + " & do not enable at resume enabled\n"); + } else if (ethqos->current_phy_mode == + DISABLE_PHY_SUSPEND_ENABLE_RESUME) { + len += scnprintf(buf + len, buf_len - len, + "Disable Phy at suspend\n"); + len += scnprintf(buf + len, buf_len - len, + " & enable at resume enabled\n"); + } else if (ethqos->current_phy_mode == DISABLE_PHY_ON_OFF) + len += scnprintf(buf + len, buf_len - len, + "Disable phy on/off disabled\n"); + else + len += scnprintf(buf + len, buf_len - len, + "Invalid Phy State\n"); + + if (len > buf_len) { + ETHQOSERR("(len > buf_len) buffer not sufficient\n"); + len = buf_len; + } + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret_cnt; +} + +static ssize_t phy_off_config( + struct file *file, const char __user *user_buffer, + size_t count, loff_t *position) +{ + char *in_buf; + int buf_len = 2000; + unsigned long ret; + int config = 0; + struct qcom_ethqos *ethqos = file->private_data; + + in_buf = kzalloc(buf_len, GFP_KERNEL); + if (!in_buf) + return -ENOMEM; + + ret = copy_from_user(in_buf, user_buffer, buf_len); + if (ret) { + ETHQOSERR("unable to copy from user\n"); + return -EFAULT; + } + + ret = sscanf(in_buf, "%d", &config); + if (ret != 1) { + ETHQOSERR("Error in reading option from user"); + return -EINVAL; + } + if (config > DISABLE_PHY_ON_OFF || config < DISABLE_PHY_IMMEDIATELY) { + ETHQOSERR("Invalid option =%d", config); + return -EINVAL; + } + if (config == ethqos->current_phy_mode) { + ETHQOSERR("No effect as duplicate config"); + return -EPERM; + } + if (config == DISABLE_PHY_IMMEDIATELY) { + ethqos->current_phy_mode = DISABLE_PHY_IMMEDIATELY; + //make phy off + if (ethqos->current_loopback == ENABLE_PHY_LOOPBACK) { + /* If Phy loopback is enabled + * Disabled It before phy off + */ + phy_digital_loopback_config(ethqos, + ethqos->loopback_speed, 0); + ETHQOSDBG("Disable phy Loopback"); + ethqos->current_loopback = ENABLE_PHY_LOOPBACK; + } + ethqos_phy_power_off(ethqos); + } else if (config == ENABLE_PHY_IMMEDIATELY) { + ethqos->current_phy_mode = ENABLE_PHY_IMMEDIATELY; + //make phy on + ethqos_phy_power_on(ethqos); + ethqos_reset_phy_enable_interrupt(ethqos); + if (ethqos->current_loopback == ENABLE_PHY_LOOPBACK) { + /*If Phy loopback is enabled , enabled It again*/ + phy_digital_loopback_config(ethqos, + ethqos->loopback_speed, 1); + ETHQOSDBG("Enabling Phy loopback again"); + } + } else if (config == DISABLE_PHY_AT_SUSPEND_ONLY) { + ethqos->current_phy_mode = DISABLE_PHY_AT_SUSPEND_ONLY; + } else if (config == DISABLE_PHY_SUSPEND_ENABLE_RESUME) { + ethqos->current_phy_mode = DISABLE_PHY_SUSPEND_ENABLE_RESUME; + } else if (config == DISABLE_PHY_ON_OFF) { + ethqos->current_phy_mode = DISABLE_PHY_ON_OFF; + } else { + ETHQOSERR("Invalid option\n"); + return -EINVAL; + } + kfree(in_buf); + return count; +} + +static void ethqos_rgmii_io_macro_loopback(struct qcom_ethqos *ethqos, int mode) +{ + /* Set loopback mode */ + if (mode == 1) { + rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, + RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG2); + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + 0, RGMII_IO_MACRO_CONFIG2); + } else { + rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, + 0, RGMII_IO_MACRO_CONFIG2); + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); + } +} + +static void ethqos_mac_loopback(struct qcom_ethqos *ethqos, int mode) +{ + u32 read_value = (u32)readl_relaxed(ethqos->ioaddr + MAC_CONFIGURATION); + /* Set loopback mode */ + if (mode == 1) + read_value |= MAC_LM; + else + read_value &= ~MAC_LM; + writel_relaxed(read_value, ethqos->ioaddr + MAC_CONFIGURATION); +} + +static int phy_digital_loopback_config( + struct qcom_ethqos *ethqos, int speed, int config) +{ + struct platform_device *pdev = ethqos->pdev; + struct net_device *dev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(dev); + int phydata = 0; + + if (config == 1) { + ETHQOSINFO("Request for phy digital loopback enable\n"); + switch (speed) { + case SPEED_1000: + phydata = PHY_LOOPBACK_1000; + break; + case SPEED_100: + phydata = PHY_LOOPBACK_100; + break; + case SPEED_10: + phydata = PHY_LOOPBACK_10; + break; + default: + ETHQOSERR("Invalid link speed\n"); + break; + } + } else if (config == 0) { + ETHQOSINFO("Request for phy digital loopback disable\n"); + if (ethqos->bmcr_backup) + phydata = ethqos->bmcr_backup; + else + phydata = 0x1140; + } else { + ETHQOSERR("Invalid option\n"); + return -EINVAL; + } + if (phydata != 0) { + if (priv->phydev) { + phy_write(priv->phydev, MII_BMCR, phydata); + ETHQOSINFO("write done for phy loopback\n"); + } else { + ETHQOSINFO("Phy dev is NULL\n"); + } + } + return 0; +} + +static void print_loopback_detail(enum loopback_mode loopback) +{ + switch (loopback) { + case DISABLE_LOOPBACK: + ETHQOSINFO("Loopback is disabled\n"); + break; + case ENABLE_IO_MACRO_LOOPBACK: + ETHQOSINFO("Loopback is Enabled as IO MACRO LOOPBACK\n"); + break; + case ENABLE_MAC_LOOPBACK: + ETHQOSINFO("Loopback is Enabled as MAC LOOPBACK\n"); + break; + case ENABLE_PHY_LOOPBACK: + ETHQOSINFO("Loopback is Enabled as PHY LOOPBACK\n"); + break; + default: + ETHQOSINFO("Invalid Loopback=%d\n", loopback); + break; + } +} + +static void setup_config_registers(struct qcom_ethqos *ethqos, + int speed, int duplex, int mode) +{ + struct platform_device *pdev = ethqos->pdev; + struct net_device *dev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(dev); + u32 ctrl = 0; + + ETHQOSDBG("Speed=%d,dupex=%d,mode=%d\n", speed, duplex, mode); + + if (mode > DISABLE_LOOPBACK && !qcom_ethqos_is_phy_link_up(ethqos)) { + /*If Link is Down & need to enable Loopback*/ + ETHQOSDBG("Enable Lower Up Flag & disable phy dev\n"); + ETHQOSDBG("IRQ so that Rx/Tx can happen beforeee Link down\n"); + netif_carrier_on(dev); + /*Disable phy interrupt by Link/Down by cable plug in/out*/ + disable_irq(ethqos->phy_intr); + } else if (mode > DISABLE_LOOPBACK && + qcom_ethqos_is_phy_link_up(ethqos)) { + ETHQOSDBG("Only disable phy irqqq Lin is UP\n"); + /*Since link is up no need to set Lower UP flag*/ + /*Disable phy interrupt by Link/Down by cable plug in/out*/ + disable_irq(ethqos->phy_intr); + } else if (mode == DISABLE_LOOPBACK && + !qcom_ethqos_is_phy_link_up(ethqos)) { + ETHQOSDBG("Disable Lower Up as Link is down\n"); + netif_carrier_off(dev); + enable_irq(ethqos->phy_intr); + } + ETHQOSDBG("Old ctrl=%d dupex full\n", ctrl); + ctrl = readl_relaxed(priv->ioaddr + MAC_CTRL_REG); + ETHQOSDBG("Old ctrl=0x%x with mask with flow control\n", ctrl); + + ctrl |= priv->hw->link.duplex; + priv->dev->phydev->duplex = duplex; + ctrl &= ~priv->hw->link.speed_mask; + switch (speed) { + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + break; + case SPEED_100: + ctrl |= priv->hw->link.speed100; + break; + case SPEED_10: + ctrl |= priv->hw->link.speed10; + break; + default: + speed = SPEED_UNKNOWN; + ETHQOSDBG("unkwon speed\n"); + break; + } + writel_relaxed(ctrl, priv->ioaddr + MAC_CTRL_REG); + ETHQOSDBG("New ctrl=%x priv hw speeed =%d\n", ctrl, + priv->hw->link.speed1000); + priv->dev->phydev->speed = speed; + priv->speed = speed; + + if (mode > DISABLE_LOOPBACK && !qcom_ethqos_is_phy_link_up(ethqos)) { + /*If Link is Down & need to enable Loopback*/ + ETHQOSDBG("Link is down . manual ipa setting up\n"); + if (priv->tx_queue[IPA_DMA_TX_CH].skip_sw) + ethqos_ipa_offload_event_handler(priv, + EV_PHY_LINK_UP); + } else if (mode == DISABLE_LOOPBACK && + !qcom_ethqos_is_phy_link_up(ethqos)) { + ETHQOSDBG("Disable request since link was down disable ipa\n"); + if (priv->tx_queue[IPA_DMA_TX_CH].skip_sw) + ethqos_ipa_offload_event_handler(priv, + EV_PHY_LINK_DOWN); + } + + if (priv->dev->phydev->speed != SPEED_UNKNOWN) + ethqos_fix_mac_speed(ethqos, speed); + + if (mode > DISABLE_LOOPBACK) { + if (mode == ENABLE_MAC_LOOPBACK || + mode == ENABLE_IO_MACRO_LOOPBACK) + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + RGMII_CONFIG_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG); + } else if (mode == DISABLE_LOOPBACK) { + if (ethqos->emac_ver == EMAC_HW_v2_3_2 || + ethqos->emac_ver == EMAC_HW_v2_1_2) + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + 0, RGMII_IO_MACRO_CONFIG); + } + ETHQOSERR("End\n"); +} + +static ssize_t loopback_handling_config( + struct file *file, const char __user *user_buffer, + size_t count, loff_t *position) +{ + char *in_buf; + int buf_len = 2000; + unsigned long ret; + int config = 0; + struct qcom_ethqos *ethqos = file->private_data; + struct platform_device *pdev = ethqos->pdev; + struct net_device *dev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(dev); + int speed = 0; + + in_buf = kzalloc(buf_len, GFP_KERNEL); + if (!in_buf) + return -ENOMEM; + + ret = copy_from_user(in_buf, user_buffer, buf_len); + if (ret) { + ETHQOSERR("unable to copy from user\n"); + return -EFAULT; + } + + ret = sscanf(in_buf, "%d %d", &config, &speed); + if (config > DISABLE_LOOPBACK && ret != 2) { + ETHQOSERR("Speed is also needed while enabling loopback\n"); + return -EINVAL; + } + if (config < DISABLE_LOOPBACK || config > ENABLE_PHY_LOOPBACK) { + ETHQOSERR("Invalid config =%d\n", config); + return -EINVAL; + } + if ((config == ENABLE_PHY_LOOPBACK || ethqos->current_loopback == + ENABLE_PHY_LOOPBACK) && + ethqos->current_phy_mode == DISABLE_PHY_IMMEDIATELY) { + ETHQOSERR("Can't enabled/disable "); + ETHQOSERR("phy loopback when phy is off\n"); + return -EPERM; + } + + /*Argument validation*/ + if (config == DISABLE_LOOPBACK || config == ENABLE_IO_MACRO_LOOPBACK || + config == ENABLE_MAC_LOOPBACK || config == ENABLE_PHY_LOOPBACK) { + if (speed != SPEED_1000 && speed != SPEED_100 && + speed != SPEED_10) + return -EINVAL; + } else { + return -EINVAL; + } + + if (config == ethqos->current_loopback) { + switch (config) { + case DISABLE_LOOPBACK: + ETHQOSINFO("Loopback is already disabled\n"); + break; + case ENABLE_IO_MACRO_LOOPBACK: + ETHQOSINFO("Loopback is already Enabled as "); + ETHQOSINFO("IO MACRO LOOPBACK\n"); + break; + case ENABLE_MAC_LOOPBACK: + ETHQOSINFO("Loopback is already Enabled as "); + ETHQOSINFO("MAC LOOPBACK\n"); + break; + case ENABLE_PHY_LOOPBACK: + ETHQOSINFO("Loopback is already Enabled as "); + ETHQOSINFO("PHY LOOPBACK\n"); + break; + } + return -EINVAL; + } + /*If request to enable loopback & some other loopback already enabled*/ + if (config != DISABLE_LOOPBACK && + ethqos->current_loopback > DISABLE_LOOPBACK) { + ETHQOSINFO("Loopback is already enabled\n"); + print_loopback_detail(ethqos->current_loopback); + return -EINVAL; + } + ETHQOSINFO("enable loopback = %d with link speed = %d backup now\n", + config, speed); + + /*Backup speed & duplex before Enabling Loopback */ + if (ethqos->current_loopback == DISABLE_LOOPBACK && + config > DISABLE_LOOPBACK) { + /*Backup old speed & duplex*/ + ethqos->backup_speed = priv->speed; + ethqos->backup_duplex = priv->dev->phydev->duplex; + } + /*Backup BMCR before Enabling Phy LoopbackLoopback */ + if (ethqos->current_loopback == DISABLE_LOOPBACK && + config == ENABLE_PHY_LOOPBACK) + ethqos->bmcr_backup = ethqos_mdio_read(priv, + priv->plat->phy_addr, + MII_BMCR); + + if (config == DISABLE_LOOPBACK) + setup_config_registers(ethqos, ethqos->backup_speed, + ethqos->backup_duplex, 0); + else + setup_config_registers(ethqos, speed, DUPLEX_FULL, config); + + switch (config) { + case DISABLE_LOOPBACK: + ETHQOSINFO("Request to Disable Loopback\n"); + if (ethqos->current_loopback == ENABLE_IO_MACRO_LOOPBACK) + ethqos_rgmii_io_macro_loopback(ethqos, 0); + else if (ethqos->current_loopback == ENABLE_MAC_LOOPBACK) + ethqos_mac_loopback(ethqos, 0); + else if (ethqos->current_loopback == ENABLE_PHY_LOOPBACK) + phy_digital_loopback_config(ethqos, + ethqos->backup_speed, 0); + break; + case ENABLE_IO_MACRO_LOOPBACK: + ETHQOSINFO("Request to Enable IO MACRO LOOPBACK\n"); + ethqos_rgmii_io_macro_loopback(ethqos, 1); + break; + case ENABLE_MAC_LOOPBACK: + ETHQOSINFO("Request to Enable MAC LOOPBACK\n"); + ethqos_mac_loopback(ethqos, 1); + break; + case ENABLE_PHY_LOOPBACK: + ETHQOSINFO("Request to Enable PHY LOOPBACK\n"); + ethqos->loopback_speed = speed; + phy_digital_loopback_config(ethqos, speed, 1); + break; + default: + ETHQOSINFO("Invalid Loopback=%d\n", config); + break; + } + + ethqos->current_loopback = config; + kfree(in_buf); + return count; +} + +static ssize_t read_loopback_config(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + unsigned int len = 0, buf_len = 2000; + struct qcom_ethqos *ethqos = file->private_data; + char *buf; + ssize_t ret_cnt; + + if (!ethqos) { + ETHQOSERR("NULL Pointer\n"); + return -EINVAL; + } + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (ethqos->current_loopback == DISABLE_LOOPBACK) + len += scnprintf(buf + len, buf_len - len, + "Loopback is Disabled\n"); + else if (ethqos->current_loopback == ENABLE_IO_MACRO_LOOPBACK) + len += scnprintf(buf + len, buf_len - len, + "Current Loopback is IO MACRO LOOPBACK\n"); + else if (ethqos->current_loopback == ENABLE_MAC_LOOPBACK) + len += scnprintf(buf + len, buf_len - len, + "Current Loopback is MAC LOOPBACK\n"); + else if (ethqos->current_loopback == ENABLE_PHY_LOOPBACK) + len += scnprintf(buf + len, buf_len - len, + "Current Loopback is PHY LOOPBACK\n"); + else + len += scnprintf(buf + len, buf_len - len, + "Invalid LOOPBACK Config\n"); + if (len > buf_len) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret_cnt; +} + static const struct file_operations fops_phy_reg_dump = { .read = read_phy_reg_dump, .open = simple_open, @@ -1249,6 +1780,22 @@ static ssize_t write_ipc_stmmac_log_ctxt_low(struct file *file, return count; } +static const struct file_operations fops_phy_off = { + .read = read_phy_off, + .write = phy_off_config, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_loopback_config = { + .read = read_loopback_config, + .write = loopback_handling_config, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static const struct file_operations fops_ipc_stmmac_log_low = { .write = write_ipc_stmmac_log_ctxt_low, .open = simple_open, @@ -1261,6 +1808,8 @@ static int ethqos_create_debugfs(struct qcom_ethqos *ethqos) static struct dentry *phy_reg_dump; static struct dentry *rgmii_reg_dump; static struct dentry *ipc_stmmac_log_low; + static struct dentry *phy_off; + static struct dentry *loopback_enable_mode; if (!ethqos) { ETHQOSERR("Null Param %s\n", __func__); @@ -1294,11 +1843,26 @@ static int ethqos_create_debugfs(struct qcom_ethqos *ethqos) ethqos->debugfs_dir, ethqos, &fops_ipc_stmmac_log_low); if (!ipc_stmmac_log_low || IS_ERR(ipc_stmmac_log_low)) { - ETHQOSERR("Cannot create debugfs ipc_stmmac_log_low %d\n", - (int)ipc_stmmac_log_low); + ETHQOSERR("Cannot create debugfs ipc_stmmac_log_low %x\n", + ipc_stmmac_log_low); + goto fail; + } + phy_off = debugfs_create_file("phy_off", 0400, + ethqos->debugfs_dir, ethqos, + &fops_phy_off); + if (!phy_off || IS_ERR(phy_off)) { + ETHQOSERR("Can't create phy_off %x\n", phy_off); goto fail; } + loopback_enable_mode = debugfs_create_file("loopback_enable_mode", 0400, + ethqos->debugfs_dir, ethqos, + &fops_loopback_config); + if (!loopback_enable_mode || IS_ERR(loopback_enable_mode)) { + ETHQOSERR("Can't create loopback_enable_mode %d\n", + (int)loopback_enable_mode); + goto fail; + } return 0; fail: @@ -1560,8 +2124,13 @@ inline bool qcom_ethqos_is_phy_link_up(struct qcom_ethqos *ethqos) */ struct stmmac_priv *priv = qcom_ethqos_get_priv(ethqos); - return ((priv->oldlink != -1) && - (priv->dev->phydev && priv->dev->phydev->link)); + if (priv->plat->mac2mac_en) { + return true; + } else { + return ((priv->oldlink != -1) && + (priv->dev->phydev && + priv->dev->phydev->link)); + } } static void qcom_ethqos_phy_resume_clks(struct qcom_ethqos *ethqos) @@ -1732,8 +2301,9 @@ static void ethqos_is_ipv6_NW_stack_ready(struct work_struct *work) flush_delayed_work(ðqos->ipv6_addr_assign_wq); } -static int ethqos_set_early_eth_param(struct stmmac_priv *priv, - struct qcom_ethqos *ethqos) +static void ethqos_set_early_eth_param( + struct stmmac_priv *priv, + struct qcom_ethqos *ethqos) { int ret = 0; @@ -1760,17 +2330,21 @@ static int ethqos_set_early_eth_param(struct stmmac_priv *priv, schedule_delayed_work(ðqos->ipv6_addr_assign_wq, msecs_to_jiffies(1000)); } + return; +} - if (pparams.is_valid_mac_addr) { - ether_addr_copy(dev_addr, pparams.mac_addr); - memcpy(priv->dev->dev_addr, dev_addr, ETH_ALEN); - } - return ret; +bool qcom_ethqos_ipa_enabled(void) +{ +#ifdef CONFIG_ETH_IPA_OFFLOAD + return pethqos->ipa_enabled; +#endif + return false; } static int qcom_ethqos_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device_node *io_macro_node = NULL; struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; struct qcom_ethqos *ethqos; @@ -1870,6 +2444,14 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); plat_dat->early_eth = ethqos->early_eth_enabled; + /* Get rgmii interface speed for mac2c from device tree */ + if (of_property_read_u32(np, "mac2mac-rgmii-speed", + &plat_dat->mac2mac_rgmii_speed)) + plat_dat->mac2mac_rgmii_speed = -1; + else + ETHQOSINFO("mac2mac rgmii speed = %d\n", + plat_dat->mac2mac_rgmii_speed); + if (of_property_read_bool(pdev->dev.of_node, "qcom,arm-smmu")) { stmmac_emb_smmu_ctx.pdev_master = pdev; ret = of_platform_populate(pdev->dev.of_node, @@ -1901,6 +2483,39 @@ static int qcom_ethqos_probe(struct platform_device *pdev) } ETHQOSDBG(": emac_core_version = %d\n", ethqos->emac_ver); + if (of_property_read_bool(pdev->dev.of_node, + "emac-phy-off-suspend")) { + /* Read emac core version value from dtsi */ + ret = of_property_read_u32(pdev->dev.of_node, + "emac-phy-off-suspend", + ðqos->current_phy_mode); + if (ret) { + ETHQOSDBG(":resource emac-phy-off-suspend! "); + ETHQOSDBG("not in dtsi\n"); + ethqos->current_phy_mode = 0; + } + } + ETHQOSINFO("emac-phy-off-suspend = %d\n", + ethqos->current_phy_mode); + + io_macro_node = of_find_node_by_name(pdev->dev.of_node, + "io-macro-info"); + + if (ethqos->emac_ver == EMAC_HW_v2_3_2 || + ethqos->emac_ver == EMAC_HW_v2_1_2) { + ethqos->io_macro.rx_prog_swap = 1; + } else if (!io_macro_node) { + ethqos->io_macro.rx_prog_swap = 0; + } else { + if (of_property_read_bool(io_macro_node, "rx-prog-swap")) + ethqos->io_macro.rx_prog_swap = 1; + } + + if (io_macro_node) { + if (of_property_read_bool(io_macro_node, "rx-dll-bypass")) + ethqos->io_macro.rx_dll_bypass = 1; + } + ethqos->ioaddr = (&stmmac_res)->addr; ethqos_update_rgmii_tx_drv_strength(ethqos); @@ -1908,10 +2523,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) goto err_clk; - if (!ethqos_phy_intr_config(ethqos)) - ethqos_phy_intr_enable(ethqos); - else - ETHQOSERR("Phy interrupt configuration failed"); rgmii_dump(ethqos); if (ethqos->emac_ver == EMAC_HW_v2_3_2) { @@ -1941,6 +2552,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ndev = dev_get_drvdata(ðqos->pdev->dev); priv = netdev_priv(ndev); + if (pparams.is_valid_mac_addr) { + ether_addr_copy(dev_addr, pparams.mac_addr); + memcpy(priv->dev->dev_addr, dev_addr, ETH_ALEN); + } + if (ethqos->early_eth_enabled) { /* Initialize work*/ INIT_WORK(ðqos->early_eth, @@ -2002,6 +2618,8 @@ static int qcom_ethqos_suspend(struct device *dev) struct net_device *ndev = NULL; int ret; int allow_suspend = 0; + struct stmmac_priv *priv; + struct plat_stmmacenet_data *plat; ETHQOSDBG("Suspend Enter\n"); if (of_device_is_compatible(dev->of_node, "qcom,emac-smmu-embedded")) { @@ -2014,6 +2632,8 @@ static int qcom_ethqos_suspend(struct device *dev) return -ENODEV; ndev = dev_get_drvdata(dev); + priv = netdev_priv(ndev); + plat = priv->plat; ethqos_ipa_offload_event_handler(&allow_suspend, EV_DPM_SUSPEND); if (!allow_suspend) { @@ -2023,9 +2643,25 @@ static int qcom_ethqos_suspend(struct device *dev) } if (!ndev || !netif_running(ndev)) return -EINVAL; - + if (ethqos->current_phy_mode == DISABLE_PHY_AT_SUSPEND_ONLY || + ethqos->current_phy_mode == DISABLE_PHY_SUSPEND_ENABLE_RESUME) { + /*Backup phy related data*/ + if (priv->phydev->autoneg == AUTONEG_DISABLE) { + ethqos->backup_autoneg = priv->phydev->autoneg; + ethqos->backup_bmcr = ethqos_mdio_read(priv, + plat->phy_addr, + MII_BMCR); + } else { + ethqos->backup_autoneg = AUTONEG_ENABLE; + } + } ret = stmmac_suspend(dev); qcom_ethqos_phy_suspend_clks(ethqos); + if (ethqos->current_phy_mode == DISABLE_PHY_AT_SUSPEND_ONLY || + ethqos->current_phy_mode == DISABLE_PHY_SUSPEND_ENABLE_RESUME) { + ETHQOSINFO("disable phy at suspend\n"); + ethqos_phy_power_off(ethqos); + } ETHQOSDBG(" ret = %d\n", ret); return ret; @@ -2036,6 +2672,7 @@ static int qcom_ethqos_resume(struct device *dev) struct net_device *ndev = NULL; struct qcom_ethqos *ethqos; int ret; + struct stmmac_priv *priv; ETHQOSDBG("Resume Enter\n"); if (of_device_is_compatible(dev->of_node, "qcom,emac-smmu-embedded")) @@ -2047,6 +2684,7 @@ static int qcom_ethqos_resume(struct device *dev) return -ENODEV; ndev = dev_get_drvdata(dev); + priv = netdev_priv(ndev); if (!ndev || !netif_running(ndev)) { ETHQOSERR(" Resume not possible\n"); @@ -2059,10 +2697,40 @@ static int qcom_ethqos_resume(struct device *dev) return 0; } + if (ethqos->current_phy_mode == DISABLE_PHY_SUSPEND_ENABLE_RESUME) { + ETHQOSINFO("enable phy at resume\n"); + ethqos_phy_power_on(ethqos); + } qcom_ethqos_phy_resume_clks(ethqos); - ret = stmmac_resume(dev); + if (ethqos->current_phy_mode == DISABLE_PHY_SUSPEND_ENABLE_RESUME) { + ETHQOSINFO("reset phy after clock\n"); + ethqos_reset_phy_enable_interrupt(ethqos); + if (ethqos->backup_autoneg == AUTONEG_DISABLE) { + priv->phydev->autoneg = ethqos->backup_autoneg; + if (priv->phydev) + phy_write(priv->phydev, MII_BMCR, ethqos->backup_bmcr); + } else { + ETHQOSINFO("Phy dev is NULL\n"); + } + } + if (ethqos->current_phy_mode == DISABLE_PHY_AT_SUSPEND_ONLY) { + /* Temp Enable LOOPBACK_EN. + * TX clock needed for reset As Phy is off + */ + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + RGMII_CONFIG_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG); + ETHQOSINFO("Loopback EN Enabled\n"); + } + ret = stmmac_resume(dev); + if (ethqos->current_phy_mode == DISABLE_PHY_AT_SUSPEND_ONLY) { + //Disable LOOPBACK_EN + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + 0, RGMII_IO_MACRO_CONFIG); + ETHQOSINFO("Loopback EN Disabled\n"); + } ethqos_ipa_offload_event_handler(NULL, EV_DPM_RESUME); ETHQOSDBG("<--Resume Exit\n"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h index 0df87f533ab85a2bd71910297d1b3e0d69b88f86..4c6c8f5143f3b83ca20d30fc182d472807f18321 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h @@ -222,7 +222,6 @@ do {\ #define ATH8035_PHY_ID 0x004dd072 #define QCA8337_PHY_ID 0x004dd036 #define ATH8030_PHY_ID 0x004dd076 -#define MICREL_PHY_ID PHY_ID_KSZ9031 #define DWC_ETH_QOS_MICREL_PHY_INTCS 0x1b #define DWC_ETH_QOS_MICREL_PHY_CTL 0x1f #define DWC_ETH_QOS_BASIC_STATUS 0x0001 @@ -236,6 +235,10 @@ do {\ #define VOTE_IDX_100MBPS 2 #define VOTE_IDX_1000MBPS 3 +//Mac config +#define MAC_CONFIGURATION 0x0 +#define MAC_LM BIT(12) + #define TLMM_BASE_ADDRESS (tlmm_central_base_addr) #define TLMM_RGMII_HDRV_PULL_CTL1_ADDRESS_OFFSET\ @@ -330,9 +333,29 @@ static inline u32 PPSX_MASK(u32 x) } enum IO_MACRO_PHY_MODE { - RGMII_MODE, - RMII_MODE, - MII_MODE + RGMII_MODE, + RMII_MODE, + MII_MODE +}; + +enum loopback_mode { + DISABLE_LOOPBACK = 0, + ENABLE_IO_MACRO_LOOPBACK, + ENABLE_MAC_LOOPBACK, + ENABLE_PHY_LOOPBACK +}; + +enum phy_power_mode { + DISABLE_PHY_IMMEDIATELY = 1, + ENABLE_PHY_IMMEDIATELY, + DISABLE_PHY_AT_SUSPEND_ONLY, + DISABLE_PHY_SUSPEND_ENABLE_RESUME, + DISABLE_PHY_ON_OFF, +}; + +enum current_phy_state { + PHY_IS_ON = 0, + PHY_IS_OFF, }; #define RGMII_IO_BASE_ADDRESS ethqos->rgmii_base @@ -385,6 +408,11 @@ struct ethqos_emac_driver_data { unsigned int num_por; }; +struct ethqos_io_macro { + bool rx_prog_swap; + bool rx_dll_bypass; +}; + struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; @@ -459,6 +487,22 @@ struct qcom_ethqos { bool ipa_enabled; /* Key Performance Indicators */ bool print_kpi; + unsigned int emac_phy_off_suspend; + int loopback_speed; + enum loopback_mode current_loopback; + enum phy_power_mode current_phy_mode; + enum current_phy_state phy_state; + /*Backup variable for phy loopback*/ + int backup_duplex; + int backup_speed; + u32 bmcr_backup; + /*Backup variable for suspend resume*/ + int backup_suspend_speed; + u32 backup_bmcr; + unsigned backup_autoneg:1; + + /* IO Macro parameters */ + struct ethqos_io_macro io_macro; }; struct pps_cfg { @@ -514,6 +558,9 @@ bool qcom_ethqos_is_phy_link_up(struct qcom_ethqos *ethqos); void *qcom_ethqos_get_priv(struct qcom_ethqos *ethqos); int ppsout_config(struct stmmac_priv *priv, struct pps_cfg *eth_pps_cfg); +int ethqos_phy_power_on(struct qcom_ethqos *ethqos); +void ethqos_phy_power_off(struct qcom_ethqos *ethqos); +void ethqos_reset_phy_enable_interrupt(struct qcom_ethqos *ethqos); u16 dwmac_qcom_select_queue( struct net_device *dev, @@ -575,4 +622,6 @@ int dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req); unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb); + +unsigned int dwmac_qcom_get_eth_type(unsigned char *buf); #endif diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c index 76aafe7008516f28f3af31b9c5cc700a9da62cb2..5ad0eddf9179727e1882773b2e14b8bec011cd1c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c @@ -183,6 +183,63 @@ void ethqos_disable_regulators(struct qcom_ethqos *ethqos) } } +void ethqos_reset_phy_enable_interrupt(struct qcom_ethqos *ethqos) +{ + struct stmmac_priv *priv = qcom_ethqos_get_priv(ethqos); + struct phy_device *phydev = priv->dev->phydev; + + /* reset the phy so that it's ready */ + if (priv->mii) { + ETHQOSERR("do mdio reset\n"); + stmmac_mdio_reset(priv->mii); + } + /*Enable phy interrupt*/ + if (phy_intr_en && phydev) { + ETHQOSDBG("PHY interrupt Mode enabled\n"); + phydev->irq = PHY_IGNORE_INTERRUPT; + phydev->interrupts = PHY_INTERRUPT_ENABLED; + + if (phydev->drv->config_intr && + !phydev->drv->config_intr(phydev)) { + ETHQOSERR("config_phy_intr successful after phy on\n"); + } + qcom_ethqos_request_phy_wol(priv->plat); + } else if (!phy_intr_en) { + phydev->irq = PHY_POLL; + ETHQOSDBG("PHY Polling Mode enabled\n"); + } else { + ETHQOSERR("phydev is null , intr value=%d\n", phy_intr_en); + } +} + +int ethqos_phy_power_on(struct qcom_ethqos *ethqos) +{ + int ret = 0; + + if (ethqos->reg_emac_phy) { + ret = regulator_enable(ethqos->reg_emac_phy); + if (ret) { + ETHQOSERR("Can not enable <%s>\n", + EMAC_VREG_EMAC_PHY_NAME); + return ret; + } + ethqos->phy_state = PHY_IS_ON; + } else { + ETHQOSERR("reg_emac_phy is NULL\n"); + } + return ret; +} + +void ethqos_phy_power_off(struct qcom_ethqos *ethqos) +{ + if (ethqos->reg_emac_phy) { + regulator_disable(ethqos->reg_emac_phy); + ethqos->phy_state = PHY_IS_OFF; + } else { + ETHQOSERR("reg_emac_phy is NULL\n"); + } +} + void ethqos_free_gpios(struct qcom_ethqos *ethqos) { if (gpio_is_valid(ethqos->gpio_phy_intr_redirect)) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c index fc6a346a4b7f982b75f0263c5a9038880c7a59f0..48285bb179a8c096986389df1226d8c512777b2b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c @@ -1046,6 +1046,7 @@ static void ntn_ipa_notify_cb(void *priv, enum ipa_dp_evt_type evt, int stat = NET_RX_SUCCESS; struct platform_device *pdev; struct net_device *dev; + struct stmmac_priv *pdata; if (!ethqos || !skb) { ETHQOSERR("Null Param pdata %p skb %pK\n", ethqos, skb); @@ -1065,6 +1066,7 @@ static void ntn_ipa_notify_cb(void *priv, enum ipa_dp_evt_type evt, pdev = ethqos->pdev; dev = platform_get_drvdata(pdev); + pdata = netdev_priv(dev); if (evt == IPA_RECEIVE) { /*Exception packets to network stack*/ @@ -1075,6 +1077,8 @@ static void ntn_ipa_notify_cb(void *priv, enum ipa_dp_evt_type evt, skb->protocol = htons(ETH_P_IP); iph = (struct iphdr *)skb->data; } else { + if (ethqos->current_loopback > DISABLE_LOOPBACK) + swap_ip_port(skb, ETH_P_IP); skb->protocol = eth_type_trans(skb, skb->dev); iph = (struct iphdr *)(skb_mac_header(skb) + ETH_HLEN); } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 712b5eb3507ab3c46297e932a2b846e1a8012527..4156cf007b532411d745ec33b2c50591678f5639 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -1362,7 +1362,7 @@ static int rk_gmac_probe(struct platform_device *pdev) ret = rk_gmac_clk_init(plat_dat); if (ret) - return ret; + goto err_remove_config_dt; ret = rk_gmac_powerup(plat_dat->bsp_priv); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 5b3b06a0a3bf53e1eac9572ae8d14add0c3835e7..33407df6bea693b44903734f939b0bd83e1e12f2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -274,16 +274,19 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) phymode == PHY_INTERFACE_MODE_MII || phymode == PHY_INTERFACE_MODE_GMII || phymode == PHY_INTERFACE_MODE_SGMII) { - ctrl |= SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2); regmap_read(sys_mgr_base_addr, SYSMGR_FPGAGRP_MODULE_REG, &module); module |= (SYSMGR_FPGAGRP_MODULE_EMAC << (reg_shift / 2)); regmap_write(sys_mgr_base_addr, SYSMGR_FPGAGRP_MODULE_REG, module); - } else { - ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2)); } + if (dwmac->f2h_ptp_ref_clk) + ctrl |= SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2); + else + ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << + (reg_shift / 2)); + regmap_write(sys_mgr_base_addr, reg_offset, ctrl); /* Deassert reset for the phy configuration to be sampled by diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index fc1fa0f9f338713da5c6fcfdd19062ced459a91f..57694eada9955f774e72360d4782713dff2013a8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -155,6 +155,8 @@ static int sun7i_gmac_probe(struct platform_device *pdev) plat_dat->init = sun7i_gmac_init; plat_dat->exit = sun7i_gmac_exit; plat_dat->fix_mac_speed = sun7i_fix_speed; + plat_dat->tx_fifo_size = 4096; + plat_dat->rx_fifo_size = 16384; ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 08dd6a06ac58d72727161c6526b7c2f7b02b3ab6..f76d4a7281af052d7dd140bb2aaf8d7df0e40f8b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -218,7 +218,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw, reg++; } - while (reg <= perfect_addr_number) { + while (reg < perfect_addr_number) { writel(0, ioaddr + GMAC_ADDR_HIGH(reg)); writel(0, ioaddr + GMAC_ADDR_LOW(reg)); reg++; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 58ccbf8386eafd1238b81f00b36b10e52a8e9a3e..a3a66fcbc1a232ee8790cd4d639eb0f88f65bf36 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -33,6 +33,9 @@ #include #endif #include "dwmac-qcom-ipa-offload.h" +#include +#include +#include struct stmmac_resources { void __iomem *addr; @@ -149,6 +152,7 @@ struct stmmac_priv { void __iomem *ptpaddr; u32 mss; bool boot_kpi; + int current_loopback; #ifdef CONFIG_DEBUG_FS struct dentry *dbgfs_dir; struct dentry *dbgfs_rings_status; @@ -173,9 +177,14 @@ extern struct stmmac_emb_smmu_cb_ctx stmmac_emb_smmu_ctx; #define GET_MEM_PDEV_DEV (stmmac_emb_smmu_ctx.valid ? \ &stmmac_emb_smmu_ctx.smmu_pdev->dev : priv->device) +#define MICREL_PHY_ID 0x00221620 + +#define MMC_CONFIG 0x24 + int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); int ethqos_init_pps(struct stmmac_priv *priv); +int ethqos_phy_intr_enable(struct stmmac_priv *priv); extern bool phy_intr_en; void qcom_ethqos_request_phy_wol(struct plat_stmmacenet_data *plat_dat); @@ -194,5 +203,8 @@ int stmmac_dvr_probe(struct device *device, struct stmmac_resources *res); void stmmac_disable_eee_mode(struct stmmac_priv *priv); bool stmmac_eee_init(struct stmmac_priv *priv); - +bool qcom_ethqos_ipa_enabled(void); +u16 icmp_fast_csum(u16 old_csum); +void swap_ip_port(struct sk_buff *skb, unsigned int eth_type); +unsigned int dwmac_qcom_get_eth_type(unsigned char *buf); #endif /* __STMMAC_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 6f4152fbab2f12017f7b32f8269aaf9f61031a1e..089572fafbedf4d46bf71d91c059da9b2956d01b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -286,6 +286,12 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phy = dev->phydev; + if (!phy) { + pr_err("%s: %s: PHY is not registered\n", + __func__, dev->name); + return -ENODEV; + } + if (priv->hw->pcs & STMMAC_PCS_RGMII || priv->hw->pcs & STMMAC_PCS_SGMII) { struct rgmii_adv adv; @@ -365,11 +371,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, return 0; } - if (phy == NULL) { - pr_err("%s: %s: PHY is not registered\n", - __func__, dev->name); - return -ENODEV; - } if (!netif_running(dev)) { pr_err("%s: interface is disabled: we cannot track " "link speed / duplex setting\n", dev->name); @@ -386,6 +387,13 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phy = dev->phydev; int rc; + u32 cmd_speed = cmd->base.speed; + + if (!phy) { + pr_err("%s: %s: PHY is not registered\n", + __func__, dev->name); + return -ENODEV; + } if (priv->hw->pcs & STMMAC_PCS_RGMII || priv->hw->pcs & STMMAC_PCS_SGMII) { @@ -412,11 +420,14 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, return 0; } + /* Half duplex is not supported */ - if (cmd->base.duplex != DUPLEX_FULL) + if (cmd->base.duplex != DUPLEX_FULL || + (cmd_speed == SPEED_1000 && cmd->base.autoneg == AUTONEG_DISABLE)) rc = -EINVAL; else rc = phy_ethtool_ksettings_set(phy, cmd); + return rc; } @@ -501,6 +512,12 @@ stmmac_set_pauseparam(struct net_device *netdev, struct phy_device *phy = netdev->phydev; int new_pause = FLOW_OFF; + if (!phy) { + pr_err("%s: %s: PHY is not registered\n", + __func__, netdev->name); + return -ENODEV; + } + if (priv->hw->pcs && priv->hw->mac->pcs_get_adv_lp) { struct rgmii_adv adv_lp; @@ -540,6 +557,9 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, u32 tx_queues_count = priv->plat->tx_queues_to_use; int i, j = 0; + /* enable reset on read for mmc counter */ + writel_relaxed(MMC_CONFIG, priv->mmcaddr); + /* Update the DMA HW counters for dwmac10/100 */ if (priv->hw->dma->dma_diagnostic_fr) priv->hw->dma->dma_diagnostic_fr(&dev->stats, @@ -627,6 +647,12 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); + if (!priv->phydev) { + pr_err("%s: %s: PHY is not registered\n", + __func__, dev->name); + return; + } + phy_ethtool_get_wol(priv->phydev, wol); mutex_lock(&priv->lock); if (device_can_wakeup(priv->device)) { @@ -643,6 +669,16 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) u32 emac_wol_support = 0; int ret; + if (!priv->phydev) { + pr_err("%s: %s: PHY is not registered\n", + __func__, dev->name); + return -ENODEV; + } + + if (ethqos->phy_state == PHY_IS_OFF) { + ETHQOSINFO("Phy is in off state Wol set not possible\n"); + return -EOPNOTSUPP; + } /* By default almost all GMAC devices support the WoL via * magic frame but we can disable it if the HW capability * register shows no support for pmt_magic_frame. */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 828c0d62c43af4743ebf541f55b3eadc25626ac3..4f7453cf2f20c4fd5cc3e013b4f85b49eae7dcf9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -295,8 +295,14 @@ static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue) */ static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv) { - if (likely(priv->plat->fix_mac_speed)) - priv->plat->fix_mac_speed(priv->plat->bsp_priv, priv->speed); + if (likely(priv->plat->fix_mac_speed)) { + if (priv->phydev->link) + priv->plat->fix_mac_speed(priv->plat->bsp_priv, + priv->speed); + else + priv->plat->fix_mac_speed(priv->plat->bsp_priv, + SPEED_10); + } } /** @@ -539,6 +545,13 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) sizeof(struct hwtstamp_config))) return -EFAULT; + if (qcom_ethqos_ipa_enabled() && + config.rx_filter == HWTSTAMP_FILTER_ALL) { + netdev_alert(priv->dev, + "No hw timestamping since ipa is enabled\n"); + return -EOPNOTSUPP; + } + netdev_dbg(priv->dev, "%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n", __func__, config.flags, config.tx_type, config.rx_filter); @@ -847,6 +860,7 @@ static void stmmac_adjust_link(struct net_device *dev) priv->oldlink = true; } } else if (priv->oldlink) { + stmmac_hw_fix_mac_speed(priv); new_state = true; priv->oldlink = false; priv->speed = SPEED_UNKNOWN; @@ -1052,6 +1066,15 @@ static int stmmac_init_phy(struct net_device *dev) if (phydev->is_pseudo_fixed_link) phydev->irq = PHY_POLL; + if (((phydev->phy_id & phydev->drv->phy_id_mask) == MICREL_PHY_ID) && + !priv->plat->phy_intr_en) { + ret = ethqos_phy_intr_enable(priv); + if (ret) + pr_alert("qcom-ethqos: Unable to enable PHY interrupt\n"); + else + priv->plat->phy_intr_en = true; + } + if (phy_intr_en) { if (phydev->drv->config_intr && !phydev->drv->config_intr(phydev)) { @@ -2720,9 +2743,10 @@ static int stmmac_open(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); int ret; - if (priv->hw->pcs != STMMAC_PCS_RGMII && - priv->hw->pcs != STMMAC_PCS_TBI && - priv->hw->pcs != STMMAC_PCS_RTBI) { + if (!priv->plat->mac2mac_en && + (priv->hw->pcs != STMMAC_PCS_RGMII && + priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI)) { ret = stmmac_init_phy(dev); if (ret) { netdev_err(priv->dev, @@ -2810,6 +2834,26 @@ static int stmmac_open(struct net_device *dev) if (priv->tx_queue[IPA_DMA_TX_CH].skip_sw) ethqos_ipa_offload_event_handler(priv, EV_DEV_OPEN); + if (priv->plat->mac2mac_en) { + u32 ctrl = readl_relaxed(priv->ioaddr + MAC_CTRL_REG); + + ctrl &= ~priv->hw->link.speed_mask; + + if (priv->plat->mac2mac_rgmii_speed == SPEED_1000) { + ctrl |= priv->hw->link.speed1000; + priv->speed = SPEED_1000; + } else if (priv->plat->mac2mac_rgmii_speed == SPEED_100) { + ctrl |= priv->hw->link.speed100; + priv->speed = SPEED_100; + } else { + ctrl |= priv->hw->link.speed10; + priv->speed = SPEED_10; + } + + stmmac_hw_fix_mac_speed(priv); + writel_relaxed(ctrl, priv->ioaddr + MAC_CTRL_REG); + } + return 0; lpiirq_error: @@ -3505,6 +3549,47 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) rx_q->dirty_rx = entry; } +static u16 csum(u16 old_csum) +{ + u16 new_checksum = 0; + + new_checksum = ~(~old_csum + (-8) + 0); + return new_checksum; +} + +void swap_ip_port(struct sk_buff *skb, unsigned int eth_type) +{ + __be32 temp_addr; + unsigned char *buf = skb->data; + struct icmphdr *icmp_hdr; + unsigned char eth_temp[ETH_ALEN] = {}; + struct ethhdr *eth = (struct ethhdr *)(buf); + struct iphdr *ip_header; + + if (eth_type == ETH_P_IP) { + ip_header = (struct iphdr *)(buf + sizeof(struct ethhdr)); + if (ip_header->protocol == IPPROTO_UDP || + ip_header->protocol == IPPROTO_ICMP) { + //swap mac address + memcpy(eth_temp, eth->h_dest, ETH_ALEN); + memcpy(eth->h_dest, eth->h_source, ETH_ALEN); + memcpy(eth->h_source, eth_temp, ETH_ALEN); + //swap ip address + temp_addr = ip_header->daddr; + ip_header->daddr = ip_header->saddr; + ip_header->saddr = temp_addr; + + icmp_hdr = (struct icmphdr *)(buf + + sizeof(struct ethhdr) + + sizeof(struct iphdr)); + if (icmp_hdr->type == ICMP_ECHO) { + icmp_hdr->type = ICMP_ECHOREPLY; + icmp_hdr->checksum = csum(icmp_hdr->checksum); + } + } + } +} + /** * stmmac_rx - manage the receive process * @priv: driver private structure @@ -3519,6 +3604,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) int coe = priv->hw->rx_csum; unsigned int next_entry = rx_q->cur_rx; unsigned int count = 0; +#ifndef CONFIG_ETH_IPA_OFFLOAD + unsigned int eth_type; +#endif if (netif_msg_rx_status(priv)) { void *rx_head; @@ -3693,7 +3781,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) stmmac_get_rx_hwtstamp(priv, p, np, skb); stmmac_rx_vlan(priv->dev, skb); +#ifndef CONFIG_ETH_IPA_OFFLOAD + eth_type = dwmac_qcom_get_eth_type(skb->data); + if (priv->current_loopback > 0 && + eth_type == ETH_P_IP) + swap_ip_port(skb, eth_type); +#endif skb->protocol = eth_type_trans(skb, priv->dev); if (unlikely(!coe)) @@ -3996,6 +4090,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; case SIOCSHWTSTAMP: ret = stmmac_hwtstamp_ioctl(dev, rq); + break; case SIOCDEVPRIVATE: ret = ethqos_handle_prv_ioctl(dev, rq, cmd); break; @@ -4528,9 +4623,10 @@ int stmmac_dvr_probe(struct device *device, stmmac_check_pcs_mode(priv); - if (priv->hw->pcs != STMMAC_PCS_RGMII && - priv->hw->pcs != STMMAC_PCS_TBI && - priv->hw->pcs != STMMAC_PCS_RTBI) { + if (!priv->plat->mac2mac_en && + (priv->hw->pcs != STMMAC_PCS_RGMII && + priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI)) { /* MDIO bus Registration */ ret = stmmac_mdio_register(ndev); if (ret < 0) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 54893d12a22dcd8daba07ac355a1e587e21fcbd9..dbbf2857831d34fe9a6f54c6e75d918720e87da0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -400,6 +400,9 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) /* Default to phy auto-detection */ plat->phy_addr = -1; + /* Flag for mac2mac feature support*/ + plat->mac2mac_en = of_property_read_bool(np, "mac2mac"); + /* "snps,phy-addr" is not a standard property. Mark it as deprecated * and warn of its use. Remove this when phy node support is added. */ @@ -407,8 +410,10 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); /* To Configure PHY by using all device-tree supported properties */ - if (stmmac_dt_phy(plat, np, &pdev->dev)) - return ERR_PTR(-ENODEV); + if (!plat->mac2mac_en) { + if (stmmac_dt_phy(plat, np, &pdev->dev)) + return ERR_PTR(-ENODEV); + } of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size); diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 3840f21dd635aa805195625b0e6d146e2700634a..92e4e5d53053ffaf46dfe92493f1e4cf969c7c7a 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -771,11 +771,13 @@ static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize) { int i; - gtp->addr_hash = kmalloc(sizeof(struct hlist_head) * hsize, GFP_KERNEL); + gtp->addr_hash = kmalloc(sizeof(struct hlist_head) * hsize, + GFP_KERNEL | __GFP_NOWARN); if (gtp->addr_hash == NULL) return -ENOMEM; - gtp->tid_hash = kmalloc(sizeof(struct hlist_head) * hsize, GFP_KERNEL); + gtp->tid_hash = kmalloc(sizeof(struct hlist_head) * hsize, + GFP_KERNEL | __GFP_NOWARN); if (gtp->tid_hash == NULL) goto err1; diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 71ff6bd4be9f2c440b5106d98e0aec0568476a4e..baf8aab59f82a8fd9cbe28d00cbb8f8ab208f149 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -256,6 +256,7 @@ void ipvlan_process_multicast(struct work_struct *work) } if (dev) dev_put(dev); + cond_resched(); } } @@ -448,19 +449,21 @@ static int ipvlan_process_outbound(struct sk_buff *skb) struct ethhdr *ethh = eth_hdr(skb); int ret = NET_XMIT_DROP; - /* In this mode we dont care about multicast and broadcast traffic */ - if (is_multicast_ether_addr(ethh->h_dest)) { - pr_warn_ratelimited("Dropped {multi|broad}cast of type= [%x]\n", - ntohs(skb->protocol)); - kfree_skb(skb); - goto out; - } - /* The ipvlan is a pseudo-L2 device, so the packets that we receive * will have L2; which need to discarded and processed further * in the net-ns of the main-device. */ if (skb_mac_header_was_set(skb)) { + /* In this mode we dont care about + * multicast and broadcast traffic */ + if (is_multicast_ether_addr(ethh->h_dest)) { + pr_debug_ratelimited( + "Dropped {multi|broad}cast of type=[%x]\n", + ntohs(skb->protocol)); + kfree_skb(skb); + goto out; + } + skb_pull(skb, sizeof(*ethh)); skb->mac_header = (typeof(skb->mac_header))~0U; skb_reset_network_header(skb); diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 09f6795cce534a6056a6b51864d83e487daf6912..cd32d6623f6a32acf554ff77b797c5ca280305a7 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -236,7 +236,6 @@ static void ipvlan_uninit(struct net_device *dev) static int ipvlan_open(struct net_device *dev) { struct ipvl_dev *ipvlan = netdev_priv(dev); - struct net_device *phy_dev = ipvlan->phy_dev; struct ipvl_addr *addr; if (ipvlan->port->mode == IPVLAN_MODE_L3 || @@ -248,7 +247,7 @@ static int ipvlan_open(struct net_device *dev) list_for_each_entry(addr, &ipvlan->addrs, anode) ipvlan_ht_addr_add(ipvlan, addr); - return dev_uc_add(phy_dev, phy_dev->dev_addr); + return 0; } static int ipvlan_stop(struct net_device *dev) @@ -260,8 +259,6 @@ static int ipvlan_stop(struct net_device *dev) dev_uc_unsync(phy_dev, dev); dev_mc_unsync(phy_dev, dev); - dev_uc_del(phy_dev, phy_dev->dev_addr); - list_for_each_entry(addr, &ipvlan->addrs, anode) ipvlan_ht_addr_del(addr); diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 9a14a483ebda4b620c6c510def7e4142f9bdbbc5..9c9b73f22c0707647ba7a4ce7f8dc96120536a34 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -3169,6 +3170,11 @@ static void macsec_dev_set_rx_mode(struct net_device *dev) dev_uc_sync(real_dev, dev); } +static sci_t dev_to_sci(struct net_device *dev, __be16 port) +{ + return make_sci(dev->dev_addr, port); +} + static int macsec_set_mac_address(struct net_device *dev, void *p) { struct macsec_dev *macsec = macsec_priv(dev); @@ -3284,6 +3290,7 @@ static const struct device_type macsec_type = { static const struct nla_policy macsec_rtnl_policy[IFLA_MACSEC_MAX + 1] = { [IFLA_MACSEC_SCI] = { .type = NLA_U64 }, + [IFLA_MACSEC_PORT] = { .type = NLA_U16 }, [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 }, [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 }, [IFLA_MACSEC_WINDOW] = { .type = NLA_U32 }, @@ -3531,19 +3538,22 @@ static int macsec_newlink(struct net *net, struct net_device *dev, struct netlink_ext_ack *extack) { struct macsec_dev *macsec = macsec_priv(dev); - struct net_device *real_dev; struct macsec_context ctx; const struct macsec_ops *ops; - int err; - sci_t sci; u8 icv_len = DEFAULT_ICV_LEN; rx_handler_func_t *rx_handler; + u8 icv_len = DEFAULT_ICV_LEN; + struct net_device *real_dev; + int err, mtu; + sci_t sci; if (!tb[IFLA_LINK]) return -EINVAL; real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; + if (real_dev->type != ARPHRD_ETHER) + return -EINVAL; dev->priv_flags |= IFF_MACSEC; @@ -3551,7 +3561,11 @@ static int macsec_newlink(struct net *net, struct net_device *dev, if (data && data[IFLA_MACSEC_ICV_LEN]) icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]); - dev->mtu = real_dev->mtu - icv_len - macsec_extra_len(true); + mtu = real_dev->mtu - icv_len - macsec_extra_len(true); + if (mtu < 0) + dev->mtu = 0; + else + dev->mtu = mtu; rx_handler = rtnl_dereference(real_dev->rx_handler); if (rx_handler && rx_handler != macsec_handle_frame) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index ab539136d5bff8770b38f2547d92f0e4a9226480..3072fc902eca57c79a8130119ddd77d7e40ee42e 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -338,6 +338,8 @@ static void macvlan_process_broadcast(struct work_struct *w) if (src) dev_put(src->dev); kfree_skb(skb); + + cond_resched(); } } @@ -1671,7 +1673,7 @@ static int macvlan_device_event(struct notifier_block *unused, struct macvlan_dev, list); - if (macvlan_sync_address(vlan->dev, dev->dev_addr)) + if (vlan && macvlan_sync_address(vlan->dev, dev->dev_addr)) return NOTIFY_BAD; break; diff --git a/drivers/net/phy/mdio-bcm-iproc.c b/drivers/net/phy/mdio-bcm-iproc.c index 46fe1ae919a30a9a9b7644b5862f4a5bfa0b56ef..51ce3ea17fb37f0533bb1dae3ad76e5797d24976 100644 --- a/drivers/net/phy/mdio-bcm-iproc.c +++ b/drivers/net/phy/mdio-bcm-iproc.c @@ -188,6 +188,23 @@ static int iproc_mdio_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +int iproc_mdio_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iproc_mdio_priv *priv = platform_get_drvdata(pdev); + + /* restore the mii clock configuration */ + iproc_mdio_config_clk(priv->base); + + return 0; +} + +static const struct dev_pm_ops iproc_mdio_pm_ops = { + .resume = iproc_mdio_resume +}; +#endif /* CONFIG_PM_SLEEP */ + static const struct of_device_id iproc_mdio_of_match[] = { { .compatible = "brcm,iproc-mdio", }, { /* sentinel */ }, @@ -198,6 +215,9 @@ static struct platform_driver iproc_mdio_driver = { .driver = { .name = "iproc-mdio", .of_match_table = iproc_mdio_of_match, +#ifdef CONFIG_PM_SLEEP + .pm = &iproc_mdio_pm_ops, +#endif }, .probe = iproc_mdio_probe, .remove = iproc_mdio_remove, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index a44b004086b78a4e1d331b43484161486359061e..cdee06bcd85e3d1272a51b1818cc10c220fc3c37 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -31,6 +31,7 @@ #include #include #include +#include /* Operation Mode Strap Override */ #define MII_KSZPHY_OMSO 0x16 @@ -777,6 +778,12 @@ static int kszphy_resume(struct phy_device *phydev) genphy_resume(phydev); + /* After switching from power-down to normal mode, an internal global + * reset is automatically generated. Wait a minimum of 1 ms before + * read/write access to the PHY registers. + */ + usleep_range(1000, 2000); + ret = kszphy_config_reset(phydev); if (ret) return ret; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0a85141d8e7691088641a26358a815db1ec7f5f3..295721efefbed0000f5b353a2b2cc6e16785c884 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -76,7 +76,7 @@ static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); #ifdef CONFIG_PM -static bool mdio_bus_phy_may_suspend(struct phy_device *phydev, bool suspend) +static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) { struct device_driver *drv = phydev->mdio.dev.driver; struct phy_driver *phydrv = to_phy_driver(drv); @@ -88,11 +88,10 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev, bool suspend) /* PHY not attached? May suspend if the PHY has not already been * suspended as part of a prior call to phy_disconnect() -> * phy_detach() -> phy_suspend() because the parent netdev might be the - * MDIO bus driver and clock gated at this point. Also may resume if - * PHY is not attached. + * MDIO bus driver and clock gated at this point. */ if (!netdev) - return suspend ? !phydev->suspended : phydev->suspended; + goto out; /* Don't suspend PHY if the attached netdev parent may wakeup. * The parent may point to a PCI device, as in tg3 driver. @@ -107,7 +106,8 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev, bool suspend) if (device_may_wakeup(&netdev->dev)) return false; - return true; +out: + return !phydev->suspended; } static int mdio_bus_phy_suspend(struct device *dev) @@ -122,9 +122,11 @@ static int mdio_bus_phy_suspend(struct device *dev) if (phydev->attached_dev && phydev->adjust_link) phy_stop_machine(phydev); - if (!mdio_bus_phy_may_suspend(phydev, true)) + if (!mdio_bus_phy_may_suspend(phydev)) return 0; + phydev->suspended_by_mdio_bus = true; + return phy_suspend(phydev); } @@ -133,9 +135,11 @@ static int mdio_bus_phy_resume(struct device *dev) struct phy_device *phydev = to_phy_device(dev); int ret; - if (!mdio_bus_phy_may_suspend(phydev, false)) + if (!phydev->suspended_by_mdio_bus) goto no_resume; + phydev->suspended_by_mdio_bus = false; + ret = phy_resume(phydev); if (ret < 0) return ret; diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index b408512f9dbac2c44b057f62fd5e7f802e2cddc3..f347e5ac66777fbf233000549b0b5d1414350fb7 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -878,15 +878,15 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf, skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); if (!skb) goto nomem; - ap->rpkt = skb; - } - if (skb->len == 0) { - /* Try to get the payload 4-byte aligned. - * This should match the - * PPP_ALLSTATIONS/PPP_UI/compressed tests in - * process_input_packet, but we do not have - * enough chars here to test buf[1] and buf[2]. - */ + ap->rpkt = skb; + } + if (skb->len == 0) { + /* Try to get the payload 4-byte aligned. + * This should match the + * PPP_ALLSTATIONS/PPP_UI/compressed tests in + * process_input_packet, but we do not have + * enough chars here to test buf[1] and buf[2]. + */ if (buf[0] != PPP_ALLSTATIONS) skb_reserve(skb, 2 + (buf[0] & 1)); } diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index ea90db3c77058b6a799245bd5a3ff9f672b5da5e..01334aeac577a6a6f36977a71bd9666f9afea1d0 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -232,7 +232,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, register struct cstate *cs = lcs->next; register unsigned long deltaS, deltaA; register short changes = 0; - int hlen; + int nlen, hlen; unsigned char new_seq[16]; register unsigned char *cp = new_seq; struct iphdr *ip; @@ -248,6 +248,8 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, return isize; ip = (struct iphdr *) icp; + if (ip->version != 4 || ip->ihl < 5) + return isize; /* Bail if this packet isn't TCP, or is an IP fragment */ if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { @@ -258,10 +260,14 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, comp->sls_o_tcp++; return isize; } - /* Extract TCP header */ + nlen = ip->ihl * 4; + if (isize < nlen + sizeof(*th)) + return isize; - th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); - hlen = ip->ihl*4 + th->doff*4; + th = (struct tcphdr *)(icp + nlen); + if (th->doff < sizeof(struct tcphdr) / 4) + return isize; + hlen = nlen + th->doff * 4; /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or * some other control bit is set). Also uncompressible if diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index b07f367abd9157ee2416af634d8853cb6af9f7d7..d7882b548b79a8e7286d1f6a246fa536f923b8c0 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -867,7 +867,10 @@ static int slip_open(struct tty_struct *tty) tty->disc_data = NULL; clear_bit(SLF_INUSE, &sl->flags); sl_free_netdev(sl->dev); + /* do not call free_netdev before rtnl_unlock */ + rtnl_unlock(); free_netdev(sl->dev); + return err; err_exit: rtnl_unlock(); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index f1aabf8a16c2f3e9daf8a8ea7323d6175d65ffd6..396a8c6cb9992c48ac9a2c4d23758c21563bba81 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -480,6 +480,9 @@ static const struct team_mode *team_mode_get(const char *kind) struct team_mode_item *mitem; const struct team_mode *mode = NULL; + if (!try_module_get(THIS_MODULE)) + return NULL; + spin_lock(&mode_list_lock); mitem = __find_mode(kind); if (!mitem) { @@ -495,6 +498,7 @@ static const struct team_mode *team_mode_get(const char *kind) } spin_unlock(&mode_list_lock); + module_put(THIS_MODULE); return mode; } @@ -2207,6 +2211,8 @@ team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = { [TEAM_ATTR_OPTION_CHANGED] = { .type = NLA_FLAG }, [TEAM_ATTR_OPTION_TYPE] = { .type = NLA_U8 }, [TEAM_ATTR_OPTION_DATA] = { .type = NLA_BINARY }, + [TEAM_ATTR_OPTION_PORT_IFINDEX] = { .type = NLA_U32 }, + [TEAM_ATTR_OPTION_ARRAY_INDEX] = { .type = NLA_U32 }, }; static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 78698b764d9eee18351f27751d5834f7026204f4..e6a3b3a34ad6d2b024ad790287e4a0ba09452393 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1134,6 +1134,13 @@ static void tun_net_init(struct net_device *dev) dev->max_mtu = MAX_MTU - dev->hard_header_len; } +static bool tun_sock_writeable(struct tun_struct *tun, struct tun_file *tfile) +{ + struct sock *sk = tfile->socket.sk; + + return (tun->dev->flags & IFF_UP) && sock_writeable(sk); +} + /* Character device part */ /* Poll */ @@ -1156,10 +1163,14 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait) if (!skb_array_empty(&tfile->tx_array)) mask |= POLLIN | POLLRDNORM; - if (tun->dev->flags & IFF_UP && - (sock_writeable(sk) || - (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) && - sock_writeable(sk)))) + /* Make sure SOCKWQ_ASYNC_NOSPACE is set if not writable to + * guarantee EPOLLOUT to be raised by either here or + * tun_sock_write_space(). Then process could get notification + * after it writes to a down device and meets -EIO. + */ + if (tun_sock_writeable(tun, tfile) || + (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) && + tun_sock_writeable(tun, tfile))) mask |= POLLOUT | POLLWRNORM; if (tun->dev->reg_state != NETREG_REGISTERED) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index db70d4c5778a621293701873977491137b350140..e028e03765a5619835ecef72eb885f79a2cd6f72 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -63,7 +63,6 @@ enum qmi_wwan_flags { enum qmi_wwan_quirks { QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ - QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1, /* check num. endpoints */ }; struct qmimux_hdr { @@ -275,6 +274,9 @@ static void qmi_wwan_netdev_setup(struct net_device *net) netdev_dbg(net, "mode: raw IP\n"); } else if (!net->header_ops) { /* don't bother if already set */ ether_setup(net); + /* Restoring min/max mtu values set originally by usbnet */ + net->min_mtu = 0; + net->max_mtu = ETH_MAX_MTU; clear_bit(EVENT_NO_IP_ALIGN, &dev->flags); netdev_dbg(net, "mode: Ethernet\n"); } @@ -853,16 +855,6 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = { .data = QMI_WWAN_QUIRK_DTR, }; -static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = { - .description = "WWAN/QMI device", - .flags = FLAG_WWAN | FLAG_SEND_ZLP, - .bind = qmi_wwan_bind, - .unbind = qmi_wwan_unbind, - .manage_power = qmi_wwan_manage_power, - .rx_fixup = qmi_wwan_rx_fixup, - .data = QMI_WWAN_QUIRK_DTR | QMI_WWAN_QUIRK_QUECTEL_DYNCFG, -}; - #define HUAWEI_VENDOR_ID 0x12D1 /* map QMI/wwan function by a fixed interface number */ @@ -883,14 +875,18 @@ static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = { #define QMI_GOBI_DEVICE(vend, prod) \ QMI_FIXED_INTF(vend, prod, 0) -/* Quectel does not use fixed interface numbers on at least some of their - * devices. We need to check the number of endpoints to ensure that we bind to - * the correct interface. +/* Many devices have QMI and DIAG functions which are distinguishable + * from other vendor specific functions by class, subclass and + * protocol all being 0xff. The DIAG function has exactly 2 endpoints + * and is silently rejected when probed. + * + * This makes it possible to match dynamically numbered QMI functions + * as seen on e.g. many Quectel modems. */ -#define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \ +#define QMI_MATCH_FF_FF_FF(vend, prod) \ USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \ USB_SUBCLASS_VENDOR_SPEC, 0xff), \ - .driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg + .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr static const struct usb_device_id products[] = { /* 1. CDC ECM like devices match on the control interface */ @@ -996,10 +992,10 @@ static const struct usb_device_id products[] = { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), .driver_info = (unsigned long)&qmi_wwan_info, }, - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ - {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ @@ -1143,6 +1139,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1435, 0xd181, 4)}, /* Wistron NeWeb D18Q1 */ {QMI_FIXED_INTF(0x1435, 0xd181, 5)}, /* Wistron NeWeb D18Q1 */ {QMI_QUIRK_SET_DTR(0x1508, 0x1001, 4)}, /* Fibocom NL668 series */ + {QMI_FIXED_INTF(0x1690, 0x7588, 4)}, /* ASKEY WWHC050 */ {QMI_FIXED_INTF(0x16d8, 0x6003, 0)}, /* CMOTech 6003 */ {QMI_FIXED_INTF(0x16d8, 0x6007, 0)}, /* CMOTech CHE-628S */ {QMI_FIXED_INTF(0x16d8, 0x6008, 0)}, /* CMOTech CMU-301 */ @@ -1287,6 +1284,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81d7, 0)}, /* Dell Wireless 5821e */ + {QMI_FIXED_INTF(0x413c, 0x81d7, 1)}, /* Dell Wireless 5821e preproduction config */ {QMI_FIXED_INTF(0x413c, 0x81e0, 0)}, /* Dell Wireless 5821e with eSIM support*/ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ @@ -1378,7 +1376,6 @@ static int qmi_wwan_probe(struct usb_interface *intf, { struct usb_device_id *id = (struct usb_device_id *)prod; struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; - const struct driver_info *info; /* Workaround to enable dynamic IDs. This disables usbnet * blacklisting functionality. Which, if required, can be @@ -1414,12 +1411,8 @@ static int qmi_wwan_probe(struct usb_interface *intf, * different. Ignore the current interface if the number of endpoints * equals the number for the diag interface (two). */ - info = (void *)id->driver_info; - - if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) { - if (desc->bNumEndpoints == 2) - return -ENODEV; - } + if (desc->bNumEndpoints == 2) + return -ENODEV; return usbnet_probe(intf, id); } diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index a7f9c1886bd4c42d946aa4b755606af5729e9598..cadf5ded45a9b387219c8f51b77f3eff38ac17b0 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2696,6 +2696,8 @@ static u16 r8153_phy_status(struct r8152 *tp, u16 desired) } msleep(20); + if (test_bit(RTL8152_UNPLUG, &tp->flags)) + break; } return data; @@ -4055,7 +4057,10 @@ static void r8153_init(struct r8152 *tp) if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & AUTOLOAD_DONE) break; + msleep(20); + if (test_bit(RTL8152_UNPLUG, &tp->flags)) + break; } data = r8153_phy_status(tp, 0); @@ -4170,7 +4175,10 @@ static void r8153b_init(struct r8152 *tp) if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & AUTOLOAD_DONE) break; + msleep(20); + if (test_bit(RTL8152_UNPLUG, &tp->flags)) + break; } data = r8153_phy_status(tp, 0); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 854ca8cd57a97cac0c81e0cf3e0bac44ce1d92de..df99787836cde25137222f060f4dd138089ce461 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1442,7 +1442,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; - int retval; + int retval = 0; struct timespec64 now; if (skb) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index e0cea5c05f0e27cbf3fd8f8f99a6a0c947f0d7ab..811fe0bde8a3a472e3aaca98a597b7779ca789f2 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -476,7 +476,8 @@ static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev, if (rt6_need_strict(&ipv6_hdr(skb)->daddr)) return skb; - if (qdisc_tx_is_default(vrf_dev)) + if (qdisc_tx_is_default(vrf_dev) || + IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) return vrf_ip6_out_direct(vrf_dev, sk, skb); return vrf_ip6_out_redirect(vrf_dev, skb); @@ -692,7 +693,8 @@ static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev, ipv4_is_lbcast(ip_hdr(skb)->daddr)) return skb; - if (qdisc_tx_is_default(vrf_dev)) + if (qdisc_tx_is_default(vrf_dev) || + IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) return vrf_ip_out_direct(vrf_dev, sk, skb); return vrf_ip_out_redirect(vrf_dev, skb); @@ -996,23 +998,24 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, struct sk_buff *skb) { int orig_iif = skb->skb_iif; - bool need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr); - bool is_ndisc = ipv6_ndisc_frame(skb); + bool need_strict; - /* loopback, multicast & non-ND link-local traffic; do not push through - * packet taps again. Reset pkt_type for upper layers to process skb + /* loopback traffic; do not push through packet taps again. + * Reset pkt_type for upper layers to process skb */ - if (skb->pkt_type == PACKET_LOOPBACK || (need_strict && !is_ndisc)) { + if (skb->pkt_type == PACKET_LOOPBACK) { skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; IP6CB(skb)->flags |= IP6SKB_L3SLAVE; - if (skb->pkt_type == PACKET_LOOPBACK) - skb->pkt_type = PACKET_HOST; + skb->pkt_type = PACKET_HOST; goto out; } - /* if packet is NDISC then keep the ingress interface */ - if (!is_ndisc) { + /* if packet is NDISC or addressed to multicast or link-local + * then keep the ingress interface + */ + need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr); + if (!ipv6_ndisc_frame(skb) && !need_strict) { vrf_rx_stats(vrf_dev, skb->len); skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 4d97a7b5fe3cabc074a28b20dd9a32afd686ded7..927d62c76a604c3214846e005e1203e82076061f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2454,10 +2454,19 @@ static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan, /* Setup stats when device is created */ static int vxlan_init(struct net_device *dev) { + struct vxlan_dev *vxlan = netdev_priv(dev); + int err; + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; + err = gro_cells_init(&vxlan->gro_cells, dev); + if (err) { + free_percpu(dev->tstats); + return err; + } + return 0; } @@ -2717,8 +2726,6 @@ static void vxlan_setup(struct net_device *dev) vxlan->dev = dev; - gro_cells_init(&vxlan->gro_cells, dev); - for (h = 0; h < FDB_HASH_SIZE; ++h) INIT_HLIST_HEAD(&vxlan->fdb_head[h]); } diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 571a1ff8f81f2606ab24036af373546251d7b65e..6a26cef6219350bf7c5c6fc5ec531769c6dce41d 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -240,6 +240,11 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) ret = -ENOMEM; goto free_riptr; } + if (riptr != (u16)riptr || tiptr != (u16)tiptr) { + dev_err(priv->dev, "MURAM allocation out of addressable range\n"); + ret = -ENOMEM; + goto free_tiptr; + } /* Set RIPTR, TIPTR */ iowrite16be(riptr, &priv->ucc_pram->riptr); diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 6a505c26a3e74416c0461b677871a81e2b543041..a269ed63d90f7fd069b6e055ec209c10e5b6dffa 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -261,7 +261,7 @@ struct port { struct hss_plat_info *plat; buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; struct desc *desc_tab; /* coherent */ - u32 desc_tab_phys; + dma_addr_t desc_tab_phys; unsigned int id; unsigned int clock_type, clock_rate, loopback; unsigned int initialized, carrier; @@ -861,7 +861,7 @@ static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_dropped++; return NETDEV_TX_OK; } - memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); + memcpy_swab32(mem, (u32 *)((uintptr_t)skb->data & ~3), bytes / 4); dev_kfree_skb(skb); #endif diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c index 502c346aa790bf4f79218d816420f9997b69df3e..7d396c81ec3eb31d6aa4d451cce72bac9440a4aa 100644 --- a/drivers/net/wimax/i2400m/usb-fw.c +++ b/drivers/net/wimax/i2400m/usb-fw.c @@ -354,6 +354,7 @@ ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m, usb_autopm_put_interface(i2400mu->usb_iface); d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n", i2400m, ack, ack_size, (long) result); + usb_put_urb(¬if_urb); return result; error_exceeded: diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 81e9b36c056ae4b45bcc7a94270dddbb4d7d9982..54637f36013b78d2c9dfee2bd7c25e02db3fb409 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -538,6 +539,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &wcn3990_ops, .decap_align_bytes = 1, .num_peers = TARGET_HL_10_TLV_NUM_PEERS, + .n_cipher_suites = 11, .ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT, .num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES, .target_64bit = true, @@ -2100,6 +2102,7 @@ static void ath10k_core_restart(struct work_struct *work) complete(&ar->offchan_tx_completed); complete(&ar->install_key_done); complete(&ar->vdev_setup_done); + complete(&ar->vdev_delete_done); complete(&ar->thermal.wmi_sync); complete(&ar->bss_survey_done); wake_up(&ar->htt.empty_tx_wq); @@ -3002,8 +3005,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); init_completion(&ar->thermal.wmi_sync); init_completion(&ar->bss_survey_done); + init_completion(&ar->peer_delete_done); INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 04dab735de7ff4a383c0f12c972b7cf739bca644..4136a8e8d190f7f811bec3fa68b03c52f096f760 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -374,7 +375,8 @@ struct ath10k_sta { #endif }; -#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +#define ATH10K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ) enum ath10k_beacon_state { ATH10K_BEACON_SCHEDULED = 0, @@ -913,6 +915,7 @@ struct ath10k { int last_wmi_vdev_start_status; struct completion vdev_setup_done; + struct completion vdev_delete_done; struct workqueue_struct *workqueue; /* Auxiliary workqueue */ @@ -1037,8 +1040,11 @@ struct ath10k { u32 ampdu_reference; + const u8 *wmi_key_cipher; void *ce_priv; + struct completion peer_delete_done; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e55524749f8fc7893e87dd7b107e7f33ca206cea..e9017d8894a80cefd45f154e02bcd8a58a172b06 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -231,24 +231,24 @@ static int ath10k_send_key(struct ath10k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: - arg.key_cipher = WMI_CIPHER_AES_CCM; + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_AES_CCM]; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; case WLAN_CIPHER_SUITE_TKIP: - arg.key_cipher = WMI_CIPHER_TKIP; + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_TKIP]; arg.key_txmic_len = 8; arg.key_rxmic_len = 8; break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - arg.key_cipher = WMI_CIPHER_WEP; + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_WEP]; break; case WLAN_CIPHER_SUITE_CCMP_256: - arg.key_cipher = WMI_CIPHER_AES_CCM; + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_AES_CCM]; break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - arg.key_cipher = WMI_CIPHER_AES_GCM; + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_AES_GCM]; break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: @@ -265,7 +265,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (cmd == DISABLE_KEY) { - arg.key_cipher = WMI_CIPHER_NONE; + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_NONE]; arg.key_data = NULL; } @@ -685,6 +685,26 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, *def = &conf->def; } +static void ath10k_wait_for_peer_delete_done(struct ath10k *ar, u32 vdev_id, + const u8 *addr) +{ + unsigned long time_left; + int ret; + + if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { + ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); + if (ret) { + ath10k_warn(ar, "failed wait for peer deleted"); + return; + } + + time_left = wait_for_completion_timeout(&ar->peer_delete_done, + 5 * HZ); + if (!time_left) + ath10k_warn(ar, "Timeout in receiving peer delete response\n"); + } +} + static int ath10k_peer_create(struct ath10k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -729,7 +749,7 @@ static int ath10k_peer_create(struct ath10k *ar, spin_unlock_bh(&ar->data_lock); ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n", addr, vdev_id); - ath10k_wmi_peer_delete(ar, vdev_id, addr); + ath10k_wait_for_peer_delete_done(ar, vdev_id, addr); return -ENOENT; } @@ -811,6 +831,18 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) if (ret) return ret; + if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { + unsigned long time_left; + + time_left = wait_for_completion_timeout + (&ar->peer_delete_done, 5 * HZ); + + if (!time_left) { + ath10k_warn(ar, "Timeout in receiving peer delete response\n"); + return -ETIMEDOUT; + } + } + ar->num_peers--; return 0; @@ -1003,6 +1035,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { @@ -1052,6 +1085,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ar->monitor_vdev_id, ret); reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) @@ -1393,6 +1427,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) lockdep_assert_held(&ar->conf_mutex); reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { @@ -1429,6 +1464,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); arg.vdev_id = arvif->vdev_id; arg.dtim_period = arvif->dtim_period; @@ -5244,8 +5280,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, err_peer_delete: if (arvif->vdev_type == WMI_VDEV_TYPE_AP || - arvif->vdev_type == WMI_VDEV_TYPE_IBSS) + arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); + ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id, + vif->addr); + } err_vdev_delete: ath10k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -5280,6 +5319,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; struct ath10k_peer *peer; + unsigned long time_left; int ret; int i; @@ -5310,6 +5350,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n", arvif->vdev_id, ret); + ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id, + vif->addr); kfree(arvif->u.ap.noa_data); } @@ -5321,6 +5363,15 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); + if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { + time_left = wait_for_completion_timeout(&ar->vdev_delete_done, + ATH10K_VDEV_DELETE_TIMEOUT_HZ); + if (time_left == 0) { + ath10k_warn(ar, "Timeout in receiving vdev delete response\n"); + goto out; + } + } + /* Some firmware revisions don't notify host about self-peer removal * until after associated vdev is deleted. */ @@ -5371,6 +5422,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_mac_txq_unref(ar, vif->txq); +out: mutex_unlock(&ar->conf_mutex); } @@ -7968,6 +8020,20 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = { }, }; +static const struct ieee80211_iface_limit ath10k_tlv_if_vap_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 3, + .types = BIT(NL80211_IFTYPE_AP) +#ifdef CONFIG_MAC80211_MESH + | BIT(NL80211_IFTYPE_MESH_POINT) +#endif + }, +}; + /* FIXME: This is not thouroughly tested. These combinations may over- or * underestimate hw/fw capabilities. */ @@ -7984,6 +8050,14 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { .max_interfaces = 2, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss), }, + { + .limits = ath10k_tlv_if_vap_limit, + .num_different_channels = 1, + .max_interfaces = 4, + .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, + .n_limits = ARRAY_SIZE(ath10k_tlv_if_vap_limit), + }, }; static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { @@ -8005,6 +8079,12 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { .max_interfaces = 2, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss), }, + { + .limits = ath10k_tlv_if_vap_limit, + .num_different_channels = 1, + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(ath10k_tlv_if_vap_limit), + }, }; static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6ab44add9f51127f74bb1efe58316d5377493af1..4a653915aa5f2f535da203ba0ebd7e3c2c6fb888 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -222,6 +223,13 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, return 0; } +static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar, + struct sk_buff *skb) +{ + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_DELETE_RESP_EVENTID\n"); + complete(&ar->vdev_delete_done); +} + static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, struct sk_buff *skb) { @@ -412,6 +420,24 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, + struct sk_buff *skb) +{ + struct wmi_peer_delete_resp_ev_arg *arg; + struct wmi_tlv *tlv_hdr; + + tlv_hdr = (struct wmi_tlv *)skb->data; + arg = (struct wmi_peer_delete_resp_ev_arg *)tlv_hdr->value; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "vdev id %d", arg->vdev_id); + ath10k_dbg(ar, ATH10K_DBG_WMI, "peer mac addr %pM", &arg->peer_addr); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete response\n"); + + complete(&ar->peer_delete_done); + + return 0; +} + /***********/ /* TLV ops */ /***********/ @@ -468,6 +494,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_VDEV_STOPPED_EVENTID: ath10k_wmi_event_vdev_stopped(ar, skb); break; + case WMI_TLV_VDEV_DELETE_RESP_EVENTID: + ath10k_wmi_tlv_event_vdev_delete_resp(ar, skb); + break; case WMI_TLV_PEER_STA_KICKOUT_EVENTID: ath10k_wmi_event_peer_sta_kickout(ar, skb); break; @@ -555,6 +584,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_TX_PAUSE_EVENTID: ath10k_wmi_tlv_event_tx_pause(ar, skb); break; + case WMI_TLV_PEER_DELETE_RESP_EVENTID: + ath10k_wmi_tlv_event_peer_delete_resp(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -1547,7 +1579,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->max_frag_entries = __cpu_to_le32(2); cfg->num_tdls_vdevs = __cpu_to_le32(TARGET_TLV_NUM_TDLS_VDEVS); cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20); - cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2); + cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(3); cfg->num_multicast_filter_entries = __cpu_to_le32(5); cfg->num_wow_filters = __cpu_to_le32(ar->wow.max_num_patterns); cfg->num_keep_alive_pattern = __cpu_to_le32(6); @@ -1704,6 +1736,28 @@ ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar, return skb; } +static int ath10k_wmi_tlv_op_get_vdev_subtype(struct ath10k *ar, + enum wmi_vdev_subtype subtype) +{ + switch (subtype) { + case WMI_VDEV_SUBTYPE_NONE: + return WMI_TLV_VDEV_SUBTYPE_NONE; + case WMI_VDEV_SUBTYPE_P2P_DEVICE: + return WMI_TLV_VDEV_SUBTYPE_P2P_DEV; + case WMI_VDEV_SUBTYPE_P2P_CLIENT: + return WMI_TLV_VDEV_SUBTYPE_P2P_CLI; + case WMI_VDEV_SUBTYPE_P2P_GO: + return WMI_TLV_VDEV_SUBTYPE_P2P_GO; + case WMI_VDEV_SUBTYPE_PROXY_STA: + return WMI_TLV_VDEV_SUBTYPE_PROXY_STA; + case WMI_VDEV_SUBTYPE_MESH_11S: + return WMI_TLV_VDEV_SUBTYPE_MESH_11S; + case WMI_VDEV_SUBTYPE_MESH_NON_11S: + return -ENOTSUPP; + } + return -ENOTSUPP; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id, @@ -1932,9 +1986,11 @@ ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar, size_t len; void *ptr; - if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) + if (arg->key_cipher == ar->wmi_key_cipher[WMI_CIPHER_NONE] && + arg->key_data) return ERR_PTR(-EINVAL); - if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) + if (arg->key_cipher != ar->wmi_key_cipher[WMI_CIPHER_NONE] && + !arg->key_data) return ERR_PTR(-EINVAL); len = sizeof(*tlv) + sizeof(*cmd) + @@ -2611,7 +2667,7 @@ ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control)) { - len += IEEE80211_CCMP_MIC_LEN; + skb_put(msdu, IEEE80211_CCMP_MIC_LEN); buf_len += IEEE80211_CCMP_MIC_LEN; } @@ -3826,7 +3882,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, - .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, + .get_vdev_subtype = ath10k_wmi_tlv_op_get_vdev_subtype, .gen_echo = ath10k_wmi_tlv_op_gen_echo, .gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf, .gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index eac0a5364a5789f059f4a68a86d5f977f754ae55..f9249a50e52b37e9a86c3d7235f475d7579701ad 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -309,11 +310,15 @@ enum wmi_tlv_event_id { WMI_TLV_VDEV_STOPPED_EVENTID, WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID, WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, + WMI_TLV_VDEV_TSF_REPORT_EVENTID, + WMI_TLV_VDEV_DELETE_RESP_EVENTID, WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER), WMI_TLV_PEER_INFO_EVENTID, WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID, WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID, WMI_TLV_PEER_STATE_EVENTID, + WMI_TLV_PEER_ASSOC_CONF_EVENTID, + WMI_TLV_PEER_DELETE_RESP_EVENTID, WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT), WMI_TLV_HOST_SWBA_EVENTID, WMI_TLV_TBTTOFFSET_UPDATE_EVENTID, @@ -1554,6 +1559,10 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) WMI_SERVICE_SAP_AUTH_OFFLOAD, len); SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI, WMI_SERVICE_MGMT_TX_WMI, len); + SVCMAP(WMI_TLV_SERVICE_MESH_11S, + WMI_SERVICE_MESH_11S, len); + SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS, + WMI_SERVICE_SYNC_DELETE_CMDS, len); } static inline void @@ -1721,6 +1730,16 @@ struct wmi_tlv_start_scan_cmd { struct wmi_mac_addr mac_mask; } __packed; +enum wmi_tlv_vdev_subtype { + WMI_TLV_VDEV_SUBTYPE_NONE = 0, + WMI_TLV_VDEV_SUBTYPE_P2P_DEV = 1, + WMI_TLV_VDEV_SUBTYPE_P2P_CLI = 2, + WMI_TLV_VDEV_SUBTYPE_P2P_GO = 3, + WMI_TLV_VDEV_SUBTYPE_PROXY_STA = 4, + WMI_TLV_VDEV_SUBTYPE_MESH = 5, + WMI_TLV_VDEV_SUBTYPE_MESH_11S = 6, +}; + struct wmi_tlv_vdev_start_cmd { __le32 vdev_id; __le32 requestor_id; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index be3bade3d101ee64d52f7b8591f27039fea979f4..1d0b8f26afa12589604af374f138d9fbab7fbbc0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1588,6 +1588,30 @@ static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { .enable_btcoex = WMI_10_4_PDEV_PARAM_ENABLE_BTCOEX, }; +static const u8 wmi_key_cipher_suites[] = { + [WMI_CIPHER_NONE] = WMI_CIPHER_NONE, + [WMI_CIPHER_WEP] = WMI_CIPHER_WEP, + [WMI_CIPHER_TKIP] = WMI_CIPHER_TKIP, + [WMI_CIPHER_AES_OCB] = WMI_CIPHER_AES_OCB, + [WMI_CIPHER_AES_CCM] = WMI_CIPHER_AES_CCM, + [WMI_CIPHER_WAPI] = WMI_CIPHER_WAPI, + [WMI_CIPHER_CKIP] = WMI_CIPHER_CKIP, + [WMI_CIPHER_AES_CMAC] = WMI_CIPHER_AES_CMAC, + [WMI_CIPHER_AES_GCM] = WMI_CIPHER_AES_GCM, +}; + +static const u8 wmi_tlv_key_cipher_suites[] = { + [WMI_CIPHER_NONE] = WMI_TLV_CIPHER_NONE, + [WMI_CIPHER_WEP] = WMI_TLV_CIPHER_WEP, + [WMI_CIPHER_TKIP] = WMI_TLV_CIPHER_TKIP, + [WMI_CIPHER_AES_OCB] = WMI_TLV_CIPHER_AES_OCB, + [WMI_CIPHER_AES_CCM] = WMI_TLV_CIPHER_AES_CCM, + [WMI_CIPHER_WAPI] = WMI_TLV_CIPHER_WAPI, + [WMI_CIPHER_CKIP] = WMI_TLV_CIPHER_CKIP, + [WMI_CIPHER_AES_CMAC] = WMI_TLV_CIPHER_AES_CMAC, + [WMI_CIPHER_AES_GCM] = WMI_TLV_CIPHER_AES_GCM, +}; + static const struct wmi_peer_flags_map wmi_peer_flags_map = { .auth = WMI_PEER_AUTH, .qos = WMI_PEER_QOS, @@ -8421,6 +8445,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; + ar->wmi_key_cipher = wmi_key_cipher_suites; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; @@ -8428,6 +8453,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; + ar->wmi_key_cipher = wmi_key_cipher_suites; break; case ATH10K_FW_WMI_OP_VERSION_10_2: ar->wmi.cmd = &wmi_10_2_cmd_map; @@ -8435,6 +8461,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; + ar->wmi_key_cipher = wmi_key_cipher_suites; break; case ATH10K_FW_WMI_OP_VERSION_10_1: ar->wmi.cmd = &wmi_10x_cmd_map; @@ -8442,6 +8469,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; ar->wmi.peer_flags = &wmi_10x_peer_flags_map; + ar->wmi_key_cipher = wmi_key_cipher_suites; break; case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->wmi.cmd = &wmi_cmd_map; @@ -8449,9 +8477,11 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map; ar->wmi.peer_flags = &wmi_peer_flags_map; + ar->wmi_key_cipher = wmi_key_cipher_suites; break; case ATH10K_FW_WMI_OP_VERSION_TLV: ath10k_wmi_tlv_attach(ar); + ar->wmi_key_cipher = wmi_tlv_key_cipher_suites; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9ca3cea79fcee41735afe7504a8d31b6ec474a5b..661f23ffe59f36a66034cf7912f3a4393b1b5d19 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -202,6 +202,7 @@ enum wmi_service { WMI_SERVICE_TPC_STATS_FINAL, WMI_SERVICE_RESET_CHIP, WMI_SERVICE_SPOOF_MAC_SUPPORT, + WMI_SERVICE_SYNC_DELETE_CMDS, /* keep last */ WMI_SERVICE_MAX, @@ -453,6 +454,7 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE); SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH); + SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS); default: return NULL; } @@ -4765,15 +4767,30 @@ struct wmi_key_seq_counter { __le32 key_seq_counter_h; } __packed; -#define WMI_CIPHER_NONE 0x0 /* clear key */ -#define WMI_CIPHER_WEP 0x1 -#define WMI_CIPHER_TKIP 0x2 -#define WMI_CIPHER_AES_OCB 0x3 -#define WMI_CIPHER_AES_CCM 0x4 -#define WMI_CIPHER_WAPI 0x5 -#define WMI_CIPHER_CKIP 0x6 -#define WMI_CIPHER_AES_CMAC 0x7 -#define WMI_CIPHER_AES_GCM 0x8 +enum wmi_cipher_suites { + WMI_CIPHER_NONE, + WMI_CIPHER_WEP, + WMI_CIPHER_TKIP, + WMI_CIPHER_AES_OCB, + WMI_CIPHER_AES_CCM, + WMI_CIPHER_WAPI, + WMI_CIPHER_CKIP, + WMI_CIPHER_AES_CMAC, + WMI_CIPHER_AES_GCM, +}; + +enum wmi_tlv_cipher_suites { + WMI_TLV_CIPHER_NONE, + WMI_TLV_CIPHER_WEP, + WMI_TLV_CIPHER_TKIP, + WMI_TLV_CIPHER_AES_OCB, + WMI_TLV_CIPHER_AES_CCM, + WMI_TLV_CIPHER_WAPI, + WMI_TLV_CIPHER_CKIP, + WMI_TLV_CIPHER_AES_CMAC, + WMI_TLV_CIPHER_ANY, + WMI_TLV_CIPHER_AES_GCM, +}; struct wmi_vdev_install_key_cmd { __le32 vdev_id; @@ -6481,6 +6498,11 @@ struct wmi_scan_ev_arg { __le32 vdev_id; }; +struct wmi_peer_delete_resp_ev_arg { + __le32 vdev_id; + struct wmi_mac_addr peer_addr; +}; + struct wmi_mgmt_rx_ev_arg { __le32 channel; __le32 snr; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 72ad84fde5c1898ae4107e28442a527102ca511d..8e084670c3c239e6dbc74e35e82183e97fd8cd12 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1456,6 +1456,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); } + if (changed & IEEE80211_CONF_CHANGE_POWER) + ath9k_set_txpower(sc, NULL); + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index f1e3dad576292ef5b8e2f03a01a8c185c927a101..f435bd0f8b5b5efba00f8a7c17c4b18323d3987e 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -1304,8 +1304,9 @@ static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) } /* Interrupt handler bottom-half */ -static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) +static void b43legacy_interrupt_tasklet(unsigned long data) { + struct b43legacy_wldev *dev = (struct b43legacy_wldev *)data; u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; @@ -3775,7 +3776,7 @@ static int b43legacy_one_core_attach(struct ssb_device *dev, b43legacy_set_status(wldev, B43legacy_STAT_UNINIT); wldev->bad_frames_preempt = modparam_bad_frames_preempt; tasklet_init(&wldev->isr_tasklet, - (void (*)(unsigned long))b43legacy_interrupt_tasklet, + b43legacy_interrupt_tasklet, (unsigned long)wldev); if (modparam_pio) wldev->__using_pio = true; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 4c28b04ea60536dce86508a9bac3168c51015ab2..d198a8780b96670635c6a74b206b347f4a502028 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1932,6 +1932,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) BRCMF_SDIO_FT_NORMAL)) { rd->len = 0; brcmu_pkt_buf_free_skb(pkt); + continue; } bus->sdcnt.rx_readahead_cnt++; if (rd->len != roundup(rd_new.len, 16)) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 2eb5fe7367c6f5ccbeb08eb6b444bf30629469e4..4ad830b7b1c9818b15bda5defc4f162d3e76ce53 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -441,6 +441,7 @@ brcmf_usbdev_qinit(struct list_head *q, int qsize) usb_free_urb(req->urb); list_del(q->next); } + kfree(reqs); return NULL; } diff --git a/drivers/net/wireless/cnss_utils/cnss_utils.c b/drivers/net/wireless/cnss_utils/cnss_utils.c index 713b6a93820787cbb36e7e26bb8e9ec1101a3f14..7c1023905e3fba0f690ac3bf01915c7bee20eb7c 100644 --- a/drivers/net/wireless/cnss_utils/cnss_utils.c +++ b/drivers/net/wireless/cnss_utils/cnss_utils.c @@ -31,7 +31,7 @@ #define LPASS_PMU_INT_EN0 0xC060084 #define LPASS_PMU_INT_CLR 0xC060034 #endif -#define CNSS_MAX_CH_NUM 45 +#define CNSS_MAX_CH_NUM 157 struct cnss_unsafe_channel_list { u16 unsafe_ch_count; u16 unsafe_ch_list[CNSS_MAX_CH_NUM]; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 19c442cb93e4af2b50e72fe1c7b972cd0827c2f6..8fbdd7d4fd0c295406e63af57c2d2f036e109d1f 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -3220,8 +3220,9 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) } } -static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) +static void ipw2100_irq_tasklet(unsigned long data) { + struct ipw2100_priv *priv = (struct ipw2100_priv *)data; struct net_device *dev = priv->net_dev; unsigned long flags; u32 inta, tmp; @@ -6027,7 +6028,7 @@ static void ipw2100_rf_kill(struct work_struct *work) spin_unlock_irqrestore(&priv->low_lock, flags); } -static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); +static void ipw2100_irq_tasklet(unsigned long data); static const struct net_device_ops ipw2100_netdev_ops = { .ndo_open = ipw2100_open, @@ -6157,7 +6158,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill); INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event); - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + tasklet_init(&priv->irq_tasklet, ipw2100_irq_tasklet, (unsigned long)priv); /* NOTE: We do not start the deferred work for status checks yet */ diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 8da87496cb587f2ed92977649c6c31d12f1f32e8..2d0734ab3f747de9618fdc5009833664b256fec9 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -1966,8 +1966,9 @@ static void notify_wx_assoc_event(struct ipw_priv *priv) wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); } -static void ipw_irq_tasklet(struct ipw_priv *priv) +static void ipw_irq_tasklet(unsigned long data) { + struct ipw_priv *priv = (struct ipw_priv *)data; u32 inta, inta_mask, handled = 0; unsigned long flags; int rc = 0; @@ -10702,7 +10703,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate); #endif /* CONFIG_IPW2200_QOS */ - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + tasklet_init(&priv->irq_tasklet, ipw_irq_tasklet, (unsigned long)priv); return ret; diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 329f3a63dadd6e5f8ab2c3991481cd0997b1e265..0fb81151a1327752a221a707e826f5de4eadbd9d 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -1399,8 +1399,9 @@ il3945_dump_nic_error_log(struct il_priv *il) } static void -il3945_irq_tasklet(struct il_priv *il) +il3945_irq_tasklet(unsigned long data) { + struct il_priv *il = (struct il_priv *)data; u32 inta, handled = 0; u32 inta_fh; unsigned long flags; @@ -3432,7 +3433,7 @@ il3945_setup_deferred_work(struct il_priv *il) setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il); tasklet_init(&il->irq_tasklet, - (void (*)(unsigned long))il3945_irq_tasklet, + il3945_irq_tasklet, (unsigned long)il); } diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index de9b6522c43f5dba3855c0b4e94f57dd4b3915c5..665e82effb03df3e12fa9f57bac3780419f204f4 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4363,8 +4363,9 @@ il4965_synchronize_irq(struct il_priv *il) } static void -il4965_irq_tasklet(struct il_priv *il) +il4965_irq_tasklet(unsigned long data) { + struct il_priv *il = (struct il_priv *)data; u32 inta, handled = 0; u32 inta_fh; unsigned long flags; @@ -6264,7 +6265,7 @@ il4965_setup_deferred_work(struct il_priv *il) setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il); tasklet_init(&il->irq_tasklet, - (void (*)(unsigned long))il4965_irq_tasklet, + il4965_irq_tasklet, (unsigned long)il); } diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 8d5acda92a9b819eb00e159790f796bbcbe1cf27..6e6b124f0d5e35e21910111c2d36ea860a35877f 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -717,7 +717,7 @@ il_eeprom_init(struct il_priv *il) u32 gp = _il_rd(il, CSR_EEPROM_GP); int sz; int ret; - u16 addr; + int addr; /* allocate eeprom */ sz = il->cfg->eeprom_size; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index ca2d66ce84247f43cae8d44a4654062ed8f43e3e..b2e393c4fab58f44ffde4a19a02370b123e3c717 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -298,7 +298,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) int regulatory_type; /* Checking for required sections */ - if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) { + if (mvm->trans->cfg->nvm_type == IWL_NVM) { if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n"); @@ -326,7 +326,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) } /* PHY_SKU section is mandatory in B0 */ - if (!mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) { + if (mvm->trans->cfg->nvm_type == IWL_NVM_EXT && + !mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) { IWL_ERR(mvm, "Can't parse phy_sku in B0, empty sections\n"); return NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 684c0f65a0528a6bcb46b17276a8b0a64892ff46..d9ab85c8eb6a7b1e78f65e9cb081a9346f3f2aeb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2981,6 +2981,10 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, igtk_cmd.sta_id = cpu_to_le32(sta_id); if (remove_key) { + /* This is a valid situation for IGTK */ + if (sta_id == IWL_MVM_INVALID_STA) + return 0; + igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); } else { struct ieee80211_key_seq seq; @@ -3285,9 +3289,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", keyconf->keyidx, sta_id); - if (mvm_sta && (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)) + if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 1232f63278eb64167263e55255cb95b54c27258d..319103f4b432e16cdefbca802a372fe7860dd28b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -739,7 +739,8 @@ static struct thermal_zone_device_ops tzone_ops = { static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) { int i; - char name[] = "iwlwifi"; + char name[16]; + static atomic_t counter = ATOMIC_INIT(0); if (!iwl_mvm_is_tt_in_fw(mvm)) { mvm->tz_device.tzone = NULL; @@ -749,6 +750,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); + sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF); mvm->tz_device.tzone = thermal_zone_device_register(name, IWL_MAX_DTS_TRIPS, IWL_WRITABLE_TRIPS_MSK, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index dffa697d71e0f5160b0c34b1a53caee6842dde02..8a074a516fb2676d0df224c3a1c8dfdb2776aed7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3023,6 +3023,15 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->reg_lock); mutex_init(&trans_pcie->mutex); init_waitqueue_head(&trans_pcie->ucode_write_waitq); + + trans_pcie->rba.alloc_wq = alloc_workqueue("rb_allocator", + WQ_HIGHPRI | WQ_UNBOUND, 1); + if (!trans_pcie->rba.alloc_wq) { + ret = -ENOMEM; + goto out_free_trans; + } + INIT_WORK(&trans_pcie->rba.rx_alloc, iwl_pcie_rx_allocator_work); + trans_pcie->tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page); if (!trans_pcie->tso_hdr_page) { ret = -ENOMEM; @@ -3195,10 +3204,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->inta_mask = CSR_INI_SET_MASK; } - trans_pcie->rba.alloc_wq = alloc_workqueue("rb_allocator", - WQ_HIGHPRI | WQ_UNBOUND, 1); - INIT_WORK(&trans_pcie->rba.rx_alloc, iwl_pcie_rx_allocator_work); - #ifdef CONFIG_IWLWIFI_PCIE_RTPM trans->runtime_pm_mode = IWL_PLAT_PM_MODE_D0I3; #else @@ -3211,6 +3216,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, iwl_pcie_free_ict(trans); out_no_pci: free_percpu(trans_pcie->tso_hdr_page); + destroy_workqueue(trans_pcie->rba.alloc_wq); +out_free_trans: iwl_trans_free(trans); return ERR_PTR(ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index bbb39d6ec2ee30b8a92ec43432730bef27d27330..f37018d72b440e56499fe348e4e3ab93c6420eb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1124,6 +1124,9 @@ void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) iwl_pcie_gen2_txq_unmap(trans, queue); + iwl_pcie_gen2_txq_free_memory(trans, trans_pcie->txq[queue]); + trans_pcie->txq[queue] = NULL; + IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", queue); } diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index 1a8d8db80b05405de0a2f1a7160c56cb2fd0fdc3..486ca1ee306edd14045db1b524a05fb204974386 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -2568,7 +2568,7 @@ static int prism2_hostapd_add_sta(struct ap_data *ap, sta->supported_rates[0] = 2; if (sta->tx_supp_rates & WLAN_RATE_2M) sta->supported_rates[1] = 4; - if (sta->tx_supp_rates & WLAN_RATE_5M5) + if (sta->tx_supp_rates & WLAN_RATE_5M5) sta->supported_rates[2] = 11; if (sta->tx_supp_rates & WLAN_RATE_11M) sta->supported_rates[3] = 22; diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 95015d74b1c0e2311912514bd7a0c3d5ea7f3528..5a64674a5c8da621206b45d6a4cae5e8376ab646 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -1364,7 +1364,8 @@ static int ezusb_init(struct hermes *hw) int retval; BUG_ON(in_interrupt()); - BUG_ON(!upriv); + if (!upriv) + return -EINVAL; upriv->reply_count = 0; /* Write the MAGIC number on the simulated registers to keep diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 27224dc264133aebd95bff20a2e068e4c5066dba..a8ec5b2c5abb3d07b76ea9107e827e13ee41c45f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3134,9 +3134,9 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) param.no_vif = true; if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { - hwname = kasprintf(GFP_KERNEL, "%.*s", - nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), - (char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME])); + hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), + nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), + GFP_KERNEL); if (!hwname) return -ENOMEM; param.hwname = hwname; @@ -3175,9 +3175,9 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) if (info->attrs[HWSIM_ATTR_RADIO_ID]) { idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { - hwname = kasprintf(GFP_KERNEL, "%.*s", - nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), - (char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME])); + hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), + nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), + GFP_KERNEL); if (!hwname) return -ENOMEM; } else diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 4ffc188d2ffd315f33637fdc69a410545e01af7d..fbeb12018c3d6d6d49babb378b7f16cd268a7ce2 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1788,6 +1788,8 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, rates_max = rates_eid[1]; if (rates_max > MAX_RATES) { lbs_deb_join("invalid rates"); + rcu_read_unlock(); + ret = -EINVAL; goto out; } rates = cmd.bss.rates; diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index c013c94fbf15f92cde66b88b14c2ad7017213518..0071c40afe81bbdbb1f450422c05b75c74783f5b 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2890,6 +2890,13 @@ mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, vs_param_set->header.len = cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) & 0x00FF) + 2); + if (le16_to_cpu(vs_param_set->header.len) > + MWIFIEX_MAX_VSIE_LEN) { + mwifiex_dbg(priv->adapter, ERROR, + "Invalid param length!\n"); + break; + } + memcpy(vs_param_set->ie, priv->vs_ie[id].ie, le16_to_cpu(vs_param_set->header.len)); *buffer += le16_to_cpu(vs_param_set->header.len) + diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index f88a953b3cd577d4c5322f1c19e50456556c717a..652acafca1368944a9f10fac0b1a412fab44f9c7 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -274,6 +274,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, if (country_ie_len > (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) { + rcu_read_unlock(); mwifiex_dbg(priv->adapter, ERROR, "11D: country_ie_len overflow!, deauth AP\n"); return -EINVAL; diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index b5340af9fa5ecfd0a2719c0a7b14de9f7ff68f84..80d20fb6f3480e51bea75380a91bacd13eb9568d 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -897,7 +897,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, u8 *peer, *pos, *end; u8 i, action, basic; u16 cap = 0; - int ie_len = 0; + int ies_len = 0; if (len < (sizeof(struct ethhdr) + 3)) return; @@ -919,7 +919,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, pos = buf + sizeof(struct ethhdr) + 4; /* payload 1+ category 1 + action 1 + dialog 1 */ cap = get_unaligned_le16(pos); - ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN; + ies_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN; pos += 2; break; @@ -929,7 +929,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/ pos = buf + sizeof(struct ethhdr) + 6; cap = get_unaligned_le16(pos); - ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN; + ies_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN; pos += 2; break; @@ -937,7 +937,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN)) return; pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN; - ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN; + ies_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN; break; default: mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n"); @@ -950,33 +950,33 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, sta_ptr->tdls_cap.capab = cpu_to_le16(cap); - for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) { - if (pos + 2 + pos[1] > end) + for (end = pos + ies_len; pos + 1 < end; pos += 2 + pos[1]) { + u8 ie_len = pos[1]; + + if (pos + 2 + ie_len > end) break; switch (*pos) { case WLAN_EID_SUPP_RATES: - if (pos[1] > 32) + if (ie_len > sizeof(sta_ptr->tdls_cap.rates)) return; - sta_ptr->tdls_cap.rates_len = pos[1]; - for (i = 0; i < pos[1]; i++) + sta_ptr->tdls_cap.rates_len = ie_len; + for (i = 0; i < ie_len; i++) sta_ptr->tdls_cap.rates[i] = pos[i + 2]; break; case WLAN_EID_EXT_SUPP_RATES: - if (pos[1] > 32) + if (ie_len > sizeof(sta_ptr->tdls_cap.rates)) return; basic = sta_ptr->tdls_cap.rates_len; - if (pos[1] > 32 - basic) + if (ie_len > sizeof(sta_ptr->tdls_cap.rates) - basic) return; - for (i = 0; i < pos[1]; i++) + for (i = 0; i < ie_len; i++) sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; - sta_ptr->tdls_cap.rates_len += pos[1]; + sta_ptr->tdls_cap.rates_len += ie_len; break; case WLAN_EID_HT_CAPABILITY: - if (pos > end - sizeof(struct ieee80211_ht_cap) - 2) - return; - if (pos[1] != sizeof(struct ieee80211_ht_cap)) + if (ie_len != sizeof(struct ieee80211_ht_cap)) return; /* copy the ie's value into ht_capb*/ memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2, @@ -984,59 +984,45 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, sta_ptr->is_11n_enabled = 1; break; case WLAN_EID_HT_OPERATION: - if (pos > end - - sizeof(struct ieee80211_ht_operation) - 2) - return; - if (pos[1] != sizeof(struct ieee80211_ht_operation)) + if (ie_len != sizeof(struct ieee80211_ht_operation)) return; /* copy the ie's value into ht_oper*/ memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2, sizeof(struct ieee80211_ht_operation)); break; case WLAN_EID_BSS_COEX_2040: - if (pos > end - 3) - return; - if (pos[1] != 1) + if (ie_len != sizeof(pos[2])) return; sta_ptr->tdls_cap.coex_2040 = pos[2]; break; case WLAN_EID_EXT_CAPABILITY: - if (pos > end - sizeof(struct ieee_types_header)) - return; - if (pos[1] < sizeof(struct ieee_types_header)) + if (ie_len < sizeof(struct ieee_types_header)) return; - if (pos[1] > 8) + if (ie_len > 8) return; memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, sizeof(struct ieee_types_header) + - min_t(u8, pos[1], 8)); + min_t(u8, ie_len, 8)); break; case WLAN_EID_RSN: - if (pos > end - sizeof(struct ieee_types_header)) + if (ie_len < sizeof(struct ieee_types_header)) return; - if (pos[1] < sizeof(struct ieee_types_header)) - return; - if (pos[1] > IEEE_MAX_IE_SIZE - + if (ie_len > IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)) return; memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, sizeof(struct ieee_types_header) + - min_t(u8, pos[1], IEEE_MAX_IE_SIZE - + min_t(u8, ie_len, IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: - if (pos > end - 3) - return; - if (pos[1] != 1) + if (ie_len != sizeof(pos[2])) return; sta_ptr->tdls_cap.qos_info = pos[2]; break; case WLAN_EID_VHT_OPERATION: if (priv->adapter->is_hw_11ac_capable) { - if (pos > end - - sizeof(struct ieee80211_vht_operation) - 2) - return; - if (pos[1] != + if (ie_len != sizeof(struct ieee80211_vht_operation)) return; /* copy the ie's value into vhtoper*/ @@ -1046,10 +1032,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, break; case WLAN_EID_VHT_CAPABILITY: if (priv->adapter->is_hw_11ac_capable) { - if (pos > end - - sizeof(struct ieee80211_vht_cap) - 2) - return; - if (pos[1] != sizeof(struct ieee80211_vht_cap)) + if (ie_len != sizeof(struct ieee80211_vht_cap)) return; /* copy the ie's value into vhtcap*/ memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2, @@ -1059,9 +1042,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, break; case WLAN_EID_AID: if (priv->adapter->is_hw_11ac_capable) { - if (pos > end - 4) - return; - if (pos[1] != 2) + if (ie_len != sizeof(u16)) return; sta_ptr->tdls_cap.aid = get_unaligned_le16((pos + 2)); diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 7fba4d940131c8042a64827c4457dd73dbf10980..a13b05ec8fc03dd0f981cb1ac7364a9a9c75e532 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -976,6 +976,10 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, "WMM Parameter Set Count: %d\n", wmm_param_ie->qos_info_bitmap & mask); + if (wmm_param_ie->vend_hdr.len + 2 > + sizeof(struct ieee_types_wmm_parameter)) + break; + memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. wmm_ie, wmm_param_ie, wmm_param_ie->vend_hdr.len + 2); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 457a0f725c8aa598c14ea80b38e6d4a6d4183c48..ab74f3155854059035013bb39857f73b1d8aa56a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1091,13 +1091,15 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) return ret; } -static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) +static void _rtl_pci_irq_tasklet(unsigned long data) { + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; _rtl_pci_tx_chk_waitq(hw); } -static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) +static void _rtl_pci_prepare_bcn_tasklet(unsigned long data) { + struct ieee80211_hw *hw = (struct ieee80211_hw *)data; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -1223,10 +1225,10 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, /*task */ tasklet_init(&rtlpriv->works.irq_tasklet, - (void (*)(unsigned long))_rtl_pci_irq_tasklet, + _rtl_pci_irq_tasklet, (unsigned long)hw); tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, - (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, + _rtl_pci_prepare_bcn_tasklet, (unsigned long)hw); INIT_WORK(&rtlpriv->works.lps_change_work, rtl_lps_change_work_callback); diff --git a/drivers/nfc/fdp/fdp.c b/drivers/nfc/fdp/fdp.c index ec50027b0d8ba327b5b125249e1fdc142426b7e9..3195bae1685f94786c72d2fa3c73386b55a60c6a 100644 --- a/drivers/nfc/fdp/fdp.c +++ b/drivers/nfc/fdp/fdp.c @@ -192,7 +192,7 @@ static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type) const struct firmware *fw; struct sk_buff *skb; unsigned long len; - u8 max_size, payload_size; + int max_size, payload_size; int rc = 0; if ((type == NCI_PATCH_TYPE_OTP && !info->otp_patch) || @@ -215,8 +215,7 @@ static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type) while (len) { - payload_size = min_t(unsigned long, (unsigned long) max_size, - len); + payload_size = min_t(unsigned long, max_size, len); skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + payload_size), GFP_KERNEL); diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 4b14740edb672c734239eb4c26282c036009d415..8ba5a6d6329e023d56c553becffdaa398c166149 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -236,6 +236,7 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) out: gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity); + usleep_range(10000, 15000); } static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode) diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 70e898e38b16189ea3ab0d6233e09209b29966f9..f30bdf95610f4b5d06fdff099c42b332cc1b6794 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -704,7 +704,7 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, target->nfcid1_len != 10) return -EOPNOTSUPP; - return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, PN544_RF_READER_CMD_ACTIVATE_NEXT, target->nfcid1, target->nfcid1_len, NULL); } else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK | diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index 60ae382f50da9887ad900a14807835490eb6bee3..06bb226c62ef46e734d5d10887b0dbc38ce8ff7e 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c @@ -574,7 +574,7 @@ static void port100_tx_update_payload_len(void *_frame, int len) { struct port100_frame *frame = _frame; - frame->datalen = cpu_to_le16(le16_to_cpu(frame->datalen) + len); + le16_add_cpu(&frame->datalen, len); } static bool port100_rx_frame_is_valid(void *_frame) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 4587c97735600aa25ca1b05253dab7d576be9cde..66cc42a7dc6e600f168c7c3f254a6f8099fe07c1 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -952,8 +952,10 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, return -EFAULT; } - if (!desc || (desc->out_num + desc->in_num == 0) || - !test_bit(cmd, &cmd_mask)) + if (!desc || + (desc->out_num + desc->in_num == 0) || + cmd > ND_CMD_CALL || + !test_bit(cmd, &cmd_mask)) return -ENOTTY; /* fail write commands (when read-only) */ diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f543b9932c830ba0ad62af837362fd6f7bad1257..a760c449f4a90566db6025a363a9405a6f62ef80 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -889,8 +889,8 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl *ctrl, static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11, void *buffer, size_t buflen, u32 *result) { + union nvme_result res = { 0 }; struct nvme_command c; - union nvme_result res; int ret; memset(&c, 0, sizeof(c)); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 9e4d2ecf736d563240aee9ca992359940a7a4709..058d542647dd5d1f6b8ba55b166c3a4cf03f89a4 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -337,8 +337,7 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo, !template->ls_req || !template->fcp_io || !template->ls_abort || !template->fcp_abort || !template->max_hw_queues || !template->max_sgl_segments || - !template->max_dif_sgl_segments || !template->dma_boundary || - !template->module) { + !template->max_dif_sgl_segments || !template->dma_boundary) { ret = -EINVAL; goto out_reghost_failed; } @@ -1763,7 +1762,6 @@ nvme_fc_ctrl_free(struct kref *ref) { struct nvme_fc_ctrl *ctrl = container_of(ref, struct nvme_fc_ctrl, ref); - struct nvme_fc_lport *lport = ctrl->lport; unsigned long flags; if (ctrl->ctrl.tagset) { @@ -1789,7 +1787,6 @@ nvme_fc_ctrl_free(struct kref *ref) if (ctrl->ctrl.opts) nvmf_free_options(ctrl->ctrl.opts); kfree(ctrl); - module_put(lport->ops->module); } static void @@ -2768,15 +2765,10 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, goto out_fail; } - if (!try_module_get(lport->ops->module)) { - ret = -EUNATCH; - goto out_free_ctrl; - } - idx = ida_simple_get(&nvme_fc_ctrl_cnt, 0, 0, GFP_KERNEL); if (idx < 0) { ret = -ENOSPC; - goto out_mod_put; + goto out_free_ctrl; } ctrl->ctrl.opts = opts; @@ -2923,8 +2915,6 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, out_free_ida: put_device(ctrl->dev); ida_simple_remove(&nvme_fc_ctrl_cnt, ctrl->cnum); -out_mod_put: - module_put(lport->ops->module); out_free_ctrl: kfree(ctrl); out_fail: diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index b8fe8702065bc1f88d26f8f292ef321412ab3b99..096523d8dd422b511c17290065dbaa290debd877 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -693,7 +693,6 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport) #define FCLOOP_DMABOUND_4G 0xFFFFFFFF static struct nvme_fc_port_template fctemplate = { - .module = THIS_MODULE, .localport_delete = fcloop_localport_delete, .remoteport_delete = fcloop_remoteport_delete, .create_queue = fcloop_create_queue, diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 0a963b17910528768eaa3562209bb906a3fa1a5c..000a96a0379b5541f75a969e12f97fdbe7ee9d62 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -133,4 +133,8 @@ config OF_BATTERYDATA help OpenFirmware BatteryData accessors +config OF_DMA_DEFAULT_COHERENT + # arches should select this if DMA is coherent by default for OF devices + bool + endif # OF diff --git a/drivers/of/address.c b/drivers/of/address.c index 792722e7d45884add844d9931ddef7dc5e816f0f..456339c19aed7bc9f3fdd362107dbc38f3a8831d 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -894,12 +894,16 @@ EXPORT_SYMBOL_GPL(of_dma_get_range); * @np: device node * * It returns true if "dma-coherent" property was found - * for this device in DT. + * for this device in the DT, or if DMA is coherent by + * default for OF devices on the current platform. */ bool of_dma_is_coherent(struct device_node *np) { struct device_node *node = of_node_get(np); + if (IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT)) + return true; + while (node) { if (of_property_read_bool(node, "dma-coherent")) { of_node_put(node); diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index fe26697d3bd724d048df132d95ab74797fc0f100..69da2f6896dae5261533ad11dcddfc75a002119d 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -259,6 +259,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) rc = of_mdiobus_register_phy(mdio, child, addr); if (rc && rc != -ENODEV) goto unregister; + break; } } } diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 4bf6a9db6ac0c2622cffcc56270a6a8318da4fe9..55c98f119df226ac1046d53e0566e56b22f237c3 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -887,10 +887,13 @@ static void __init of_unittest_platform_populate(void) of_platform_populate(np, match, NULL, &test_bus->dev); for_each_child_of_node(np, child) { - for_each_child_of_node(child, grandchild) - unittest(of_find_device_by_node(grandchild), + for_each_child_of_node(child, grandchild) { + pdev = of_find_device_by_node(grandchild); + unittest(pdev, "Could not create device for node '%s'\n", grandchild->name); + of_dev_put(pdev); + } } of_platform_depopulate(&test_bus->dev); diff --git a/drivers/pci/dwc/pci-keystone-dw.c b/drivers/pci/dwc/pci-keystone-dw.c index 2fb20b887d2a5f70de614995523beefdf201636d..4cf2662930d86942aea9c21d0cd555033e99f58d 100644 --- a/drivers/pci/dwc/pci-keystone-dw.c +++ b/drivers/pci/dwc/pci-keystone-dw.c @@ -510,7 +510,7 @@ void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) /* Disable Link training */ val = ks_dw_app_readl(ks_pcie, CMD_STATUS); val &= ~LTSSM_EN_VAL; - ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + ks_dw_app_writel(ks_pcie, CMD_STATUS, val); /* Initiate Link Training */ val = ks_dw_app_readl(ks_pcie, CMD_STATUS); diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c index 83b7d5d3fc3e465d37f6eaf361f217279f8f8db7..60fbfe92e0ef8249cc5057f2d9a2bf1d48df58a0 100644 --- a/drivers/pci/endpoint/pci-epc-mem.c +++ b/drivers/pci/endpoint/pci-epc-mem.c @@ -90,6 +90,7 @@ int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size, mem->page_size = page_size; mem->pages = pages; mem->size = size; + mutex_init(&mem->lock); epc->mem = mem; @@ -133,7 +134,7 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, phys_addr_t *phys_addr, size_t size) { int pageno; - void __iomem *virt_addr; + void __iomem *virt_addr = NULL; struct pci_epc_mem *mem = epc->mem; unsigned int page_shift = ilog2(mem->page_size); int order; @@ -141,15 +142,18 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, size = ALIGN(size, mem->page_size); order = pci_epc_mem_get_order(mem, size); + mutex_lock(&mem->lock); pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); if (pageno < 0) - return NULL; + goto ret; *phys_addr = mem->phys_base + (pageno << page_shift); virt_addr = ioremap(*phys_addr, size); if (!virt_addr) bitmap_release_region(mem->bitmap, pageno, order); +ret: + mutex_unlock(&mem->lock); return virt_addr; } EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); @@ -175,7 +179,9 @@ void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, pageno = (phys_addr - mem->phys_base) >> page_shift; size = ALIGN(size, mem->page_size); order = pci_epc_mem_get_order(mem, size); + mutex_lock(&mem->lock); bitmap_release_region(mem->bitmap, pageno, order); + mutex_unlock(&mem->lock); } EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr); diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 30c419d22ef87c3944839c0892ca1c92168326a0..ad55f37d00022724a6adaad22a04d33c6d013afb 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -50,7 +50,6 @@ #include #include #include -#include #define PCIE_VENDOR_ID_QCOM 0x17cb @@ -3725,7 +3724,7 @@ static int msm_pcie_get_resources(struct msm_pcie_dev_t *dev, of_property_read_u32_array(pdev->dev.of_node, "qcom,bw-scale", (u32 *)dev->bw_scale, size / sizeof(u32)); - dev->bw_gen_max = size / sizeof(u32); + dev->bw_gen_max = size / sizeof(*dev->bw_scale); } else { PCIE_DBG(dev, "RC%d: bandwidth scaling is not supported\n", dev->rc_idx); @@ -5758,14 +5757,12 @@ static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev) pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev); } -static int __msm_pcie_probe(void *arg) +static int msm_pcie_probe(struct platform_device *pdev) { int ret = 0; int rc_idx = -1; int i, j; - struct platform_device *pdev; - pdev = (struct platform_device *)arg; PCIE_GEN_DBG("%s\n", __func__); mutex_lock(&pcie_drv.drv_lock); @@ -6253,24 +6250,6 @@ static int __msm_pcie_probe(void *arg) return ret; } -static int msm_pcie_probe(struct platform_device *pdev) -{ -#ifdef CONFIG_PLATFORM_AUTO - struct task_struct *msm_pcie_task = - kthread_run(__msm_pcie_probe, pdev, - "msm_pcie_probe"); - if (IS_ERR(msm_pcie_task)) - return PTR_ERR(msm_pcie_task); - else - return 0; -#else - int ret = 0; - - ret = __msm_pcie_probe(pdev); - return ret; -#endif -} - static int msm_pcie_remove(struct platform_device *pdev) { int ret = 0; @@ -6471,6 +6450,15 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, pcie_dev = PCIE_BUS_PRIV_DATA(root_pci_dev->bus); + if (target_link_speed > pcie_dev->bw_gen_max || + (pcie_dev->target_link_speed && + target_link_speed > pcie_dev->target_link_speed)) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: invalid target link speed: %d\n", + pcie_dev->rc_idx, target_link_speed); + return -EINVAL; + } + pcie_capability_read_word(root_pci_dev, PCI_EXP_LNKSTA, &link_status); current_link_speed = link_status & PCI_EXP_LNKSTA_CLS; diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 0fd8e164339c3e6352af98eb5240e885c10e5103..0dc646c1bc3db9eb822153411bc5c4f61c029a5e 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -179,6 +179,7 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset) failed2: sysfs_remove_link(&dev->dev.kobj, buf); failed1: + pci_stop_and_remove_bus_device(virtfn); pci_dev_put(dev); pci_stop_and_remove_bus_device(virtfn); failed0: diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 2b95984c6a57b61d65507ef913198da9b07f8e89..9146f01ffeb251496b4a59771674dcacf5b53bc0 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -80,6 +80,7 @@ struct pcie_link_state { u32 clkpm_capable:1; /* Clock PM capable? */ u32 clkpm_enabled:1; /* Current Clock PM state */ u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + u32 clkpm_disable:1; /* Clock PM disabled */ /* Exit latencies */ struct aspm_latency latency_up; /* Upstream direction exit latency */ @@ -177,8 +178,11 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) static void pcie_set_clkpm(struct pcie_link_state *link, int enable) { - /* Don't enable Clock PM if the link is not Clock PM capable */ - if (!link->clkpm_capable) + /* + * Don't enable Clock PM if the link is not Clock PM capable + * or Clock PM is disabled + */ + if (!link->clkpm_capable || link->clkpm_disable) enable = 0; /* Need nothing if the specified equals to current state */ if (link->clkpm_enabled == enable) @@ -208,7 +212,8 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) } link->clkpm_enabled = enabled; link->clkpm_default = enabled; - link->clkpm_capable = (blacklist) ? 0 : capable; + link->clkpm_capable = capable; + link->clkpm_disable = blacklist ? 1 : 0; } static bool pcie_retrain_link(struct pcie_link_state *link) @@ -693,9 +698,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) /* Enable what we need to enable */ pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1, - PCI_L1SS_CAP_L1_PM_SS, val); + PCI_L1SS_CTL1_L1SS_MASK, val); pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1, - PCI_L1SS_CAP_L1_PM_SS, val); + PCI_L1SS_CTL1_L1SS_MASK, val); } static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) @@ -1052,10 +1057,9 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) link->aspm_disable |= ASPM_STATE_L1; pcie_config_aspm_link(link, policy_to_aspm_state(link)); - if (state & PCIE_LINK_STATE_CLKPM) { - link->clkpm_capable = 0; - pcie_set_clkpm(link, 0); - } + if (state & PCIE_LINK_STATE_CLKPM) + link->clkpm_disable = 1; + pcie_set_clkpm(link, policy_to_clkpm_state(link)); mutex_unlock(&aspm_lock); if (sem) up_read(&pci_bus_sem); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e7ed051ec125ee37768ee4771a43609eaac92500..530646c4c5913ac4723b2fe01f5e19aa83aa57a2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4588,6 +4588,7 @@ static const struct pci_dev_acs_enabled { /* QCOM QDF2xxx root ports */ { 0x17cb, 0x400, pci_quirk_qcom_rp_acs }, { 0x17cb, 0x401, pci_quirk_qcom_rp_acs }, + { 0x17cb, 0x10c, pci_quirk_qcom_rp_acs }, /* Intel PCH root ports */ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs }, diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 958da7db90331c44315f95ab90553c586d918c46..fb73e975d22b55a365bcbbfdf15731c5cb2e13ac 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1824,12 +1824,18 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) /* restore size and flags */ list_for_each_entry(fail_res, &fail_head, list) { struct resource *res = fail_res->res; + int idx; res->start = fail_res->start; res->end = fail_res->end; res->flags = fail_res->flags; - if (fail_res->dev->subordinate) - res->flags = 0; + + if (pci_is_bridge(fail_res->dev)) { + idx = res - &fail_res->dev->resource[0]; + if (idx >= PCI_BRIDGE_RESOURCES && + idx <= PCI_BRIDGE_RESOURCE_END) + res->flags = 0; + } } free_list(&fail_head); @@ -1895,12 +1901,18 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) /* restore size and flags */ list_for_each_entry(fail_res, &fail_head, list) { struct resource *res = fail_res->res; + int idx; res->start = fail_res->start; res->end = fail_res->end; res->flags = fail_res->flags; - if (fail_res->dev->subordinate) - res->flags = 0; + + if (pci_is_bridge(fail_res->dev)) { + idx = res - &fail_res->dev->resource[0]; + if (idx >= PCI_BRIDGE_RESOURCES && + idx <= PCI_BRIDGE_RESOURCE_END) + res->flags = 0; + } } free_list(&fail_head); diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 73dba2739849b08218996a7b759412cf9c3da693..6ef0d4b756f0994d503565f2be38fdd83be7f266 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -412,7 +412,7 @@ static int mrpc_queue_cmd(struct switchtec_user *stuser) kref_get(&stuser->kref); stuser->read_len = sizeof(stuser->data); stuser_set_state(stuser, MRPC_QUEUED); - init_completion(&stuser->comp); + reinit_completion(&stuser->comp); list_add_tail(&stuser->list, &stdev->mrpc_queue); mrpc_cmd_submit(stdev); @@ -1399,7 +1399,7 @@ static int switchtec_init_isr(struct switchtec_dev *stdev) if (nvecs < 0) return nvecs; - event_irq = ioread32(&stdev->mmio_part_cfg->vep_vector_number); + event_irq = ioread16(&stdev->mmio_part_cfg->vep_vector_number); if (event_irq < 0 || event_irq >= nvecs) return -EFAULT; diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c index 3303dd8d8eb5718f96de5326949ba89a60e9f32e..604e549a9a47d2986ddd13793b5c847ff12c574d 100644 --- a/drivers/perf/arm_pmu_acpi.c +++ b/drivers/perf/arm_pmu_acpi.c @@ -25,8 +25,6 @@ static int arm_pmu_acpi_register_irq(int cpu) int gsi, trigger; gicc = acpi_cpu_get_madt_gicc(cpu); - if (WARN_ON(!gicc)) - return -EINVAL; gsi = gicc->performance_interrupt; @@ -65,11 +63,10 @@ static void arm_pmu_acpi_unregister_irq(int cpu) int gsi; gicc = acpi_cpu_get_madt_gicc(cpu); - if (!gicc) - return; gsi = gicc->performance_interrupt; - acpi_unregister_gsi(gsi); + if (gsi) + acpi_unregister_gsi(gsi); } static int arm_pmu_acpi_parse_irqs(void) diff --git a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c index 69ce2afac0150fb580630921ed4f9892d58dab77..c6925e3e878bfc7770c2176639e1c939afeaef82 100644 --- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c @@ -88,7 +88,7 @@ static int read_poll_timeout(void __iomem *addr, u32 mask) if (readl_relaxed(addr) & mask) return 0; - usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); + usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); } while (!time_after(jiffies, timeout)); return (readl_relaxed(addr) & mask) ? 0 : -ETIMEDOUT; diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index c55517312485d5ab3f8257e2b7ada1fbe5856778..08ea74177de296d877f1d1fa11a37d30065b9625 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -2031,7 +2031,6 @@ static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev) return PTR_ERR(pctldev->p); } - kref_get(&pctldev->p->users); pctldev->hog_default = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT); if (IS_ERR(pctldev->hog_default)) { diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 9df5d29d708da14403b386982635c80478fa3592..4fb3e44f91331acab6e70dcd6d5817b796d64742 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -958,7 +958,13 @@ static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned int offset) raw_spin_lock_irqsave(&byt_lock, flags); value = readl(reg); - value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + + /* Do not clear direct-irq enabled IRQs (from gpio_disable_free) */ + if (value & BYT_DIRECT_IRQ_EN) + /* nothing to do */ ; + else + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + writel(value, reg); raw_spin_unlock_irqrestore(&byt_lock, flags); } diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c index 36c14b85fc7cde0caf54330423c38d4092bde04a..8db182067ecb0ee94d432f686ede43c51794ad23 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c @@ -158,8 +158,8 @@ static const unsigned int sdio_d0_pins[] = { PIN(GPIOX_0, EE_OFF) }; static const unsigned int sdio_d1_pins[] = { PIN(GPIOX_1, EE_OFF) }; static const unsigned int sdio_d2_pins[] = { PIN(GPIOX_2, EE_OFF) }; static const unsigned int sdio_d3_pins[] = { PIN(GPIOX_3, EE_OFF) }; -static const unsigned int sdio_cmd_pins[] = { PIN(GPIOX_4, EE_OFF) }; -static const unsigned int sdio_clk_pins[] = { PIN(GPIOX_5, EE_OFF) }; +static const unsigned int sdio_clk_pins[] = { PIN(GPIOX_4, EE_OFF) }; +static const unsigned int sdio_cmd_pins[] = { PIN(GPIOX_5, EE_OFF) }; static const unsigned int sdio_irq_pins[] = { PIN(GPIOX_7, EE_OFF) }; static const unsigned int nand_ce0_pins[] = { PIN(BOOT_8, EE_OFF) }; diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index 75d5a096676de2063350489ca3812aedc10f1599..8d28839de8a026e2915924589f9b8f34261dc791 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * Copyright (c) 2016, BayLibre, SAS. All rights reserved. * Author: Neil Armstrong @@ -40,6 +40,9 @@ #include "pinconf.h" #include "pinctrl-utils.h" +static bool in_kexec_panic; +static struct notifier_block *panic_block; + /* The chip models of sx150x */ enum { SX150X_123 = 0, @@ -581,6 +584,14 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) struct sx150x_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(d)); + /* In crash kexec panic path interrupt is disabled. + * Writing to regmap will need interrupt/polling mode, + * as it goes though i2c. + */ + if (in_kexec_panic) { + mutex_unlock(&pctl->lock); + return; + } regmap_write(pctl->regmap, pctl->data->reg_irq_mask, pctl->irq.masked); regmap_write(pctl->regmap, pctl->data->reg_sense, pctl->irq.sense); mutex_unlock(&pctl->lock); @@ -1102,6 +1113,14 @@ const struct regmap_config sx150x_regmap_config = { .volatile_reg = sx150x_reg_volatile, }; +static int sx150x_panic_handler(struct notifier_block *this, + unsigned long event, void *ptr) +{ + if (crash_kexec_post_notifiers) + in_kexec_panic = 1; + return NOTIFY_DONE; +} + static int sx150x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1301,6 +1320,12 @@ static struct i2c_driver sx150x_driver = { static int __init sx150x_init(void) { + panic_block = kzalloc(sizeof(*panic_block), GFP_KERNEL); + if (!panic_block) + return -ENOMEM; + panic_block->notifier_call = sx150x_panic_handler; + atomic_notifier_chain_register(&panic_notifier_list, + panic_block); return i2c_add_driver(&sx150x_driver); } subsys_initcall(sx150x_init); diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c index c3af9ebee4afc7b0cc4d73a7aad0144cbcae8dc9..28c0405ba396f9500f5d3dd55c318a26abbb097c 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c @@ -2325,7 +2325,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_ATAG0_A, 0, FN_REMOCON_B, 0, /* IP0_11_8 [4] */ FN_SD1_DAT2_A, FN_MMC_D2, 0, FN_BS, - FN_ATADIR0_A, 0, FN_SDSELF_B, 0, + FN_ATADIR0_A, 0, FN_SDSELF_A, 0, FN_PWM4_B, 0, 0, 0, 0, 0, 0, 0, /* IP0_7_5 [3] */ @@ -2367,7 +2367,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_TS_SDAT0_A, 0, 0, 0, 0, 0, 0, 0, /* IP1_10_8 [3] */ - FN_SD1_CLK_B, FN_MMC_D6, 0, FN_A24, + FN_SD1_CD_A, FN_MMC_D6, 0, FN_A24, FN_DREQ1_A, 0, FN_HRX0_B, FN_TS_SPSYNC0_A, /* IP1_7_5 [3] */ FN_A23, FN_HTX0_B, FN_TX2_B, FN_DACK2_A, diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7264.c b/drivers/pinctrl/sh-pfc/pfc-sh7264.c index e1c34e19222ee7bcf12d3a98f348b9d749b312fe..3ddb9565ed8044486308ef1abe631568ffec55bd 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7264.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7264.c @@ -500,17 +500,15 @@ enum { SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK, CRX0_MARK, CRX1_MARK, CTX0_MARK, CTX1_MARK, + CRX0_CRX1_MARK, CTX0_CTX1_MARK, PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK, PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK, PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK, PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK, IERXD_MARK, IETXD_MARK, - CRX0_CRX1_MARK, WDTOVF_MARK, - CRX0X1_MARK, - /* DMAC */ TEND0_MARK, DACK0_MARK, DREQ0_MARK, TEND1_MARK, DACK1_MARK, DREQ1_MARK, @@ -998,12 +996,12 @@ static const u16 pinmux_data[] = { PINMUX_DATA(PJ3_DATA, PJ3MD_00), PINMUX_DATA(CRX1_MARK, PJ3MD_01), - PINMUX_DATA(CRX0X1_MARK, PJ3MD_10), + PINMUX_DATA(CRX0_CRX1_MARK, PJ3MD_10), PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11), PINMUX_DATA(PJ2_DATA, PJ2MD_000), PINMUX_DATA(CTX1_MARK, PJ2MD_001), - PINMUX_DATA(CRX0_CRX1_MARK, PJ2MD_010), + PINMUX_DATA(CTX0_CTX1_MARK, PJ2MD_010), PINMUX_DATA(CS2_MARK, PJ2MD_011), PINMUX_DATA(SCK0_MARK, PJ2MD_100), PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101), @@ -1248,6 +1246,7 @@ static const struct pinmux_func pinmux_func_gpios[] = { GPIO_FN(CTX1), GPIO_FN(CRX1), GPIO_FN(CTX0), + GPIO_FN(CTX0_CTX1), GPIO_FN(CRX0), GPIO_FN(CRX0_CRX1), diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c index cfdb4fc177c3e2133cf8b59afce5b7fbcc91a28b..3df0c0d139d08f6bd889084373ecd81610f5b618 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7269.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c @@ -740,13 +740,12 @@ enum { CRX0_MARK, CTX0_MARK, CRX1_MARK, CTX1_MARK, CRX2_MARK, CTX2_MARK, - CRX0_CRX1_MARK, - CRX0_CRX1_CRX2_MARK, - CTX0CTX1CTX2_MARK, + CRX0_CRX1_MARK, CTX0_CTX1_MARK, + CRX0_CRX1_CRX2_MARK, CTX0_CTX1_CTX2_MARK, CRX1_PJ22_MARK, CTX1_PJ23_MARK, CRX2_PJ20_MARK, CTX2_PJ21_MARK, - CRX0CRX1_PJ22_MARK, - CRX0CRX1CRX2_PJ20_MARK, + CRX0_CRX1_PJ22_MARK, CTX0_CTX1_PJ23_MARK, + CRX0_CRX1_CRX2_PJ20_MARK, CTX0_CTX1_CTX2_PJ21_MARK, /* VDC */ DV_CLK_MARK, @@ -824,6 +823,7 @@ static const u16 pinmux_data[] = { PINMUX_DATA(CS3_MARK, PC8MD_001), PINMUX_DATA(TXD7_MARK, PC8MD_010), PINMUX_DATA(CTX1_MARK, PC8MD_011), + PINMUX_DATA(CTX0_CTX1_MARK, PC8MD_100), PINMUX_DATA(PC7_DATA, PC7MD_000), PINMUX_DATA(CKE_MARK, PC7MD_001), @@ -836,11 +836,12 @@ static const u16 pinmux_data[] = { PINMUX_DATA(CAS_MARK, PC6MD_001), PINMUX_DATA(SCK7_MARK, PC6MD_010), PINMUX_DATA(CTX0_MARK, PC6MD_011), + PINMUX_DATA(CTX0_CTX1_CTX2_MARK, PC6MD_100), PINMUX_DATA(PC5_DATA, PC5MD_000), PINMUX_DATA(RAS_MARK, PC5MD_001), PINMUX_DATA(CRX0_MARK, PC5MD_011), - PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100), + PINMUX_DATA(CTX0_CTX1_CTX2_MARK, PC5MD_100), PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101), PINMUX_DATA(PC4_DATA, PC4MD_00), @@ -1292,30 +1293,32 @@ static const u16 pinmux_data[] = { PINMUX_DATA(LCD_DATA23_PJ23_MARK, PJ23MD_010), PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011), PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100), - PINMUX_DATA(CTX1_MARK, PJ23MD_101), + PINMUX_DATA(CTX1_PJ23_MARK, PJ23MD_101), + PINMUX_DATA(CTX0_CTX1_PJ23_MARK, PJ23MD_110), PINMUX_DATA(PJ22_DATA, PJ22MD_000), PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001), PINMUX_DATA(LCD_DATA22_PJ22_MARK, PJ22MD_010), PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011), PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100), - PINMUX_DATA(CRX1_MARK, PJ22MD_101), - PINMUX_DATA(CRX0_CRX1_MARK, PJ22MD_110), + PINMUX_DATA(CRX1_PJ22_MARK, PJ22MD_101), + PINMUX_DATA(CRX0_CRX1_PJ22_MARK, PJ22MD_110), PINMUX_DATA(PJ21_DATA, PJ21MD_000), PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001), PINMUX_DATA(LCD_DATA21_PJ21_MARK, PJ21MD_010), PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011), PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100), - PINMUX_DATA(CTX2_MARK, PJ21MD_101), + PINMUX_DATA(CTX2_PJ21_MARK, PJ21MD_101), + PINMUX_DATA(CTX0_CTX1_CTX2_PJ21_MARK, PJ21MD_110), PINMUX_DATA(PJ20_DATA, PJ20MD_000), PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001), PINMUX_DATA(LCD_DATA20_PJ20_MARK, PJ20MD_010), PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011), PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100), - PINMUX_DATA(CRX2_MARK, PJ20MD_101), - PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110), + PINMUX_DATA(CRX2_PJ20_MARK, PJ20MD_101), + PINMUX_DATA(CRX0_CRX1_CRX2_PJ20_MARK, PJ20MD_110), PINMUX_DATA(PJ19_DATA, PJ19MD_000), PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001), @@ -1666,12 +1669,24 @@ static const struct pinmux_func pinmux_func_gpios[] = { GPIO_FN(WDTOVF), /* CAN */ + GPIO_FN(CTX2), + GPIO_FN(CRX2), GPIO_FN(CTX1), GPIO_FN(CRX1), GPIO_FN(CTX0), GPIO_FN(CRX0), + GPIO_FN(CTX0_CTX1), GPIO_FN(CRX0_CRX1), + GPIO_FN(CTX0_CTX1_CTX2), GPIO_FN(CRX0_CRX1_CRX2), + GPIO_FN(CTX2_PJ21), + GPIO_FN(CRX2_PJ20), + GPIO_FN(CTX1_PJ23), + GPIO_FN(CRX1_PJ22), + GPIO_FN(CTX0_CTX1_PJ23), + GPIO_FN(CRX0_CRX1_PJ22), + GPIO_FN(CTX0_CTX1_CTX2_PJ21), + GPIO_FN(CRX0_CRX1_CRX2_PJ20), /* DMAC */ GPIO_FN(TEND0), diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index e77734e1b476193c8c493249a52e736a83b841a7..cd4effbea361eb7a3506cd01a336537f5cb8f5da 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -406,7 +406,6 @@ struct ep_pcie_dev_t { bool config_mmio_init; bool enumerated; enum ep_pcie_link_status link_status; - bool perst_deast; bool power_on; bool suspending; bool l23_ready; @@ -414,6 +413,8 @@ struct ep_pcie_dev_t { struct ep_pcie_msi_config msi_cfg; bool no_notify; bool client_ready; + atomic_t ep_pcie_dev_wake; + atomic_t perst_deast; struct ep_pcie_register_event *event_reg; struct work_struct handle_perst_work; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index d3c79d7a291235bb0547da2c40353b2bf132da89..62d40d9fe81f432ee651bc1418393a03a9ba5298 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -1805,7 +1805,7 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) ret = EP_PCIE_ERROR; goto link_fail; } else { - dev->perst_deast = true; + atomic_set(&dev->perst_deast, 1); if (opt & EP_PCIE_OPT_AST_WAKE) { /* deassert PCIe WAKE# */ EP_PCIE_DBG(dev, @@ -1971,11 +1971,19 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) int ep_pcie_core_disable_endpoint(void) { int rc = 0; + u32 val = 0; + unsigned long irqsave_flags; struct ep_pcie_dev_t *dev = &ep_pcie_dev; EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); mutex_lock(&dev->setup_mtx); + if (atomic_read(&dev->perst_deast)) { + EP_PCIE_DBG(dev, + "PCIe V%d: PERST is de-asserted, exiting disable\n", + dev->rev); + goto out; + } if (!dev->power_on) { EP_PCIE_DBG(dev, @@ -1992,9 +2000,25 @@ int ep_pcie_core_disable_endpoint(void) dev->rev); } + val = readl_relaxed(dev->elbi + PCIE20_ELBI_SYS_STTS); + EP_PCIE_DBG(dev, "PCIe V%d: LTSSM_STATE during disable:0x%x\n", + dev->rev, (val >> 0xC) & 0x3f); ep_pcie_pipe_clk_deinit(dev); ep_pcie_clk_deinit(dev); ep_pcie_vreg_deinit(dev); + + spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + if (atomic_read(&dev->ep_pcie_dev_wake) && + !atomic_read(&dev->perst_deast)) { + EP_PCIE_DBG(dev, "PCIe V%d: Released wakelock\n", dev->rev); + atomic_set(&dev->ep_pcie_dev_wake, 0); + pm_relax(&dev->pdev->dev); + } else { + EP_PCIE_DBG(dev, "PCIe V%d: Bail, Perst-assert:%d wake:%d\n", + dev->rev, atomic_read(&dev->perst_deast), + atomic_read(&dev->ep_pcie_dev_wake)); + } + spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); out: mutex_unlock(&dev->setup_mtx); return rc; @@ -2251,12 +2275,25 @@ static void handle_d3cold_func(struct work_struct *work) { struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t, handle_d3cold_work); + unsigned long irqsave_flags; EP_PCIE_DBG(dev, "PCIe V%d: shutdown PCIe link due to PERST assertion before BME is set\n", dev->rev); ep_pcie_core_disable_endpoint(); dev->no_notify = false; + spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + if (atomic_read(&dev->ep_pcie_dev_wake) && + !atomic_read(&dev->perst_deast)) { + atomic_set(&dev->ep_pcie_dev_wake, 0); + pm_relax(&dev->pdev->dev); + EP_PCIE_DBG(dev, "PCIe V%d: Released wakelock\n", dev->rev); + } else { + EP_PCIE_DBG(dev, "PCIe V%d: Bail, Perst-assert:%d wake:%d\n", + dev->rev, atomic_read(&dev->perst_deast), + atomic_read(&dev->ep_pcie_dev_wake)); + } + spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); } static void handle_bme_func(struct work_struct *work) @@ -2294,14 +2331,24 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) } if (perst) { - dev->perst_deast = true; + atomic_set(&dev->perst_deast, 1); dev->perst_deast_counter++; + /* + * Hold a wakelock to avoid missing BME and other + * interrupts if apps goes into suspend before BME is set. + */ + if (!atomic_read(&dev->ep_pcie_dev_wake)) { + pm_stay_awake(&dev->pdev->dev); + atomic_set(&dev->ep_pcie_dev_wake, 1); + EP_PCIE_DBG(dev, "PCIe V%d: Acquired wakelock\n", + dev->rev); + } EP_PCIE_DBG(dev, "PCIe V%d: No. %ld PERST deassertion\n", dev->rev, dev->perst_deast_counter); ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST); } else { - dev->perst_deast = false; + atomic_set(&dev->perst_deast, 0); dev->perst_ast_counter++; EP_PCIE_DBG(dev, "PCIe V%d: No. %ld PERST assertion\n", @@ -2552,13 +2599,15 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev) * based on the next expected level of the gpio */ if (gpio_get_value(dev->gpio[EP_PCIE_GPIO_PERST].num) == 1) - dev->perst_deast = true; + atomic_set(&dev->perst_deast, 1); /* register handler for PERST interrupt */ perst_irq = gpio_to_irq(dev->gpio[EP_PCIE_GPIO_PERST].num); ret = devm_request_irq(pdev, perst_irq, ep_pcie_handle_perst_irq, - (dev->perst_deast ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH), + ((atomic_read(&dev->perst_deast) ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) + | IRQF_EARLY_RESUME), "ep_pcie_perst", dev); if (ret) { EP_PCIE_ERR(dev, @@ -2952,7 +3001,7 @@ static int ep_pcie_core_wakeup_host(enum ep_pcie_event event) if (event == EP_PCIE_EVENT_PM_D3_HOT) ep_pcie_core_issue_inband_pme(); - if (dev->perst_deast && !dev->l23_ready) { + if (atomic_read(&dev->perst_deast) && !dev->l23_ready) { EP_PCIE_ERR(dev, "PCIe V%d: request to assert WAKE# when PERST is de-asserted and D3hot is not received\n", dev->rev); @@ -2963,7 +3012,7 @@ static int ep_pcie_core_wakeup_host(enum ep_pcie_event event) EP_PCIE_DBG(dev, "PCIe V%d: No. %ld to assert PCIe WAKE#; perst is %s de-asserted; D3hot is %s received\n", dev->rev, dev->wake_counter, - dev->perst_deast ? "" : "not", + atomic_read(&dev->perst_deast) ? "" : "not", dev->l23_ready ? "" : "not"); /* * Assert WAKE# GPIO until link is back to L0. @@ -3218,6 +3267,14 @@ static int ep_pcie_probe(struct platform_device *pdev) goto irq_failure; } + /* + * Wakelock is needed to avoid missing BME and other + * interrupts if apps goes into suspend before host + * sets them. + */ + device_init_wakeup(&ep_pcie_dev.pdev->dev, true); + atomic_set(&ep_pcie_dev.ep_pcie_dev_wake, 0); + if (ep_pcie_dev.perst_enum && !gpio_get_value(ep_pcie_dev.gpio[EP_PCIE_GPIO_PERST].num)) { EP_PCIE_DBG2(&ep_pcie_dev, diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 0626b7f3234f7ace3f626037c2dfa2633863859c..c62aebc8ef0ae92fdd067922928636a49f8e3127 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -3844,17 +3844,19 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) return -GSI_STATUS_UNSUPPORTED_OP; } + spin_lock_irqsave(&gsi_ctx->slock, flags); + if (atomic_read(&ctx->poll_mode)) curr = GSI_CHAN_MODE_POLL; else curr = GSI_CHAN_MODE_CALLBACK; if (mode == curr) { - GSIDBG("already in requested mode %u chan_hdl=%lu\n", + GSIERR("already in requested mode %u chan_hdl=%lu\n", curr, chan_hdl); + spin_unlock_irqrestore(&gsi_ctx->slock, flags); return -GSI_STATUS_UNSUPPORTED_OP; } - spin_lock_irqsave(&gsi_ctx->slock, flags); if (curr == GSI_CHAN_MODE_CALLBACK && mode == GSI_CHAN_MODE_POLL) { __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0); diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 755910c02582099e2e3504ecd3a461d87bac9d90..3dc6baaf5cd677b88234649f64951764c750e342 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -224,6 +224,8 @@ const char *ipa_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_MHI_LOW_LAT_CONS), __stringify(IPA_CLIENT_QDSS_PROD), __stringify(IPA_CLIENT_MHI_QDSS_CONS), + __stringify(IPA_CLIENT_ETHERNET2_PROD), + __stringify(IPA_CLIENT_ETHERNET2_CONS), }; /** @@ -381,7 +383,7 @@ int ipa_smmu_store_sgt(struct sg_table **out_ch_ptr, } memcpy((*out_ch_ptr)->sgl, in_sgt_ptr->sgl, - nents*sizeof((*out_ch_ptr)->sgl)); + nents*sizeof(struct scatterlist)); (*out_ch_ptr)->nents = nents; (*out_ch_ptr)->orig_nents = in_sgt_ptr->orig_nents; } diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 7090b63f4cc35bc19b3036180c62c4e6c33119e1..67ed1fd76347db70538017cd5e5ede3454a0e6b3 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -540,20 +540,16 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp, goto fail; } - if (ntn_ctx->conn.dl.smmu_enabled) { - result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.dl, - &inp->dl); - if (result) { - IPA_UC_OFFLOAD_ERR("alloc failure on TX\n"); - goto fail; - } - result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.ul, - &inp->ul); - if (result) { - ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.dl); - IPA_UC_OFFLOAD_ERR("alloc failure on RX\n"); - goto fail; - } + result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.dl, &inp->dl); + if (result) { + IPA_UC_OFFLOAD_ERR("alloc failure on TX\n"); + goto fail; + } + result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.ul, &inp->ul); + if (result) { + ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.dl); + IPA_UC_OFFLOAD_ERR("alloc failure on RX\n"); + goto fail; } fail: diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c index 22d75d4b579f7fcb03ef8ac42f759016a1cbf1fc..8fe69d3bbee5752f640d72a25bc8273f705a8568 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c @@ -143,6 +143,8 @@ int ipa_wdi_cleanup(void) struct ipa_wdi_intf_info *entry; struct ipa_wdi_intf_info *next; + ipa_uc_dereg_rdyCB(); + /* clear interface list */ list_for_each_entry_safe(entry, next, &ipa_wdi_ctx->head_intf_list, link) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c index 8a64c5a6e7b1d120accdcbefcf02f4c5f52fc0d5..71c7c6ffbad7a75c56a859a3006bd31fa73076cd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c @@ -571,9 +571,10 @@ static int ipa_eth_pm_notifier_event_suspend_prepare( * and reverts the device suspension by aborting the system suspend. */ if (ipa_eth_net_check_active(eth_dev)) { - pr_info("%s: %s is active, preventing suspend for some time", - IPA_ETH_SUBSYS, eth_dev->net_dev->name); - ipa_eth_dev_wakeup_event(eth_dev); + pr_info("%s: %s is active, preventing suspend for %u ms", + IPA_ETH_SUBSYS, eth_dev->net_dev->name, + IPA_ETH_WAKE_TIME_MS); + pm_wakeup_dev_event(eth_dev->dev, IPA_ETH_WAKE_TIME_MS, false); return NOTIFY_BAD; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h index f92da41cd7aa1b7f024d3037e380c6f631b3c842..2ffc31c27da73fc57bfb06d15b0111142d3fbb47 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h @@ -35,8 +35,12 @@ #define IPA_ETH_IPC_LOGDBG_DEFAULT false #endif +/* Time to remain awake after a suspend abort due to NIC activity */ #define IPA_ETH_WAKE_TIME_MS 500 +/* Time for NIC HW to settle down (ex. receive link interrupt) after a resume */ +#define IPA_ETH_RESUME_SETTLE_MS 2000 + #define IPA_ETH_PFDEV (ipa3_ctx ? ipa3_ctx->pdev : NULL) #define IPA_ETH_SUBSYS "ipa_eth" @@ -161,9 +165,31 @@ extern bool ipa_eth_ipc_logdbg; bool ipa_eth_is_ready(void); bool ipa_eth_all_ready(void); -static inline void ipa_eth_dev_wakeup_event(struct ipa_eth_device *eth_dev) +static inline void ipa_eth_dev_assume_active_ms( + struct ipa_eth_device *eth_dev, + unsigned int msec) +{ + eth_dev_priv(eth_dev)->assume_active += + DIV_ROUND_UP(msec, IPA_ETH_WAKE_TIME_MS); + pm_system_wakeup(); +} + +static inline void ipa_eth_dev_assume_active_inc( + struct ipa_eth_device *eth_dev, + unsigned int count) +{ + eth_dev_priv(eth_dev)->assume_active += count; + pm_system_wakeup(); +} + +static inline void ipa_eth_dev_assume_active_dec( + struct ipa_eth_device *eth_dev, + unsigned int count) { - pm_wakeup_dev_event(eth_dev->dev, IPA_ETH_WAKE_TIME_MS, false); + if (eth_dev_priv(eth_dev)->assume_active > count) + eth_dev_priv(eth_dev)->assume_active -= count; + else + eth_dev_priv(eth_dev)->assume_active = 0; } struct ipa_eth_device *ipa_eth_alloc_device( diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c index 1095306b009fc960b9f105fcc418276f92b0f254..80f4a80b71812924394123c84f9d9747b7d77175 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c @@ -374,7 +374,7 @@ static int ipa_eth_pci_suspend_late_handler(struct device *dev) IPA_ETH_SUBSYS, eth_dev->net_dev->name); /* Have PM_SUSPEND_PREPARE give us one wakeup time quanta */ - eth_dev_priv(eth_dev)->assume_active++; + ipa_eth_dev_assume_active_inc(eth_dev, 1); return -EAGAIN; } @@ -428,8 +428,8 @@ static int ipa_eth_pci_resume_handler(struct device *dev) "Device resume delegated to net driver"); rc = eth_dev_pm_ops(eth_dev)->resume(dev); - /* Give some time after a resume for the device to settle */ - eth_dev_priv(eth_dev)->assume_active++; + /* Give some time for device to settle after a resume */ + ipa_eth_dev_assume_active_ms(eth_dev, IPA_ETH_RESUME_SETTLE_MS); } if (rc) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index a1191427c30cf02c79c81ef85bd95ed2955a6e0c..8e930ef0ce0e0593f75a04a1a92a80fbdafa21df 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -862,6 +862,74 @@ static void ipa3_get_pcie_ep_info( } } +static void ipa3_get_eth_ep_info( + struct ipa_ioc_get_ep_info *ep_info, + struct ipa_ep_pair_info *pair_info + ) +{ + int ep_index = -1, i; + + ep_info->num_ep_pairs = 0; + for (i = 0; i < ep_info->max_ep_pairs; i++) { + pair_info[i].consumer_pipe_num = -1; + pair_info[i].producer_pipe_num = -1; + pair_info[i].ep_id = -1; + } + + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_ETHERNET2_PROD); + + if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) { + pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index; + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_ETHERNET2_CONS); + if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) { + pair_info[ep_info->num_ep_pairs].producer_pipe_num = + ep_index; + pair_info[ep_info->num_ep_pairs].ep_id = + IPA_ETH1_EP_ID; + + IPADBG("ep_pair_info consumer_pipe_num %d", + pair_info[ep_info->num_ep_pairs].consumer_pipe_num); + IPADBG(" producer_pipe_num %d ep_id %d\n", + pair_info[ep_info->num_ep_pairs].producer_pipe_num, + pair_info[ep_info->num_ep_pairs].ep_id); + ep_info->num_ep_pairs++; + } else { + pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1; + IPADBG("ep_pair_info consumer_pipe_num %d", + pair_info[ep_info->num_ep_pairs].consumer_pipe_num); + IPADBG(" producer_pipe_num %d ep_id %d\n", + pair_info[ep_info->num_ep_pairs].producer_pipe_num, + pair_info[ep_info->num_ep_pairs].ep_id); + } + } + + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_ETHERNET_PROD); + + if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) { + pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index; + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_ETHERNET_CONS); + if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) { + pair_info[ep_info->num_ep_pairs].producer_pipe_num = + ep_index; + pair_info[ep_info->num_ep_pairs].ep_id = + IPA_ETH0_EP_ID; + + IPADBG("ep_pair_info consumer_pipe_num %d", + pair_info[ep_info->num_ep_pairs].consumer_pipe_num); + IPADBG(" producer_pipe_num %d ep_id %d\n", + pair_info[ep_info->num_ep_pairs].producer_pipe_num, + pair_info[ep_info->num_ep_pairs].ep_id); + ep_info->num_ep_pairs++; + } else { + pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1; + IPADBG("ep_pair_info consumer_pipe_num %d", + pair_info[ep_info->num_ep_pairs].consumer_pipe_num); + IPADBG(" producer_pipe_num %d ep_id %d\n", + pair_info[ep_info->num_ep_pairs].producer_pipe_num, + pair_info[ep_info->num_ep_pairs].ep_id); + } + } +} static int ipa3_get_ep_info(struct ipa_ioc_get_ep_info *ep_info, u8 *param) @@ -878,6 +946,10 @@ static int ipa3_get_ep_info(struct ipa_ioc_get_ep_info *ep_info, ipa3_get_pcie_ep_info(ep_info, pair_info); break; + case IPA_DATA_EP_TYP_ETH: + ipa3_get_eth_ep_info(ep_info, pair_info); + break; + default: IPAERR_RL("Undefined ep_type %d\n", ep_info->ep_type); ret = -EFAULT; @@ -1003,6 +1075,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_get_vlan_mode vlan_mode; struct ipa_ioc_wigig_fst_switch fst_switch; struct ipa_nat_in_sram_info nat_in_sram_info; + union ipa_ioc_uc_activation_entry uc_act; size_t sz; int pre_entry; int hdl; @@ -3052,6 +3125,39 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; + case IPA_IOC_ADD_UC_ACT_ENTRY: + if (copy_from_user(&uc_act, (const void __user *)arg, + sizeof(union ipa_ioc_uc_activation_entry))) { + IPAERR_RL("copy_from_user fails\n"); + retval = -EFAULT; + break; + } + + /* first field in both structs is cmd id */ + if (uc_act.socks.cmd_id == IPA_SOCKSV5_ADD_COM_ID) { + retval = ipa3_add_socksv5_conn_usr(&uc_act.socks); + } else { + retval = ipa3_add_ipv6_nat_uc_activation_entry( + &uc_act.ipv6_nat); + } + if (retval) { + retval = -EFAULT; + break; + } + if (copy_to_user((void __user *)arg, &uc_act, + sizeof(union ipa_ioc_uc_activation_entry))) { + IPAERR_RL("copy_to_user fails\n"); + retval = -EFAULT; + break; + } + break; + case IPA_IOC_DEL_UC_ACT_ENTRY: + if (ipa3_del_uc_act_entry((uint16_t)arg)) { + retval = -EFAULT; + break; + } + break; + default: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return -ENOTTY; @@ -6597,6 +6703,9 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf, /* Check MHI configuration on MDM devices */ if (!ipa3_is_msm_device()) { + /* reset ecm default as non-vlan mode */ + if (!ipa3_ctx->vlan_mode_set && ipa3_ctx->ipa_config_is_auto) + ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] = false; if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) { if (strnstr(dbg_buff, "eth", strlen(dbg_buff))) @@ -6613,6 +6722,13 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf, * when vlan mode is passed to our dev we expect * another write */ + ipa3_ctx->vlan_mode_set = true; + IPAERR("emac vlan(%d)\n", + ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC]); + IPAERR("rndis vlan(%d)\n", + ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS]); + IPAERR("ecm vlan(%d)\n", + ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM]); return count; } @@ -7356,6 +7472,10 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, mutex_init(&ipa3_ctx->app_clock_vote.mutex); + /* put ecm default as vlan mode */ + if (ipa3_ctx->ipa_config_is_auto) + ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] = true; + return 0; fail_cdev_add: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 96ef459437cd9273c5377f20e487e1c5a38906a0..1f7ab697f918faaf1a9be1b29a82475f7f92374e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -433,14 +433,33 @@ int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt, } } } else { - res = iommu_unmap(smmu_domain, - rounddown(iova, PAGE_SIZE), - roundup(size + iova - rounddown(iova, PAGE_SIZE), - PAGE_SIZE)); - if (res != roundup(size + iova - rounddown(iova, PAGE_SIZE), - PAGE_SIZE)) { - IPAERR("Fail to unmap 0x%llx\n", iova); - return -EINVAL; + if (sgt != NULL) { + va = rounddown(iova, PAGE_SIZE); + len = 0; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + len = PAGE_ALIGN(sg->offset + sg->length); + res = iommu_unmap(smmu_domain, va, + roundup(len, PAGE_SIZE)); + if (res != + roundup(len, PAGE_SIZE)) { + IPAERR("Fail to unmap iova=%llx\n", + iova); + return -EINVAL; + } + va += len; + count++; + } + } else { + res = iommu_unmap(smmu_domain, + rounddown(iova, PAGE_SIZE), + roundup(size + iova - + rounddown(iova, PAGE_SIZE), + PAGE_SIZE)); + if (res != roundup(size + iova - + rounddown(iova, PAGE_SIZE), PAGE_SIZE)) { + IPAERR("Fail to unmap 0x%llx\n", iova); + return -EINVAL; + } } } IPADBG("Peer buff %s 0x%llx\n", map ? "map" : "unmap", iova); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 09856c4403dda46e6a1c1715c6fe34fbe4fe36be..bfcaae8c6fad3602af01ce92c26c7ef9be43b892 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -110,6 +110,7 @@ const char *ipa3_hdr_proc_type_name[] = { __stringify(IPA_HDR_PROC_ETHII_TO_ETHII_EX), __stringify(IPA_HDR_PROC_L2TP_UDP_HEADER_ADD), __stringify(IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE), + __stringify(IPA_HDR_PROC_SET_DSCP), }; static struct dentry *dent; @@ -323,7 +324,7 @@ static ssize_t ipa3_read_ep_reg(struct file *file, char __user *ubuf, *ppos = pos; ret = simple_read_from_buffer(ubuf, count, ppos, dbg_buff, - nbytes); + nbytes); if (ret < 0) { IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return ret; @@ -502,12 +503,12 @@ static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib, if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) { pr_err("src_port_range:%u %u ", attrib->src_port_lo, - attrib->src_port_hi); + attrib->src_port_hi); } if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) { pr_err("dst_port_range:%u %u ", attrib->dst_port_lo, - attrib->dst_port_hi); + attrib->dst_port_hi); } if (attrib->attrib_mask & IPA_FLT_TYPE) pr_err("type:%d ", attrib->type); @@ -2645,6 +2646,125 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, return count; } +static ssize_t ipa3_read_uc_act_tbl(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos) +{ + int nbytes; + int cnt = 0; + int i; + struct ipa_ipv6_nat_uc_tmpl *uc_entry_nat; + struct ipa_socksv5_uc_tmpl *uc_entry_socks; + struct iphdr_rsv *socks_iphdr; + struct ipv6hdr *socks_ipv6hdr; + + /* IPA version check */ + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "This feature only support on IPA4.5+\n"); + cnt += nbytes; + goto done; + } + + if (!ipa3_ctx->uc_act_tbl_valid) { + IPAERR("uC act tbl wasn't allocated\n"); + return -ENOENT; + } + + if (sizeof(dbg_buff) < count + 1) + return -EFAULT; + + dbg_buff[count] = '\0'; + + mutex_lock(&ipa3_ctx->act_tbl_lock); + + uc_entry_nat = (struct ipa_ipv6_nat_uc_tmpl *) + (ipa3_ctx->uc_act_tbl.base); + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "uc_act_tbl_total %d, uc_act_tbl_ipv6_nat_total %d uc_act_tbl_socksv5_total %d, uc_act_tbl_next_index %d\n" + "uC activation entries:" + , ipa3_ctx->uc_act_tbl_total, + ipa3_ctx->uc_act_tbl_ipv6_nat_total, + ipa3_ctx->uc_act_tbl_socksv5_total, + ipa3_ctx->uc_act_tbl_next_index); + cnt += nbytes; + for (i = 0; i < IPA_UC_ACT_TBL_SIZE; i++) { + if (uc_entry_nat[i].cmd_id == IPA_IPv6_NAT_COM_ID) { + nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, + "\nentry %d:\n" + "cmd_id = IPV6_NAT\n" + "private_address_msb 0x%llX\n" + "private_address_lsb 0x%llX\n" + "private_port %u\n" + "public_address_msb 0x%llX\n" + "public_address_lsb 0x%llX\n" + "public_port %u\n", + i, + uc_entry_nat[i].private_address_msb, + uc_entry_nat[i].private_address_lsb, + uc_entry_nat[i].private_port, + uc_entry_nat[i].public_address_msb, + uc_entry_nat[i].public_address_lsb, + uc_entry_nat[i].public_port); + cnt += nbytes; + } else if (uc_entry_nat[i].cmd_id == IPA_SOCKSV5_ADD_COM_ID) { + uc_entry_socks = (struct ipa_socksv5_uc_tmpl *) + (uc_entry_nat); + nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, + "\nentry %d:\n" + "cmd_id = SOCKSv5\n" + "cmd_param: %u\n" + "source_port: %u\n" + "dest_port: %u\n" + "ipa_socksv5_mask: %x\n", + i, + uc_entry_socks[i].cmd_param, + uc_entry_socks[i].src_port, + uc_entry_socks[i].dst_port, + uc_entry_socks[i].ipa_sockv5_mask); + cnt += nbytes; + + if (uc_entry_socks[i].cmd_param == + IPA_SOCKsv5_ADD_V6_V4_COM_PM) { + socks_iphdr = + &uc_entry_socks[i].ip_hdr.ipv4_rsv; + nbytes = scnprintf(dbg_buff + cnt, + IPA_MAX_MSG_LEN, + "ipv4_src_addr: 0x%X\n" + "ipv4_dst_addr: 0x%X\n", + socks_iphdr->ipv4_temp.saddr, + socks_iphdr->ipv4_temp.daddr); + cnt += nbytes; + } else { + socks_ipv6hdr = + &uc_entry_socks[i].ip_hdr.ipv6_temp; + nbytes = scnprintf(dbg_buff + cnt, + IPA_MAX_MSG_LEN, + "ipv6_src_addr[0]: 0x%X\n" + "ipv6_src_addr[1]: 0x%X\n" + "ipv6_src_addr[2]: 0x%X\n" + "ipv6_src_addr[3]: 0x%X\n" + "ipv6_dts_addr[0]: 0x%X\n" + "ipv6_dts_addr[1]: 0x%X\n" + "ipv6_dts_addr[2]: 0x%X\n" + "ipv6_dts_addr[3]: 0x%X\n", + socks_ipv6hdr->saddr.s6_addr32[0], + socks_ipv6hdr->saddr.s6_addr32[1], + socks_ipv6hdr->saddr.s6_addr32[2], + socks_ipv6hdr->saddr.s6_addr32[3], + socks_ipv6hdr->daddr.s6_addr32[0], + socks_ipv6hdr->daddr.s6_addr32[1], + socks_ipv6hdr->daddr.s6_addr32[2], + socks_ipv6hdr->daddr.s6_addr32[3]); + cnt += nbytes; + } + } + } + mutex_unlock(&ipa3_ctx->act_tbl_lock); +done: + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); + +} + static const struct ipa3_debugfs_file debugfs_files[] = { { "gen_reg", IPA_READ_ONLY_MODE, NULL, { @@ -2810,7 +2930,11 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_app_clk_vote, } - }, + }, { + "uc_act_table", IPA_READ_ONLY_MODE, NULL, { + .read = ipa3_read_uc_act_tbl, + } + } }; void ipa3_debugfs_pre_init(void) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 0b32a44af77742671696c4470662a7878f8db6cf..5cbb83a421c9716717b7374b1d03ea3ab1c9b510 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1795,6 +1795,7 @@ static void ipa3_wq_handle_rx(struct work_struct *work) else ipa_pm_activate_sync(sys->pm_hdl); napi_schedule(sys->napi_obj); + IPA_STATS_INC_CNT(sys->napi_sch_cnt); } else ipa3_handle_rx(sys); } @@ -4360,6 +4361,7 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys) clk_off = ipa_pm_activate(sys->pm_hdl); if (!clk_off && sys->napi_obj) { napi_schedule(sys->napi_obj); + IPA_STATS_INC_CNT(sys->napi_sch_cnt); return; } queue_work(sys->wq, &sys->work); @@ -4951,6 +4953,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight) */ if (cnt < weight && ep->sys->len > IPA_DEFAULT_SYS_YELLOW_WM) { napi_complete(ep->sys->napi_obj); + IPA_STATS_INC_CNT(ep->sys->napi_comp_cnt); ret = ipa3_rx_switch_to_intr_mode(ep->sys); if (ret == -GSI_STATUS_PENDING_IRQ && napi_reschedule(ep->sys->napi_obj)) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 16e5db011bb8643d39ee76de186cd59018f6ab9c..54d6bf0a7a3e099d68c50d3241a69a6853fc5d27 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1059,6 +1059,8 @@ struct ipa3_sys_context { struct workqueue_struct *repl_wq; struct ipa3_status_stats *status_stat; u32 pm_hdl; + unsigned int napi_sch_cnt; + unsigned int napi_comp_cnt; /* ordering is important - other immutable fields go below */ }; @@ -1986,6 +1988,7 @@ struct ipa3_context { int num_ipa_cne_evt_req; struct mutex ipa_cne_evt_lock; bool use_ipa_pm; + bool vlan_mode_set; bool vlan_mode_iface[IPA_VLAN_IF_MAX]; bool wdi_over_pcie; u32 entire_ipa_block_size; @@ -2019,6 +2022,8 @@ struct ipa3_context { bool uc_act_tbl_valid; struct mutex act_tbl_lock; int uc_act_tbl_total; + int uc_act_tbl_socksv5_total; + int uc_act_tbl_ipv6_nat_total; int uc_act_tbl_next_index; bool manual_fw_load; }; @@ -2416,6 +2421,15 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info); int ipa3_del_socksv5_conn(uint32_t handle); +int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl); + +int ipa3_add_ipv6_nat_uc_activation_entry( + struct ipa_ioc_ipv6_nat_uc_act_entry *entry); + +int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index); + +int ipa3_del_uc_act_entry(uint16_t index); + /* * Header removal / addition */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c index 384a065209118c6e2c1191551d2ac19877790771..c0a0d1150060d8d4808234165bd4cc082931f478 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c @@ -627,7 +627,9 @@ static long ipa_adpl_ioctl(struct file *filp, switch (cmd) { case IPA_IOC_ODL_GET_AGG_BYTE_LIMIT: odl_pipe_info.agg_byte_limit = - ipa3_odl_ctx->odl_sys_param.ipa_ep_cfg.aggr.aggr_byte_limit; + /*Modem expecting value in bytes. so passing 15 = 15*1024*/ + (ipa3_odl_ctx->odl_sys_param.ipa_ep_cfg.aggr.aggr_byte_limit * + 1024); if (copy_to_user((void __user *)arg, &odl_pipe_info, sizeof(odl_pipe_info))) { retval = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h index 2aedda4d6b28c9028d04883d65587407c061c3ed..c8fb2df487c00bb6a1ea52461831ed1ae76b6dd3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h @@ -13,7 +13,7 @@ #ifndef _IPA3_ODL_H_ #define _IPA3_ODL_H_ -#define IPA_ODL_AGGR_BYTE_LIMIT (15 * 1024) +#define IPA_ODL_AGGR_BYTE_LIMIT 15 #define IPA_ODL_RX_RING_SIZE 192 #define MAX_QUEUE_TO_ODL 1024 #define CONFIG_SUCCESS 1 diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 1f6d6eb070ddd6452e5a84d94cef0fe0414cedcd..2027f303a037855df0163268473b0550acf46c53 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -86,14 +86,16 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip, if (entry->hdr) { hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); - if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->hdr)) { IPAERR_RL("Header entry already deleted\n"); return -EPERM; } } else if (entry->proc_ctx) { hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); if (!hdr_proc_entry || - hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + (hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->proc_ctx)) { IPAERR_RL("Proc header entry already deleted\n"); return -EPERM; } @@ -1768,18 +1770,19 @@ int __ipa3_del_rt_rule(u32 rule_hdl) hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { IPAERR_RL("Header entry already deleted\n"); - return -EINVAL; + entry->hdr = NULL; } } else if (entry->proc_ctx) { hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); if (!hdr_proc_entry || hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { IPAERR_RL("Proc header entry already deleted\n"); - return -EINVAL; + entry->proc_ctx = NULL; } } - if (entry->hdr) + if (entry->hdr && + (!ipa3_check_idr_if_freed(entry->hdr))) __ipa3_release_hdr(entry->hdr->id); else if (entry->proc_ctx && (!ipa3_check_idr_if_freed(entry->proc_ctx))) @@ -1956,7 +1959,6 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) if (!user_only || rule->ipacm_installed) { - list_del(&rule->link); if (rule->hdr) { hdr_entry = ipa3_id_find( rule->rule.hdr_hdl); @@ -1964,8 +1966,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) hdr_entry->cookie != IPA_HDR_COOKIE) { IPAERR_RL( "Header already deleted\n"); - mutex_unlock(&ipa3_ctx->lock); - return -EINVAL; + rule->hdr = NULL; } } else if (rule->proc_ctx) { hdr_proc_entry = @@ -1976,12 +1977,13 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) IPA_PROC_HDR_COOKIE) { IPAERR_RL( "Proc entry already deleted\n"); - mutex_unlock(&ipa3_ctx->lock); - return -EINVAL; + rule->proc_ctx = NULL; } } tbl->rule_cnt--; - if (rule->hdr) + list_del(&rule->link); + if (rule->hdr && + (!ipa3_check_idr_if_freed(rule->hdr))) __ipa3_release_hdr(rule->hdr->id); else if (rule->proc_ctx && (!ipa3_check_idr_if_freed( @@ -2158,20 +2160,8 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule) struct ipa3_hdr_entry *hdr_entry; struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; - if (rtrule->rule.hdr_hdl) { - hdr = ipa3_id_find(rtrule->rule.hdr_hdl); - if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid hdr\n"); - goto error; - } - } else if (rtrule->rule.hdr_proc_ctx_hdl) { - proc_ctx = ipa3_id_find(rtrule->rule.hdr_proc_ctx_hdl); - if ((proc_ctx == NULL) || - (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid proc ctx\n"); - goto error; - } - } + if (__ipa_rt_validate_hndls(&rtrule->rule, &hdr, &proc_ctx)) + goto error; entry = ipa3_id_find(rtrule->rt_rule_hdl); if (entry == NULL) { @@ -2194,14 +2184,16 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule) if (entry->hdr) { hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); - if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->hdr)) { IPAERR_RL("Header entry already deleted\n"); return -EPERM; } } else if (entry->proc_ctx) { hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); if (!hdr_proc_entry || - hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + (hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->proc_ctx)) { IPAERR_RL("Proc header entry already deleted\n"); return -EPERM; } @@ -2209,7 +2201,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule) if (entry->hdr) entry->hdr->ref_cnt--; - if (entry->proc_ctx) + else if (entry->proc_ctx) entry->proc_ctx->ref_cnt--; entry->rule = rtrule->rule; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c index e3be643c3d0c057d7332ed1a91ea34c3e8603086..601ee86cea127b14eb207cfb3d20b4be2ac43383 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c @@ -606,7 +606,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the DL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false, true); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false, false); if (result) { IPAERR("failed to unmap SMMU for DL %d\n", result); goto fail; @@ -627,7 +627,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the UL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false, true); if (result) { IPAERR("failed to unmap SMMU for UL %d\n", result); goto fail; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 668311add95f0c8df7e330adafaa74ce025c9840..c88eb4f64c195f9cd1356edd424b362163a00aef 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -2005,6 +2005,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 9, 0, 8, 16, IPA_EE_UC } }, + [IPA_4_1_APQ][IPA_CLIENT_WLAN2_PROD] = { + true, IPA_v4_0_GROUP_UL_DL, + true, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, + QMB_MASTER_SELECT_DDR, + { 7, 9, 8, 16, IPA_EE_AP } }, /* Only for test purpose */ [IPA_4_1_APQ][IPA_CLIENT_TEST_PROD] = { true, IPA_v4_0_GROUP_UL_DL, @@ -2061,6 +2067,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 22, 1, 9, 9, IPA_EE_UC } }, + [IPA_4_1_APQ][IPA_CLIENT_WLAN2_CONS] = { + true, IPA_v4_0_GROUP_UL_DL, + false, + IPA_DPS_HPS_SEQ_TYPE_INVALID, + QMB_MASTER_SELECT_DDR, + { 17, 1, 8, 13, IPA_EE_AP } }, /* Only for test purpose */ /* MBIM aggregation test pipes should have the same QMB as USB_CONS */ [IPA_4_1_APQ][IPA_CLIENT_TEST_CONS] = { @@ -2770,6 +2782,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 12, 0, 8, 16, IPA_EE_UC, GSI_SMART_PRE_FETCH, 3 } }, + [IPA_4_5_AUTO][IPA_CLIENT_ETHERNET2_PROD] = { + true, IPA_v4_5_GROUP_CV2X, + true, + IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + QMB_MASTER_SELECT_DDR, + { 10, 13, 8, 16, IPA_EE_UC, GSI_SMART_PRE_FETCH, 3 } }, [IPA_4_5_AUTO][IPA_CLIENT_Q6_WAN_PROD] = { true, IPA_v4_5_GROUP_UL_DL, true, @@ -2887,6 +2905,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 28, 1, 9, 9, IPA_EE_UC, GSI_SMART_PRE_FETCH, 4 } }, + [IPA_4_5_AUTO][IPA_CLIENT_ETHERNET2_CONS] = { + true, IPA_v4_5_GROUP_CV2X, + false, + IPA_DPS_HPS_SEQ_TYPE_INVALID, + QMB_MASTER_SELECT_DDR, + { 25, 16, 9, 9, IPA_EE_UC, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5_AUTO][IPA_CLIENT_Q6_LAN_CONS] = { true, IPA_v4_5_GROUP_UL_DL, false, @@ -3549,18 +3573,19 @@ bool ipa3_should_pipe_be_suspended(enum ipa_client_type client) if (client == IPA_CLIENT_USB_CONS || client == IPA_CLIENT_USB2_CONS || - client == IPA_CLIENT_USB_DPL_CONS || - client == IPA_CLIENT_MHI_QDSS_CONS || - client == IPA_CLIENT_MHI_CONS || - client == IPA_CLIENT_MHI_DPL_CONS || - client == IPA_CLIENT_HSIC1_CONS || - client == IPA_CLIENT_WLAN1_CONS || - client == IPA_CLIENT_WLAN2_CONS || - client == IPA_CLIENT_WLAN3_CONS || - client == IPA_CLIENT_WLAN4_CONS || - client == IPA_CLIENT_ODU_EMB_CONS || - client == IPA_CLIENT_ODU_TETH_CONS || - client == IPA_CLIENT_ETHERNET_CONS) + client == IPA_CLIENT_USB_DPL_CONS || + client == IPA_CLIENT_MHI_QDSS_CONS || + client == IPA_CLIENT_MHI_CONS || + client == IPA_CLIENT_MHI_DPL_CONS || + client == IPA_CLIENT_HSIC1_CONS || + client == IPA_CLIENT_WLAN1_CONS || + client == IPA_CLIENT_WLAN2_CONS || + client == IPA_CLIENT_WLAN3_CONS || + client == IPA_CLIENT_WLAN4_CONS || + client == IPA_CLIENT_ODU_EMB_CONS || + client == IPA_CLIENT_ODU_TETH_CONS || + client == IPA_CLIENT_ETHERNET_CONS || + client == IPA_CLIENT_ETHERNET2_CONS) return true; return false; @@ -5719,6 +5744,7 @@ int ipa3_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) param_in->client == IPA_CLIENT_HSIC1_PROD || param_in->client == IPA_CLIENT_ODU_PROD || param_in->client == IPA_CLIENT_ETHERNET_PROD || + param_in->client == IPA_CLIENT_ETHERNET2_PROD || param_in->client == IPA_CLIENT_WIGIG_PROD || param_in->client == IPA_CLIENT_AQC_ETHERNET_PROD) { result = ipa3_cfg_ep_metadata(ipa_ep_idx, &meta); @@ -8021,6 +8047,16 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) ipa_assert(); } } else { + if (IPA_CLIENT_IS_APPS_PROD(client) || + (client == IPA_CLIENT_APPS_WAN_CONS && + coal_ep_idx != IPA_EP_NOT_ALLOCATED)) + goto chan_statrt; + if (!atomic_read(&ep->sys->curr_polling_state)) { + IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl); + gsi_config_channel_mode(ep->gsi_chan_hdl, + GSI_CHAN_MODE_CALLBACK); + } +chan_statrt: res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { IPAERR("failed to start LAN channel\n"); @@ -8047,12 +8083,7 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); if (!ipa3_gsi_channel_is_quite(ep)) return -EAGAIN; - } else if (!atomic_read(&ep->sys->curr_polling_state)) { - IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl); - gsi_config_channel_mode(ep->gsi_chan_hdl, - GSI_CHAN_MODE_CALLBACK); } - return 0; } @@ -9006,6 +9037,8 @@ int ipa3_get_prot_id(enum ipa_client_type client) case IPA_CLIENT_USB_CONS: prot_id = IPA_HW_PROTOCOL_USB; break; + case IPA_CLIENT_ETHERNET2_PROD: + case IPA_CLIENT_ETHERNET2_CONS: case IPA_CLIENT_ETHERNET_PROD: case IPA_CLIENT_ETHERNET_CONS: prot_id = IPA_HW_PROTOCOL_ETH; @@ -9133,6 +9166,213 @@ int ipa3_setup_uc_act_tbl(void) return res; } +static inline bool is_free_socksv5(struct ipa_socksv5_uc_tmpl *socksv5_entry) +{ + if ((!socksv5_entry->cmd_id) || + (socksv5_entry->cmd_id == IPA_SOCKsv5_ADD_COM_ID && + !(socksv5_entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID))) + return true; + return false; +} + +static int ipa3_get_free_uc_act_entry(void) +{ + struct ipa_socksv5_uc_tmpl *entry; + int orig_index = ipa3_ctx->uc_act_tbl_next_index; + int free_index = -1; + + IPADBG("\n"); + /* find a free spot*/ + do { + entry = ipa3_ctx->uc_act_tbl.base + + ipa3_ctx->uc_act_tbl_next_index + * sizeof(struct ipa_socksv5_uc_tmpl); + + /* check if entry is free */ + if (is_free_socksv5(entry)) { + free_index = ipa3_ctx->uc_act_tbl_next_index; + IPADBG("found free index at %d\n", free_index); + break; + } + + ipa3_ctx->uc_act_tbl_next_index++; + ipa3_ctx->uc_act_tbl_next_index %= + IPA_UC_ACT_TBL_SIZE; + } while (orig_index != ipa3_ctx->uc_act_tbl_next_index); + IPADBG("exit free_index %d\n", free_index); + return free_index; +} + +int ipa3_add_ipv6_nat_uc_activation_entry( + struct ipa_ioc_ipv6_nat_uc_act_entry *entry) +{ + int res = 0; + int index; + struct ipa_ipv6_nat_uc_tmpl *uc_entry; + + /* IPA version check */ + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + IPAERR("Not support !\n"); + return -EPERM; + } + + if (!ipa3_ctx->uc_act_tbl_valid) { + IPAERR("uC act tbl wasn't allocated\n"); + return -ENOENT; + } + + if (!entry) { + IPAERR("Null entry\n"); + return -EIO; + } + if (!entry->private_address_lsb || !entry->private_address_msb + || !entry->public_address_lsb || !entry->public_address_msb + || !entry->private_port || !entry->public_port) { + IPAERR("0 param 0x%llX 0x%llX 0x%llX 0x%llX %d %d\n", + entry->private_address_lsb, entry->private_address_msb, + entry->public_address_lsb, entry->public_address_msb, + entry->private_port, entry->public_port); + return -EFAULT; + } + + mutex_lock(&ipa3_ctx->act_tbl_lock); + /* check the left # of entries */ + if (ipa3_ctx->uc_act_tbl_total + >= IPA_UC_ACT_TBL_SIZE) { + IPAERR("uc act tbl is full!\n"); + res = -EFAULT; + goto error; + } + + index = ipa3_get_free_uc_act_entry(); + + uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); + + uc_entry->private_address_lsb = entry->private_address_lsb; + uc_entry->private_address_msb = entry->private_address_msb; + uc_entry->public_address_lsb = entry->public_address_lsb; + uc_entry->public_address_msb = entry->public_address_msb; + uc_entry->private_port = entry->private_port; + uc_entry->public_port = entry->public_port; + uc_entry->cmd_id = IPA_IPv6_NAT_COM_ID; + + /* set output index */ + entry->index = (uint16_t)index; + + ipa3_ctx->uc_act_tbl_total++; + ipa3_ctx->uc_act_tbl_ipv6_nat_total++; + + if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) { + /* + * find next free spot, this function shall update + * uc_act_tbl_next_index + */ + index = ipa3_get_free_uc_act_entry(); + + if (index < 0) { + /* set to max tbl size to debug */ + IPAERR("can't find available spot!\n"); + ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE; + res = -EFAULT; + } + } +error: + mutex_unlock(&ipa3_ctx->act_tbl_lock); + return res; +} + +int ipa3_del_uc_act_entry(uint16_t index) +{ + struct ipa_ipv6_nat_uc_tmpl *uc_entry; + uint16_t cmd_id; + + /* IPA version check */ + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + IPAERR_RL("Not support !\n"); + return -EPERM; + } + + if (!ipa3_ctx->uc_act_tbl_valid) { + IPAERR_RL("uC act tbl haven't allocated\n"); + return -ENOENT; + } + + if (index > IPA_UC_ACT_TBL_SIZE || index < 0) { + IPAERR_RL("invalid index!\n"); + return -EINVAL; + } + + if (!ipa3_ctx->uc_act_tbl_total) { + IPAERR_RL( + "invalid handle, no uc activation entries in table (total %d)\n" + , ipa3_ctx->uc_act_tbl_total); + return -EINVAL; + } + + uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); + + mutex_lock(&ipa3_ctx->act_tbl_lock); + cmd_id = uc_entry->cmd_id; + mutex_unlock(&ipa3_ctx->act_tbl_lock); + + if (cmd_id == IPA_IPv6_NAT_COM_ID) + return ipa3_del_ipv6_nat_uc_activation_entry(index); + else + return ipa3_del_socksv5_conn(index); +} + +int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index) +{ + struct ipa_ipv6_nat_uc_tmpl *uc_entry; + int res = 0; + + /* IPA version check */ + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { + IPAERR_RL("Not support !\n"); + return -EPERM; + } + + if (!ipa3_ctx->uc_act_tbl_valid) { + IPAERR_RL("uC act tbl haven't allocated\n"); + return -ENOENT; + } + + if (index > IPA_UC_ACT_TBL_SIZE || index < 0) { + IPAERR_RL("invalid index!\n"); + return -EINVAL; + } + + if (!ipa3_ctx->uc_act_tbl_ipv6_nat_total) { + IPAERR_RL( + "invalid handle, no IPv6 NAT entries in table (total %d)\n" + , ipa3_ctx->uc_act_tbl_total); + return -EINVAL; + } + + uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); + + mutex_lock(&ipa3_ctx->act_tbl_lock); + if (uc_entry->cmd_id != IPA_IPv6_NAT_COM_ID) { + IPAERR_RL("entry %d wrong cmd id %d\n", uc_entry->cmd_id); + res = -EFAULT; + goto error; + } + uc_entry->cmd_id = 0; + ipa3_ctx->uc_act_tbl_total--; + ipa3_ctx->uc_act_tbl_ipv6_nat_total--; + + IPADBG("free entry %d, nat total %d, left total %d\n", + index, + ipa3_ctx->uc_act_tbl_ipv6_nat_total, + ipa3_ctx->uc_act_tbl_total); +error: + mutex_unlock(&ipa3_ctx->act_tbl_lock); + return res; +} + static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) { if (!buff) { @@ -9150,6 +9390,39 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } +static int ipa3_get_free_socksv5_entry(void) +{ + struct ipa_socksv5_uc_tmpl *first; + struct ipa_socksv5_uc_tmpl *next; + int orig_index = ipa3_ctx->uc_act_tbl_next_index; + int free_index = -1; + + IPADBG("\n"); + /* find a free spot with two contiguous entries*/ + do { + first = ipa3_ctx->uc_act_tbl.base + + ipa3_ctx->uc_act_tbl_next_index + * sizeof(struct ipa_socksv5_uc_tmpl); + next = ipa3_ctx->uc_act_tbl.base + + (ipa3_ctx->uc_act_tbl_next_index + 1) + * sizeof(struct ipa_socksv5_uc_tmpl); + + /* check if first entry and next entry are free */ + if (is_free_socksv5(first) && is_free_socksv5(next)) { + free_index = ipa3_ctx->uc_act_tbl_next_index; + IPADBG("found free index at %d\n", free_index); + break; + } + + ipa3_ctx->uc_act_tbl_next_index += 2; + ipa3_ctx->uc_act_tbl_next_index %= + IPA_UC_ACT_TBL_SIZE; + } while (orig_index != ipa3_ctx->uc_act_tbl_next_index); + + IPADBG("exit free_index %d\n", free_index); + return free_index; +} + /** * ipa3_add_socksv5_conn() - IPA add socksv5_conn * @@ -9159,8 +9432,8 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) */ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) { - int res = 0; - void *rp_va, *wp_va; + int res = 0, index; + void *wp_va; struct ipa_socksv5_msg *socksv5_msg; struct ipa_msg_meta msg_meta; @@ -9181,18 +9454,24 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) } mutex_lock(&ipa3_ctx->act_tbl_lock); - /* check the left # of entries */ + /* check the left # of entries (need at least 2)*/ if (ipa3_ctx->uc_act_tbl_total - >= IPA_UC_ACT_TBL_SIZE) { + >= IPA_UC_ACT_TBL_SIZE - 1) { IPAERR("uc act tbl is full!\n"); res = -EFAULT; goto error; } + index = ipa3_get_free_socksv5_entry(); + if (index < 0) { + IPAERR("couldn't find free socksv5 entry\n"); + res = -EFAULT; + goto error; + } + /* Copied the act-info to tbl */ wp_va = ipa3_ctx->uc_act_tbl.base + - ipa3_ctx->uc_act_tbl_next_index - * sizeof(struct ipa_socksv5_uc_tmpl); + index * sizeof(struct ipa_socksv5_uc_tmpl); /* check entry valid */ if ((info->ul_out.cmd_id != IPA_SOCKsv5_ADD_COM_ID) @@ -9229,9 +9508,10 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) &(info->dl_out), sizeof(info->dl_out)); /* set output handle */ - info->handle = (uint16_t) ipa3_ctx->uc_act_tbl_next_index; + info->handle = (uint16_t) index; ipa3_ctx->uc_act_tbl_total += 2; + ipa3_ctx->uc_act_tbl_socksv5_total += 2; /* send msg to ipacm */ socksv5_msg = kzalloc(sizeof(*socksv5_msg), GFP_KERNEL); @@ -9244,9 +9524,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) memcpy(&(socksv5_msg->dl_in), &(info->dl_in), sizeof(info->dl_in)); socksv5_msg->handle = info->handle; socksv5_msg->ul_in.index = - (uint16_t) ipa3_ctx->uc_act_tbl_next_index; + (uint16_t) index; socksv5_msg->dl_in.index = - (uint16_t) ipa3_ctx->uc_act_tbl_next_index + 1; + (uint16_t) index + 1; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = IPA_SOCKV5_ADD; @@ -9259,27 +9539,14 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) goto error; } - if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) { - /* find next free spot */ - do { - ipa3_ctx->uc_act_tbl_next_index += 2; - ipa3_ctx->uc_act_tbl_next_index %= - IPA_UC_ACT_TBL_SIZE; - - rp_va = ipa3_ctx->uc_act_tbl.base + - ipa3_ctx->uc_act_tbl_next_index - * sizeof(struct ipa_socksv5_uc_tmpl); - - if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)-> - ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { - IPADBG("next available entry %d, total %d\n", - ipa3_ctx->uc_act_tbl_next_index, - ipa3_ctx->uc_act_tbl_total); - break; - } - } while (rp_va != wp_va); + if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE - 1) { + /* + * find next free spot, this function shall update + * uc_act_tbl_next_index + */ + index = ipa3_get_free_socksv5_entry(); - if (rp_va == wp_va) { + if (index < 0) { /* set to max tbl size to debug */ IPAERR("can't find available spot!\n"); ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE; @@ -9291,6 +9558,127 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } +/* + * ipa3_add_socksv5_conn_usr() - IPA copy and add socksv5 conn + * + * Returns: 0 on success, negative on failure + * + * Note : Should not be called from atomic context + */ +int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl) +{ + struct ipa_socksv5_info info; + int retval = 0; + + memset(&info, 0, sizeof(struct ipa_socksv5_info)); + + if (tmpl->direction == 0) { /* DL */ + info.dl_out.cmd_id = tmpl->cmd_id; + info.dl_out.cmd_param = tmpl->cmd_param; + info.dl_out.ip_hdr.ipv6_temp.version = 6; + info.dl_out.ip_hdr.ipv6_temp.nexthdr = 6; + info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] = + tmpl->ipv6_src_addr[0]; + info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] = + tmpl->ipv6_src_addr[1]; + info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] = + tmpl->ipv6_src_addr[2]; + info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] = + tmpl->ipv6_src_addr[3]; + info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] = + tmpl->ipv6_dst_addr[0]; + info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] = + tmpl->ipv6_dst_addr[1]; + info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] = + tmpl->ipv6_dst_addr[2]; + info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] = + tmpl->ipv6_dst_addr[3]; + info.dl_out.src_port = tmpl->src_port; + info.dl_out.dst_port = tmpl->dst_port; + info.dl_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask; + info.dl_out.out_irs = tmpl->out_irs; + info.dl_out.out_iss = tmpl->out_iss; + info.dl_out.in_irs = tmpl->in_irs; + info.dl_out.in_iss = tmpl->in_iss; + info.dl_out.out_ircv_tsval = tmpl->out_ircv_tsval; + info.dl_out.in_ircv_tsecr = tmpl->in_ircv_tsecr; + info.dl_out.out_ircv_tsecr = tmpl->out_ircv_tsecr; + info.dl_out.in_ircv_tsval = tmpl->in_ircv_tsval; + info.dl_out.in_isnd_wscale = tmpl->in_isnd_wscale; + info.dl_out.out_isnd_wscale = tmpl->out_isnd_wscale; + info.dl_out.in_ircv_wscale = tmpl->in_ircv_wscale; + info.dl_out.out_ircv_wscale = tmpl->out_ircv_wscale; + + /* for UL set default values to pass pair validity check */ + info.ul_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID; + info.ul_out.cmd_param = IPA_SOCKsv5_ADD_V6_V4_COM_PM; + } else if (tmpl->direction == 1) { /* UL */ + info.ul_out.cmd_id = tmpl->cmd_id; + info.ul_out.cmd_param = tmpl->cmd_param; + if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V4_COM_PM) { + info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.version = 4; + info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.ihl = 5; + info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.saddr = + tmpl->ip_src_addr; + info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.daddr = + tmpl->ip_dst_addr; + info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.protocol = 6; + } + if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V6_COM_PM) { + info.ul_out.ip_hdr.ipv6_temp.version = 6; + info.ul_out.ip_hdr.ipv6_temp.nexthdr = 6; + info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] = + tmpl->ipv6_src_addr[0]; + info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] = + tmpl->ipv6_src_addr[1]; + info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] = + tmpl->ipv6_src_addr[2]; + info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] = + tmpl->ipv6_src_addr[3]; + info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] = + tmpl->ipv6_dst_addr[0]; + info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] = + tmpl->ipv6_dst_addr[1]; + info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] = + tmpl->ipv6_dst_addr[2]; + info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] = + tmpl->ipv6_dst_addr[3]; + } + info.ul_out.src_port = tmpl->src_port; + info.ul_out.dst_port = tmpl->dst_port; + info.ul_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask; + info.ul_out.out_irs = tmpl->out_irs; + info.ul_out.out_iss = tmpl->out_iss; + info.ul_out.in_irs = tmpl->in_irs; + info.ul_out.in_iss = tmpl->in_iss; + info.ul_out.out_ircv_tsval = tmpl->out_ircv_tsval; + info.ul_out.in_ircv_tsecr = tmpl->in_ircv_tsecr; + info.ul_out.out_ircv_tsecr = tmpl->out_ircv_tsecr; + info.ul_out.in_ircv_tsval = tmpl->in_ircv_tsval; + info.ul_out.in_isnd_wscale = tmpl->in_isnd_wscale; + info.ul_out.out_isnd_wscale = tmpl->out_isnd_wscale; + info.ul_out.in_ircv_wscale = tmpl->in_ircv_wscale; + info.ul_out.out_ircv_wscale = tmpl->out_ircv_wscale; + + /* for DL set default values to pass pair validity check */ + info.dl_out.cmd_param = IPA_SOCKsv5_ADD_V4_V6_COM_PM; + info.dl_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID; + } else { + IPAERR("invalid socksv5 direction: %d\n", tmpl->direction); + return -EINVAL; + } + + retval = ipa3_add_socksv5_conn(&info); + if (retval) { + IPAERR("ipa3_add_socksv5_conn failed retval: %d\n", retval); + return retval; + } + + /* save uc handle */ + tmpl->handle = info.handle; + + return retval; +} /** * ipa3_del_socksv5_conn() - IPA add socksv5_conn @@ -9302,9 +9690,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) int ipa3_del_socksv5_conn(uint32_t handle) { int res = 0; - void *rp_va; uint32_t *socksv5_handle; struct ipa_msg_meta msg_meta; + struct ipa_socksv5_uc_tmpl *entry, *next; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { @@ -9322,43 +9710,44 @@ int ipa3_del_socksv5_conn(uint32_t handle) return -EINVAL; } - if ((handle % 2) != 0) { - IPAERR("invalid handle!\n"); + if (ipa3_ctx->uc_act_tbl_socksv5_total < 2) { + IPAERR("invalid handle, tbl doesn't have socksv5 entries!\n"); return -EINVAL; } - if (ipa3_ctx->uc_act_tbl_total < 2) { - IPAERR("invalid handle, all tbl is empty!\n"); - return -EINVAL; - } - - rp_va = ipa3_ctx->uc_act_tbl.base + - handle * sizeof(struct ipa_socksv5_uc_tmpl); + entry = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + + handle * sizeof(struct ipa_socksv5_uc_tmpl)); + next = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + + (handle + 1) * sizeof(struct ipa_socksv5_uc_tmpl)); /* check entry is valid or not */ mutex_lock(&ipa3_ctx->act_tbl_lock); - if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)-> - ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { - IPADBG(" entry %d already free\n", handle); + if (entry->cmd_id != IPA_SOCKsv5_ADD_COM_ID) { + IPAERR(" entry %d not socksv5\n", handle); + res = -EINVAL; + goto error; } + if (next->cmd_id != IPA_SOCKsv5_ADD_COM_ID) { + IPAERR(" entry %d not socksv5\n", handle + 1); + res = -EINVAL; + goto error; + } + if (!(entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)) + IPADBG(" entry %d already free\n", handle); - if (!((((struct ipa_socksv5_uc_tmpl *) (rp_va + - sizeof(struct ipa_socksv5_uc_tmpl)))-> - ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { + if (!(next->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)) IPADBG(" entry %d already free\n", handle); - } - ((struct ipa_socksv5_uc_tmpl *) rp_va)->ipa_sockv5_mask - &= ~IPA_SOCKSv5_ENTRY_VALID; - ((struct ipa_socksv5_uc_tmpl *) (rp_va + - sizeof(struct ipa_socksv5_uc_tmpl)))->ipa_sockv5_mask - &= ~IPA_SOCKSv5_ENTRY_VALID; + entry->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; + next->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; ipa3_ctx->uc_act_tbl_total -= 2; + ipa3_ctx->uc_act_tbl_socksv5_total -= 2; - IPADBG("free entry %d and %d, left total %d\n", + IPADBG("free entry %d and %d, left total %d, socksv5 total %d\n", handle, handle + 1, - ipa3_ctx->uc_act_tbl_total); + ipa3_ctx->uc_act_tbl_total, + ipa3_ctx->uc_act_tbl_socksv5_total); /* send msg to ipacm */ socksv5_handle = kzalloc(sizeof(*socksv5_handle), GFP_KERNEL); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index e16003813a9ce3970fd5deb45caa3175e1f4eb0a..4d261f862d9731ab215dd92eaebc7a83e969d545 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -1428,6 +1428,9 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type, case IPA_HDR_PROC_802_3_TO_802_3: ctx->cmd.value = IPA_HDR_UCP_802_3_TO_802_3; break; + case IPA_HDR_PROC_SET_DSCP: + ctx->cmd.value = IPA_HDR_UCP_SET_DSCP; + break; default: IPAHAL_ERR("unknown ipa_hdr_proc_type %d", type); WARN_ON(1); @@ -1480,6 +1483,9 @@ static int ipahal_get_proc_ctx_needed_len_v3(enum ipa_hdr_proc_type type) case IPA_HDR_PROC_ETHII_TO_ETHII_EX: ret = sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq_ex); break; + case IPA_HDR_PROC_SET_DSCP: + ret = sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq); + break; default: /* invalid value to make sure failure */ IPAHAL_ERR_RL("invalid ipa_hdr_proc_type %d\n", type); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h index 77524c4a5227967cf296fa7dd4fada4e4b134c09..787da2a651ff07583f91d90bd1be9215d74c3159 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h @@ -624,6 +624,7 @@ struct ipa_pkt_status_hw { #define IPA_HDR_UCP_L2TP_UDP_HEADER_ADD 12 #define IPA_HDR_UCP_L2TP_UDP_HEADER_REMOVE 13 #define IPA_HDR_UCP_ETHII_TO_ETHII_EX 14 +#define IPA_HDR_UCP_SET_DSCP 16 /* Processing context TLV type */ #define IPA_PROC_CTX_TLV_TYPE_END 0 diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 8c2f12e6dc2c1224e1da5f30cc0f29e1f4f239f2..d6cd1b856bea6aba9ca3d17fe1b59c2ed81a01aa 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1496,6 +1496,10 @@ static int ipa_send_mhi_endp_ind_to_modem(void) int ipa_mhi_cons_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); + if (ipa_mhi_prod_ep_idx == IPA_EP_NOT_ALLOCATED || + ipa_mhi_cons_ep_idx == IPA_EP_NOT_ALLOCATED) + return -EINVAL; + memset(&req, 0, sizeof(struct ipa_endp_desc_indication_msg_v01)); req.ep_info_len = 2; req.ep_info_valid = true; @@ -4165,7 +4169,12 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) if (ipa3_ctx->ipa_mhi_proxy) imp_handle_modem_ready(); - if (ipa3_ctx->ipa_config_is_mhi) + /* + * currently the endp_desc indication only send + * on non-auto mode for low latency pipes + */ + if (ipa3_ctx->ipa_config_is_mhi && + !ipa3_ctx->ipa_config_is_auto) ipa_send_mhi_endp_ind_to_modem(); } diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index fc98fec90068915043b12bfaca1b2fa8a88c67a9..f2336be13d8d9c4241dc1fdaeb78561086b2a406 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -41,6 +41,9 @@ /* Wait time before suspend/resume is complete */ #define MHI_SUSPEND_MIN 100 #define MHI_SUSPEND_TIMEOUT 600 +/* Wait time on the device for Host to set BHI_INTVEC */ +#define MHI_BHI_INTVEC_MAX_CNT 200 +#define MHI_BHI_INTVEC_WAIT_MS 50 #define MHI_WAKEUP_TIMEOUT_CNT 20 #define MHI_MASK_CH_EV_LEN 32 #define MHI_RING_CMD_ID 0 @@ -2045,6 +2048,14 @@ static void mhi_update_state_info_all(enum mhi_ctrl_info info) mhi_ctx->ctrl_info = info; for (i = 0; i < MHI_MAX_SOFTWARE_CHANNELS; ++i) { + /* + * Skip channel state info change + * if channel is already in the desired state. + */ + if (channel_state_info[i].ctrl_info == info || + (info == MHI_STATE_DISCONNECTED && + channel_state_info[i].ctrl_info == MHI_STATE_CONFIGURED)) + continue; channel_state_info[i].ctrl_info = info; /* Notify kernel clients */ mhi_dev_trigger_cb(i); @@ -3162,7 +3173,7 @@ EXPORT_SYMBOL(mhi_dev_write_channel); static int mhi_dev_recover(struct mhi_dev *mhi) { int rc = 0; - uint32_t syserr, max_cnt = 0, bhi_intvec = 0; + uint32_t syserr, max_cnt = 0, bhi_intvec = 0, bhi_max_cnt = 0; u32 mhi_reset; enum mhi_dev_state state; @@ -3187,6 +3198,26 @@ static int mhi_dev_recover(struct mhi_dev *mhi) if (rc) return rc; + while (bhi_intvec == 0xffffffff && + bhi_max_cnt < MHI_BHI_INTVEC_MAX_CNT) { + /* Wait for Host to set the bhi_intvec */ + msleep(MHI_BHI_INTVEC_WAIT_MS); + mhi_log(MHI_MSG_VERBOSE, + "Wait for Host to set BHI_INTVEC\n"); + rc = mhi_dev_mmio_read(mhi, BHI_INTVEC, &bhi_intvec); + if (rc) { + pr_err("%s: Get BHI_INTVEC failed\n", __func__); + return rc; + } + bhi_max_cnt++; + } + + if (bhi_max_cnt == MHI_BHI_INTVEC_MAX_CNT) { + mhi_log(MHI_MSG_ERROR, + "Host failed to set BHI_INTVEC\n"); + return -EINVAL; + } + if (bhi_intvec != 0xffffffff) { /* Indicate the host that the device is ready */ rc = ep_pcie_trigger_msi(mhi->phandle, bhi_intvec); diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d01e15711e18ad5453af7d4d70f96f40749f9a3f..c61bec66eaf67bc2946b14068dd17ee59f42d2f5 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "mhi.h" @@ -526,8 +527,6 @@ static int mhi_dev_net_open_chan_create_netif(struct mhi_dev_net_client *client) mhi_dev_net_log(MHI_DBG, "opening OUT %d IN %d channels\n", client->out_chan, client->in_chan); - mutex_lock(&client->out_chan_lock); - mutex_lock(&client->in_chan_lock); mhi_dev_net_log(MHI_DBG, "Initializing inbound chan %d.\n", client->in_chan); @@ -552,8 +551,6 @@ static int mhi_dev_net_open_chan_create_netif(struct mhi_dev_net_client *client) } else atomic_set(&client->tx_enabled, 1); - mutex_unlock(&client->in_chan_lock); - mutex_unlock(&client->out_chan_lock); mhi_dev_net_log(MHI_INFO, "IN %d, OUT %d channels are opened", client->in_chan, client->out_chan); @@ -601,8 +598,8 @@ static int mhi_dev_net_close(void) "mhi_dev_net module is removed\n"); client = mhi_net_ctxt.client_handle; mhi_dev_close_channel(client->out_handle); - mhi_dev_close_channel(client->in_handle); atomic_set(&client->tx_enabled, 0); + mhi_dev_close_channel(client->in_handle); atomic_set(&client->rx_enabled, 0); if (client->dev != NULL) { netif_stop_queue(client->dev); @@ -638,6 +635,18 @@ static int mhi_dev_net_dergstr_client return 0; } +static void mhi_dev_net_free_reqs(struct list_head *buff) +{ + struct list_head *node, *next; + struct mhi_req *mreq; + + list_for_each_safe(node, next, buff) { + mreq = list_entry(node, struct mhi_req, list); + list_del(&mreq->list); + kfree(mreq); + } +} + static void mhi_dev_net_state_cb(struct mhi_dev_client_cb_data *cb_data) { struct mhi_dev_net_client *mhi_client; @@ -686,11 +695,15 @@ static void mhi_dev_net_state_cb(struct mhi_dev_client_cb_data *cb_data) netif_stop_queue(mhi_client->dev); unregister_netdev(mhi_client->dev); mhi_dev_close_channel(mhi_client->out_handle); - mhi_dev_close_channel(mhi_client->in_handle); atomic_set(&mhi_client->tx_enabled, 0); + mhi_dev_close_channel(mhi_client->in_handle); atomic_set(&mhi_client->rx_enabled, 0); + mhi_dev_net_free_reqs(&mhi_client->rx_buffers); + mhi_dev_net_free_reqs(&mhi_client->wr_req_buffers); free_netdev(mhi_client->dev); mhi_client->dev = NULL; + kfree(mhi_client); + kfree(mhi_net_ipc_log); } } } diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 62d4fe0bf7de2d61a961c2f71b10b23856b26c6a..4d208bb931c18e1c979d159e4c93753c5e9c8d75 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -1102,7 +1102,7 @@ int mhi_dev_sm_init(struct mhi_dev *mhi_dev) /*init debugfs*/ mhi_sm_debugfs_init(); - mhi_sm_ctx->mhi_sm_wq = create_singlethread_workqueue("mhi_sm_wq"); + mhi_sm_ctx->mhi_sm_wq = alloc_workqueue("mhi_sm_wq", WQ_HIGHPRI, 0); if (!mhi_sm_ctx->mhi_sm_wq) { MHI_SM_ERR("Failed to create singlethread_workqueue: sm_wq\n"); res = -ENOMEM; diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c index d2b8a8d75099da3d77967416735dd17074814559..6c1d04cfe079a099c818a4bf0b78743246e77a98 100644 --- a/drivers/platform/msm/qcom-geni-se.c +++ b/drivers/platform/msm/qcom-geni-se.c @@ -501,9 +501,12 @@ static int geni_se_select_dma_mode(void __iomem *base) geni_write_reg(0xFFFFFFFF, base, SE_IRQ_EN); common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN); - if (proto != UART) + if (proto != UART) { common_geni_m_irq_en &= ~(M_TX_FIFO_WATERMARK_EN | M_RX_FIFO_WATERMARK_EN); + if (proto != I3C) + common_geni_m_irq_en &= ~M_CMD_DONE_EN; + } geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN); geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN); @@ -622,6 +625,14 @@ EXPORT_SYMBOL(geni_setup_s_cmd); */ void geni_cancel_m_cmd(void __iomem *base) { + unsigned int common_geni_m_irq_en; + int proto = get_se_proto(base); + + if (proto != UART && proto != I3C) { + common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN); + common_geni_m_irq_en &= ~M_CMD_DONE_EN; + geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN); + } geni_write_reg(M_GENI_CMD_CANCEL, base, SE_GENI_M_CMD_CTRL_REG); } EXPORT_SYMBOL(geni_cancel_m_cmd); @@ -2026,7 +2037,8 @@ static int geni_se_probe(struct platform_device *pdev) ret = devm_clk_bulk_get(dev, SSC_NUM_CLKS, geni_se_dev->ssc_clks); if (ret) { - dev_err(dev, "%s: Err getting core/2x clk:%d\n", ret); + dev_err(dev, "%s: Err getting core/2x clk:%d\n", + __func__, ret); return ret; } diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c index c2b2137185b826fd14312f299065443055b99616..be6e45604f8a67870b724668ea34d69da17abd42 100644 --- a/drivers/platform/msm/sps/bam.c +++ b/drivers/platform/msm/sps/bam.c @@ -2174,13 +2174,16 @@ void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option) u32 pipe = pipe_index; u32 desc_fifo_addr; u32 desc_fifo_size; - u32 *desc_fifo; + u32 __iomem *desc_fifo; int i; char desc_info[MAX_MSG_LEN]; + struct sps_bam *dev; if (base == NULL) return; + dev = to_sps_bam_dev(virt_addr); + desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR, pipe); desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES, pipe, P_DESC_FIFO_SIZE); @@ -2202,7 +2205,14 @@ void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option) "BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n", desc_fifo_addr, desc_fifo_size, desc_fifo_size); - desc_fifo = (u32 *) phys_to_virt(desc_fifo_addr); + if (dev->props.options & SPS_BAM_SMMU_EN) { + struct sps_pipe *pipe_indx = dev->pipes[pipe_index]; + + SPS_DUMP("%s", "SMMU is enabled\n"); + desc_fifo = pipe_indx->map->desc.base; + } else { + desc_fifo = (u32 __iomem *) phys_to_virt(desc_fifo_addr); + } if (option == 100) { SPS_DUMP("%s", diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 68f4e3e91c90499c2a21f9d6dd530d25fd6eaf6b..3a8ccbdea296ed766ab214f170c8d6af7d3641d5 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -899,14 +899,12 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, peer_bam->props.phys_addr; } if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) { - hw_params.peer_phys_addr = - bam_pipe->connect.destination; - hw_params.peer_pipe = - bam_pipe->connect.dest_pipe_index; + hw_params.peer_pipe = other_pipe->pipe_index; } else { hw_params.peer_phys_addr = bam_pipe->connect.destination; - hw_params.peer_pipe = other_pipe->pipe_index; + hw_params.peer_pipe = + bam_pipe->connect.dest_pipe_index; hw_params.dummy_peer = true; } /* Verify FIFO buffers are allocated for BAM-to-BAM pipes */ diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 5ad44204a9c3c997bf237aacfb1bbb99ab292ef7..10dbd6cac48aedea426d0cf8b525c7717ffd23b4 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -158,9 +158,10 @@ static int mid_pb_probe(struct platform_device *pdev) input_set_capability(input, EV_KEY, KEY_POWER); - ddata = (struct mid_pb_ddata *)id->driver_data; + ddata = devm_kmemdup(&pdev->dev, (void *)id->driver_data, + sizeof(*ddata), GFP_KERNEL); if (!ddata) - return -ENODATA; + return -ENOMEM; ddata->dev = &pdev->dev; ddata->irq = irq; diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 2c85f75e32b08b27af3c96fa413fc9ebbccc252c..2434ce8bead6dd4579da2c5b1ecfc1badd8aaf78 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -69,26 +69,22 @@ struct intel_scu_ipc_pdata_t { u32 i2c_base; u32 i2c_len; - u8 irq_mode; }; static const struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = { .i2c_base = 0xff12b000, .i2c_len = 0x10, - .irq_mode = 0, }; /* Penwell and Cloverview */ static const struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = { .i2c_base = 0xff12b000, .i2c_len = 0x10, - .irq_mode = 1, }; static const struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = { .i2c_base = 0xff00d000, .i2c_len = 0x10, - .irq_mode = 0, }; struct intel_scu_ipc_dev { @@ -101,6 +97,9 @@ struct intel_scu_ipc_dev { static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ +#define IPC_STATUS 0x04 +#define IPC_STATUS_IRQ BIT(2) + /* * IPC Read Buffer (Read Only): * 16 byte buffer for receiving data from SCU, if IPC command @@ -122,11 +121,8 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ */ static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd) { - if (scu->irq_mode) { - reinit_completion(&scu->cmd_complete); - writel(cmd | IPC_IOC, scu->ipc_base); - } - writel(cmd, scu->ipc_base); + reinit_completion(&scu->cmd_complete); + writel(cmd | IPC_IOC, scu->ipc_base); } /* @@ -612,9 +608,10 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); static irqreturn_t ioc(int irq, void *dev_id) { struct intel_scu_ipc_dev *scu = dev_id; + int status = ipc_read_status(scu); - if (scu->irq_mode) - complete(&scu->cmd_complete); + writel(status | IPC_STATUS_IRQ, scu->ipc_base + IPC_STATUS); + complete(&scu->cmd_complete); return IRQ_HANDLED; } @@ -640,8 +637,6 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!pdata) return -ENODEV; - scu->irq_mode = pdata->irq_mode; - err = pcim_enable_device(pdev); if (err) return err; diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index 74997194fd88081a901daf9336f15ca4293b0e22..92205b90c25cbbf1c42d5d846bbc692dac6fa1a3 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -443,6 +443,14 @@ static const struct dmi_system_id critclk_systems[] = { DMI_MATCH(DMI_PRODUCT_NAME, "3I380D"), }, }, + { + /* pmc_plt_clk* - are used for ethernet controllers */ + .ident = "Lex 2I385SW", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), + DMI_MATCH(DMI_PRODUCT_NAME, "2I385SW"), + }, + }, { /* pmc_plt_clk* - are used for ethernet controllers */ .ident = "Beckhoff CB3163", diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 51f0961ecf3e015c5ff9752d8999ac1281c48e34..a7d8cadf172cb24704b8a840b5cbf887cb4d2724 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1842,7 +1842,10 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) { - dev_err(di->dev, "failed to register battery\n"); + if (PTR_ERR(di->bat) == -EPROBE_DEFER) + dev_dbg(di->dev, "failed to register battery, deferring probe\n"); + else + dev_err(di->dev, "failed to register battery\n"); return PTR_ERR(di->bat); } diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index 9621d6dd88c6f6219486b2dc6ec169cc1d91dff1..50bdf2d5248b9b6594460857cf86dc94ffa76483 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -406,7 +406,7 @@ static int ltc294x_i2c_remove(struct i2c_client *client) { struct ltc294x_info *info = i2c_get_clientdata(client); - cancel_delayed_work(&info->work); + cancel_delayed_work_sync(&info->work); power_supply_unregister(info->supply); return 0; } diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index e702131d8ebd2dbc5131102e81b528d5b6563136..88bfbb203e3be1e379ac379d2d983f432765fc88 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -60,8 +60,7 @@ static const char * const power_supply_charge_type_text[] = { static const char * const power_supply_health_text[] = { "Unknown", "Good", "Overheat", "Dead", "Over voltage", "Unspecified failure", "Cold", "Watchdog timer expire", - "Safety timer expire", - "Warm", "Cool", "Hot" + "Safety timer expire", "Over current", "Warm", "Cool", "Hot" }; static const char * const power_supply_technology_text[] = { diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index ccb0565a1c4931a4c3dc5de8ab790d68b9c69427..0c6a11b6961a79dc8daf2c804c4e7dbf66073631 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -49,6 +49,7 @@ #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" #define FCC_VOTER "FCC_VOTER" #define MAIN_FCC_VOTER "MAIN_FCC_VOTER" +#define PD_VOTER "PD_VOTER" struct pl_data { int pl_mode; @@ -198,30 +199,58 @@ static int cp_get_parallel_mode(struct pl_data *chip, int mode) return pval.intval; } -static int get_hvdcp3_icl_limit(struct pl_data *chip) +static int get_adapter_icl_based_ilim(struct pl_data *chip) { - int main_icl, target_icl = -EINVAL; + int main_icl = -EINVAL, adapter_icl = -EINVAL, final_icl = -EINVAL; + int rc = -EINVAL; + union power_supply_propval pval = {0, }; - if ((chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3) - && (chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3P5)) - return target_icl; + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &pval); + if (rc < 0) + pr_err("Failed to read PD_ACTIVE status rc=%d\n", + rc); + /* Check for QC 3, 3.5 and PPS adapters, return if its none of them */ + if (chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3 && + chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3P5 && + pval.intval != POWER_SUPPLY_PD_PPS_ACTIVE) + return final_icl; + + /* + * For HVDCP3/HVDCP_3P5 adapters, limit max. ILIM as: + * HVDCP3_ICL: Maximum ICL of HVDCP3 adapter(from DT + * configuration). + * + * For PPS adapters, limit max. ILIM to + * MIN(qc4_max_icl, PD_CURRENT_MAX) + */ + if (pval.intval == POWER_SUPPLY_PD_PPS_ACTIVE) { + adapter_icl = min_t(int, chip->chg_param->qc4_max_icl_ua, + get_client_vote_locked(chip->usb_icl_votable, + PD_VOTER)); + if (adapter_icl <= 0) + adapter_icl = chip->chg_param->qc4_max_icl_ua; + } else { + adapter_icl = chip->chg_param->hvdcp3_max_icl_ua; + } /* - * For HVDCP3 adapters, limit max. ILIM as follows: - * HVDCP3_ICL: Maximum ICL of HVDCP3 adapter(from DT configuration) * For Parallel input configurations: - * VBUS: target_icl = HVDCP3_ICL - main_ICL - * VMID: target_icl = HVDCP3_ICL + * VBUS: final_icl = adapter_icl - main_ICL + * VMID: final_icl = adapter_icl */ - target_icl = chip->chg_param->hvdcp3_max_icl_ua; + final_icl = adapter_icl; if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE) == POWER_SUPPLY_PL_USBIN_USBIN) { main_icl = get_effective_result_locked(chip->usb_icl_votable); - if ((main_icl >= 0) && (main_icl < target_icl)) - target_icl -= main_icl; + if ((main_icl >= 0) && (main_icl < adapter_icl)) + final_icl = adapter_icl - main_icl; } - return target_icl; + pr_debug("charger_type=%d final_icl=%d adapter_icl=%d main_icl=%d\n", + chip->charger_type, final_icl, adapter_icl, main_icl); + + return final_icl; } /* @@ -252,7 +281,7 @@ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) == POWER_SUPPLY_PL_OUTPUT_VPH) return; - target_icl = get_hvdcp3_icl_limit(chip); + target_icl = get_adapter_icl_based_ilim(chip); ilim = (target_icl > 0) ? min(ilim, target_icl) : ilim; rc = power_supply_get_property(chip->cp_master_psy, @@ -750,7 +779,7 @@ static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, if (!chip->cp_ilim_votable) chip->cp_ilim_votable = find_votable("CP_ILIM"); - target_icl = get_hvdcp3_icl_limit(chip) * 2; + target_icl = get_adapter_icl_based_ilim(chip) * 2; total_fcc_ua -= chip->main_fcc_ua; /* diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h index 0ff716a3d97b638d629e6fd41332231c65ad47f6..5d2e783ead82d5b1aff99562b16759461dea29fc 100644 --- a/drivers/power/supply/qcom/battery.h +++ b/drivers/power/supply/qcom/battery.h @@ -19,6 +19,7 @@ struct charger_param { u32 smb_version; u32 hvdcp3_max_icl_ua; u32 forced_main_fcc; + u32 qc4_max_icl_ua; }; int qcom_batt_init(struct charger_param *param); diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 8c4a2ace9f5649383b2a87a57b0515f3a195dff2..7134225ffbd52fba2888f9b6768622e398c071da 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3663,6 +3663,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: rc = fg_get_time_to_full(fg, &pval->intval); break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + rc = fg_get_time_to_full(fg, &pval->intval); + break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: rc = fg_get_time_to_empty(fg, &pval->intval); break; @@ -3888,6 +3891,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 42c0ccf4ba54c07ac6da8c3bb3426c1dc4033735..85a62678b79b0f3cf43dd57210f69729db26c2cf 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -4437,6 +4437,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: rc = ttf_get_time_to_full(chip->ttf, &pval->intval); break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); break; @@ -4621,6 +4624,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, POWER_SUPPLY_PROP_CC_STEP, POWER_SUPPLY_PROP_CC_STEP_SEL, diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index e2bff0c0f48cd90251128c77d864ff8fca7f680f..5651c8c0ccf92a262c957002997489e8a9534be3 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -2150,6 +2150,9 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: rc = ttf_get_time_to_full(chip->ttf, &pval->intval); break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); break; @@ -2235,6 +2238,7 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, POWER_SUPPLY_PROP_ESR_ACTUAL, POWER_SUPPLY_PROP_ESR_NOMINAL, diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index b54c20d8c04e89397e6e244bac240cabd26d3d61..c0e59cec26a6538b61a373a087e1310023b51ec5 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -1020,6 +1020,8 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, }; @@ -1130,9 +1132,11 @@ static int smb2_batt_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: case POWER_SUPPLY_PROP_CYCLE_COUNT: case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: rc = smblib_get_prop_from_bms(chg, psp, val); break; case POWER_SUPPLY_PROP_CURRENT_NOW: diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 3903c213c0d39a4b19c96e29a952488b670745bf..f0e19d9108fef33a6ca2efa1cfd644909f24593f 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -388,6 +388,7 @@ static int smb5_configure_internal_pull(struct smb_charger *chg, int type, #define MICRO_P1A 100000 #define MICRO_1PA 1000000 #define MICRO_3PA 3000000 +#define MICRO_4PA 4000000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 #define DEFAULT_WD_BARK_TIME 64 #define DEFAULT_WD_SNARL_TIME_8S 0x07 @@ -657,6 +658,12 @@ static int smb5_parse_dt(struct smb5 *chip) if (chg->chg_param.hvdcp3_max_icl_ua <= 0) chg->chg_param.hvdcp3_max_icl_ua = MICRO_3PA; + /* Used only in Adapter CV mode of operation */ + of_property_read_u32(node, "qcom,qc4-max-icl-ua", + &chg->chg_param.qc4_max_icl_ua); + if (chg->chg_param.qc4_max_icl_ua <= 0) + chg->chg_param.qc4_max_icl_ua = MICRO_4PA; + chg->wls_icl_ua = DCIN_ICL_MAX_UA; rc = of_property_read_u32(node, "qcom,wls-current-max-ua", &tmp); @@ -784,7 +791,7 @@ static int smb5_usb_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER); break; case POWER_SUPPLY_PROP_CURRENT_MAX: - rc = smblib_get_prop_input_current_settled(chg, val); + rc = smblib_get_prop_input_current_max(chg, val); break; case POWER_SUPPLY_PROP_TYPE: val->intval = POWER_SUPPLY_TYPE_USB_PD; @@ -1580,6 +1587,8 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_RECHARGE_SOC, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_FORCE_RECHARGE, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, }; @@ -1717,6 +1726,14 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FORCE_RECHARGE: val->intval = 0; break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, val); + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, val); + break; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; break; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index ffec1bf46b0d68af68bbcb388d87345fec14151f..d3c378a2b708220d6d1966968a3ddb0438e9cd08 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -725,6 +725,7 @@ static void smblib_uusb_removal(struct smb_charger *chg) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0); + vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0); cancel_delayed_work_sync(&chg->hvdcp_detect_work); @@ -1716,6 +1717,8 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev) rc = _smblib_vbus_regulator_enable(rdev); if (rc >= 0) chg->otg_en = true; + else + vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0); unlock: mutex_unlock(&chg->otg_oc_lock); @@ -4388,6 +4391,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); + vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0); chg->vconn_attempts = 0; chg->otg_attempts = 0; chg->pulse_cnt = 0; diff --git a/drivers/power/supply/qcom/smb1390-charger-psy.c b/drivers/power/supply/qcom/smb1390-charger-psy.c index bb2daa1a1bed1d44c6dbe141a17676364a5b9532..2ba33936e048885006eb10b92abd2819f460363a 100644 --- a/drivers/power/supply/qcom/smb1390-charger-psy.c +++ b/drivers/power/supply/qcom/smb1390-charger-psy.c @@ -211,10 +211,10 @@ struct smb1390 { int cp_isns_slave; int cp_ilim; int die_temp; + int min_ilim_ua; bool suspended; bool disabled; u32 debug_mask; - u32 min_ilim_ua; u32 max_temp_alarm_degc; u32 max_cutoff_soc; u32 pl_output_mode; @@ -1240,7 +1240,7 @@ static void smb1390_taper_work(struct work_struct *work) { struct smb1390 *chip = container_of(work, struct smb1390, taper_work); union power_supply_propval pval = {0, }; - int rc, fcc_uA, delta_fcc_uA, main_fcc_ua = 0; + int rc, fcc_uA, delta_fcc_uA, main_fcc_ua = 0, fcc_cp_ua; if (!is_psy_voter_available(chip)) goto out; @@ -1290,7 +1290,21 @@ static void smb1390_taper_work(struct work_struct *work) goto out; } - if ((fcc_uA - main_fcc_ua) < (chip->min_ilim_ua * 2)) { + /* + * fcc and fcc_main are the same for VPH config, hence + * reduce fcc_main from fcc only in VBAT (output config) + * where fcc_main is a portion of full-fcc. + */ + fcc_cp_ua = fcc_uA; + if (chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VBAT) + fcc_cp_ua = fcc_uA - main_fcc_ua; + + smb1390_dbg(chip, PR_INFO, + "Taper: fcc_ua=%d fcc_cp_ua=%d fcc_main_ua=%d min_ilim_ua(x2) = %u\n", + fcc_uA, fcc_cp_ua, main_fcc_ua, + (chip->min_ilim_ua*2)); + + if (fcc_cp_ua < (chip->min_ilim_ua * 2)) { vote(chip->disable_votable, TAPER_END_VOTER, true, 0); /* diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 5f834401ab0b2b7d31bb728dbef0f009bd7dc003..62396c59a32ebf1da799b98c9770bd6e116ee281 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -26,6 +26,8 @@ #include /* Status register definition */ +#define PERPH0_REVISION4 0x2603 + #define INPUT_STATUS_REG 0x2609 #define INPUT_USB_IN BIT(1) #define INPUT_WLS_IN BIT(0) @@ -97,6 +99,7 @@ #define MISC_CFG0_REG 0x2634 #define DIS_SYNC_DRV_BIT BIT(5) #define SW_EN_SWITCHER_BIT BIT(3) +#define CFG_DIS_FPF_IREV_BIT BIT(1) #define MISC_CFG1_REG 0x2635 #define MISC_CFG1_MASK GENMASK(7, 0) @@ -113,6 +116,7 @@ #define MISC_CFG2_REG 0x2636 #define NOLOCK_SPARE_REG 0x2637 +#define EN_SLAVE_OWN_FREQ_BIT BIT(5) #define DIV2_WIN_UV_SEL_BIT BIT(4) #define DIV2_WIN_UV_25MV 0 #define COMBO_WIN_LO_EXIT_SEL_MASK GENMASK(3, 2) @@ -177,6 +181,10 @@ #define PERPH0_CFG_SDCDC_REG 0x267A #define EN_WIN_UV_BIT BIT(7) +#define PERPH0_SSUPPLY_CFG0_REG 0x2682 +#define EN_HV_OV_OPTION2_BIT BIT(7) +#define EN_MV_OV_OPTION2_BIT BIT(5) + #define SSUPLY_TEMP_CTRL_REG 0x2683 #define SEL_OUT_TEMP_MAX_MASK GENMASK(7, 5) #define SEL_OUT_TEMP_MAX_SHFT 5 @@ -191,6 +199,10 @@ #define DIV2_ILIM_STS BIT(5) #define DIV2_CFLY_SS_DONE_STS BIT(1) +#define PERPH1_LOCK_SPARE_REG 0x27C3 +#define CFG_LOCK_SPARE1_MASK GENMASK(7, 6) +#define CFG_LOCK_SPARE1_SHIFT 6 + /* available voters */ #define ILIM_VOTER "ILIM_VOTER" #define TAPER_VOTER "TAPER_VOTER" @@ -232,6 +244,13 @@ enum isns_mode { ISNS_MODE_STANDBY, }; +enum ovp { + OVP_17P7V = 0, + OVP_14V, + OVP_22P2V, + OVP_7P3, +}; + enum { /* Perph0 IRQs */ CFLY_HARD_FAULT_LATCH_IRQ, @@ -879,6 +898,24 @@ static int div2_cp_master_get_prop_suspended(struct smb1398_chip *chip, return 0; } +#define DEFAULT_HVDCP3_MIN_ICL_UA 1000000 +static int smb1398_div2_cp_get_min_icl(struct smb1398_chip *chip) +{ + union power_supply_propval pval; + int rc; + + /* Use max(dt_min_icl, 1A) for HVDCP3 */ + if (chip->usb_psy) { + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_REAL_TYPE, &pval); + if (rc >= 0 && (pval.intval == POWER_SUPPLY_TYPE_USB_HVDCP_3)) + return max(chip->div2_cp_min_ilim_ua, + DEFAULT_HVDCP3_MIN_ICL_UA); + } + + return chip->div2_cp_min_ilim_ua; +} + static int div2_cp_master_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) @@ -979,7 +1016,7 @@ static int div2_cp_master_get_prop(struct power_supply *psy, val->intval = chip->pl_output_mode; break; case POWER_SUPPLY_PROP_MIN_ICL: - val->intval = chip->div2_cp_min_ilim_ua; + val->intval = smb1398_div2_cp_get_min_icl(chip); break; default: rc = -EINVAL; @@ -1223,16 +1260,6 @@ static int smb1398_div2_cp_slave_disable_vote_cb(struct votable *votable, if (!is_cps_available(chip)) return -ENODEV; - /* Enable/disable SYNC driver before enabling/disabling slave */ - reg = MISC_CFG0_REG; - val = !!disable ? DIS_SYNC_DRV_BIT : 0; - rc = smb1398_masked_write(chip, reg, DIS_SYNC_DRV_BIT, val); - if (rc < 0) { - dev_err(chip->dev, "%s slave SYNC_DRV failed, rc=%d\n", - !!disable ? "disable" : "enable", rc); - return rc; - } - reg = MISC_SL_SWITCH_EN_REG; val = !!disable ? 0 : EN_SLAVE; rc = smb1398_masked_write(chip, reg, EN_SLAVE, val); @@ -1278,7 +1305,7 @@ static int smb1398_div2_cp_ilim_vote_cb(struct votable *votable, { struct smb1398_chip *chip = (struct smb1398_chip *)data; union power_supply_propval pval = {0}; - int rc = 0, max_ilim_ua; + int rc = 0, max_ilim_ua, min_ilim_ua; bool slave_dis, split_ilim = false; if (!is_psy_voter_available(chip) || chip->in_suspend) @@ -1287,19 +1314,21 @@ static int smb1398_div2_cp_ilim_vote_cb(struct votable *votable, if (!client) return -EINVAL; + min_ilim_ua = smb1398_div2_cp_get_min_icl(chip); + ilim_ua = (ilim_ua * DIV2_ILIM_CFG_PCT) / 100; max_ilim_ua = is_cps_available(chip) ? DIV2_MAX_ILIM_DUAL_CP_UA : DIV2_MAX_ILIM_UA; ilim_ua = min(ilim_ua, max_ilim_ua); - if (ilim_ua < chip->div2_cp_min_ilim_ua) { + if (ilim_ua < min_ilim_ua) { dev_dbg(chip->dev, "ilim %duA is too low to config CP charging\n", ilim_ua); vote(chip->div2_cp_disable_votable, ILIM_VOTER, true, 0); } else { if (is_cps_available(chip)) { split_ilim = true; - slave_dis = ilim_ua < (2 * chip->div2_cp_min_ilim_ua); + slave_dis = ilim_ua < (2 * min_ilim_ua); vote(chip->div2_cp_slave_disable_votable, ILIM_VOTER, slave_dis, 0); slave_dis = !!get_effective_result( @@ -1726,7 +1755,7 @@ static void smb1398_taper_work(struct work_struct *work) struct smb1398_chip *chip = container_of(work, struct smb1398_chip, taper_work); union power_supply_propval pval = {0}; - int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua = 0; + int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua = 0, min_ilim_ua; bool slave_en; if (!is_psy_voter_available(chip)) @@ -1738,6 +1767,8 @@ static void smb1398_taper_work(struct work_struct *work) if (chip->fcc_main_votable) main_fcc_ua = get_effective_result(chip->fcc_main_votable); + min_ilim_ua = smb1398_div2_cp_get_min_icl(chip); + chip->taper_entry_fv = get_effective_result(chip->fv_votable); while (true) { rc = power_supply_get_property(chip->batt_psy, @@ -1773,7 +1804,7 @@ static void smb1398_taper_work(struct work_struct *work) * If total FCC is less than the minimum ILIM to * keep CP master and slave online, disable CP. */ - if (fcc_ua < (chip->div2_cp_min_ilim_ua * 2)) { + if (fcc_ua < (min_ilim_ua * 2)) { vote(chip->div2_cp_disable_votable, TAPER_VOTER, true, 0); /* @@ -1822,10 +1853,53 @@ static void smb1398_taper_work(struct work_struct *work) chip->taper_work_running = false; } +static int smb1398_update_ovp(struct smb1398_chip *chip) +{ + int rc = 0; + u8 reg = 0; + + rc = smb1398_read(chip, PERPH0_REVISION4, ®); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read PERPH0_REVISION4 rc=%d\n", rc); + return rc; + } + + /* Ignore for REV2 and below */ + if (reg <= 2) + return 0; + + rc = smb1398_masked_write(chip, PERPH0_SSUPPLY_CFG0_REG, + EN_HV_OV_OPTION2_BIT | EN_MV_OV_OPTION2_BIT, + EN_HV_OV_OPTION2_BIT); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set PERPH0_SSUPPLY_CFG0_REG rc=%d\n", rc); + return rc; + } + + rc = smb1398_masked_write(chip, PERPH1_LOCK_SPARE_REG, + CFG_LOCK_SPARE1_MASK, + OVP_14V << CFG_LOCK_SPARE1_SHIFT); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set PERPH1_LOCK_SPARE_REG rc=%d\n", rc); + return rc; + } + + return 0; +} + static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) { int rc = 0; + rc = smb1398_update_ovp(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't update OVP threshold rc=%d\n", rc); + return rc; + } + /* Configure window (Vin/2 - Vout) OV level to 500mV */ rc = smb1398_masked_write(chip, DIV2_PROTECTION_REG, DIV2_WIN_OV_SEL_MASK, WIN_OV_500_MV); @@ -1834,6 +1908,14 @@ static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) return rc; } + /* Configure window (Vin/2 - Vout) UV level to 10mV */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + DIV2_WIN_UV_SEL_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc); + return rc; + } + /* Configure master TEMP pin to output Vtemp signal by default */ rc = smb1398_masked_write(chip, SSUPLY_TEMP_CTRL_REG, SEL_OUT_TEMP_MAX_MASK, SEL_OUT_VTEMP); @@ -1874,6 +1956,14 @@ static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) return rc; } + /* Do not disable FP_FET during IREV conditions */ + rc = smb1398_masked_write(chip, MISC_CFG0_REG, CFG_DIS_FPF_IREV_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_DIS_FPF_IREV_BIT, rc=%d\n", + rc); + return rc; + } + /* switcher enable controlled by register */ rc = smb1398_masked_write(chip, MISC_CFG0_REG, SW_EN_SWITCHER_BIT, SW_EN_SWITCHER_BIT); @@ -2146,6 +2236,12 @@ static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip) int rc; u8 status; + rc = smb1398_update_ovp(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't update OVP threshold rc=%d\n", rc); + return rc; + } + rc = smb1398_read(chip, MODE_STATUS_REG, &status); if (rc < 0) { dev_err(chip->dev, "Couldn't read slave MODE_STATUS_REG, rc=%d\n", @@ -2153,6 +2249,14 @@ static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip) return rc; } + /* Configure window (Vin/2 - Vout) UV level to 10mV */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + DIV2_WIN_UV_SEL_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc); + return rc; + } + /* * Disable slave WIN_UV detection, otherwise slave might not be * enabled due to WIN_UV until master drawing very high current. @@ -2191,6 +2295,15 @@ static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip) return rc; } + /* Enable slave clock on its own */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + EN_SLAVE_OWN_FREQ_BIT, EN_SLAVE_OWN_FREQ_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable slave clock, rc=%d\n", + rc); + return rc; + } + rc = smb1398_init_div2_cp_slave_psy(chip); if (rc < 0) { dev_err(chip->dev, "Initial div2_cp_slave_psy failed, rc=%d\n", diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index ea3f74aa578bf9c90622096c1bf9bcdaaa8acf22..1b9d586c2ecd27231e497e96e6ff07ce4051e3a6 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1337,6 +1337,7 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count) #define USBIN_150MA 150000 #define USBIN_500MA 500000 #define USBIN_900MA 900000 +#define USBIN_1000MA 1000000 static int set_sdp_current(struct smb_charger *chg, int icl_ua) { int rc; @@ -3798,6 +3799,24 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg, return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); } +int smblib_get_prop_input_current_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + int icl_ua = 0, rc; + + rc = smblib_get_charge_param(chg, &chg->param.usb_icl, &icl_ua); + if (rc < 0) + return rc; + + if (is_override_vote_enabled_locked(chg->usb_icl_votable) && + icl_ua < USBIN_1000MA) { + val->intval = USBIN_1000MA; + return 0; + } + + return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); +} + int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, union power_supply_propval *val) { diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index de04a7ab4a0671dd1651d047c6a3bd8c5d637fe9..0a06c4b95e65409296b21d7d542ce75616e097b5 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -755,6 +755,8 @@ int smblib_get_prop_charger_temp(struct smb_charger *chg, int smblib_get_prop_die_health(struct smb_charger *chg); int smblib_get_prop_smb_health(struct smb_charger *chg); int smblib_get_prop_connector_health(struct smb_charger *chg); +int smblib_get_prop_input_current_max(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_thermal_overheat(struct smb_charger *chg, int therm_overheat); int smblib_get_skin_temp_status(struct smb_charger *chg); diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index db001cba937fd8617fc81720e21c30601f2bfec5..e340ad79a1ec95c060af20691832a346c1b49e26 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -166,6 +166,7 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &bcm2835_pwm_ops; + pc->chip.base = -1; pc->chip.npwm = 2; pc->chip.of_xlate = of_pwm_xlate_with_flags; pc->chip.of_pwm_n_cells = 3; diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 5ad42f33e70c11d8efd0ef4a545f01bf948e3c76..2e15acf13893d98cde13b1bc972a9ef4e33ca370 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -337,6 +337,11 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) static int pwm_omap_dmtimer_remove(struct platform_device *pdev) { struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev); + int ret; + + ret = pwmchip_remove(&omap->chip); + if (ret) + return ret; if (pm_runtime_active(&omap->dm_timer_pdev->dev)) omap->pdata->stop(omap->dm_timer); @@ -345,7 +350,7 @@ static int pwm_omap_dmtimer_remove(struct platform_device *pdev) mutex_destroy(&omap->mutex); - return pwmchip_remove(&omap->chip); + return 0; } static const struct of_device_id pwm_omap_dmtimer_of_match[] = { diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 567f5e2771c47288488063f49363fd3e0b4eaab7..259fd58812aed13f293c52105ec415a6f48ca12c 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -31,6 +31,7 @@ #include #include #include +#include /* * Because the PCA9685 has only one prescaler per chip, changing the period of @@ -85,6 +86,7 @@ struct pca9685 { #if IS_ENABLED(CONFIG_GPIOLIB) struct mutex lock; struct gpio_chip gpio; + DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1); #endif }; @@ -94,51 +96,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip) } #if IS_ENABLED(CONFIG_GPIOLIB) -static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset) +static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx) { - struct pca9685 *pca = gpiochip_get_data(gpio); - struct pwm_device *pwm; + bool is_inuse; mutex_lock(&pca->lock); - - pwm = &pca->chip.pwms[offset]; - - if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) { - mutex_unlock(&pca->lock); - return -EBUSY; + if (pwm_idx >= PCA9685_MAXCHAN) { + /* + * "all LEDs" channel: + * pretend already in use if any of the PWMs are requested + */ + if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) { + is_inuse = true; + goto out; + } + } else { + /* + * regular channel: + * pretend already in use if the "all LEDs" channel is requested + */ + if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) { + is_inuse = true; + goto out; + } } - - pwm_set_chip_data(pwm, (void *)1); - + is_inuse = test_and_set_bit(pwm_idx, pca->pwms_inuse); +out: mutex_unlock(&pca->lock); - pm_runtime_get_sync(pca->chip.dev); - return 0; + return is_inuse; } -static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm) +static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx) { - bool is_gpio = false; - mutex_lock(&pca->lock); + clear_bit(pwm_idx, pca->pwms_inuse); + mutex_unlock(&pca->lock); +} - if (pwm->hwpwm >= PCA9685_MAXCHAN) { - unsigned int i; - - /* - * Check if any of the GPIOs are requested and in that case - * prevent using the "all LEDs" channel. - */ - for (i = 0; i < pca->gpio.ngpio; i++) - if (gpiochip_is_requested(&pca->gpio, i)) { - is_gpio = true; - break; - } - } else if (pwm_get_chip_data(pwm)) { - is_gpio = true; - } +static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset) +{ + struct pca9685 *pca = gpiochip_get_data(gpio); - mutex_unlock(&pca->lock); - return is_gpio; + if (pca9685_pwm_test_and_set_inuse(pca, offset)) + return -EBUSY; + pm_runtime_get_sync(pca->chip.dev); + return 0; } static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset) @@ -170,13 +172,10 @@ static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset, static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset) { struct pca9685 *pca = gpiochip_get_data(gpio); - struct pwm_device *pwm; pca9685_pwm_gpio_set(gpio, offset, 0); pm_runtime_put(pca->chip.dev); - mutex_lock(&pca->lock); - pwm = &pca->chip.pwms[offset]; - mutex_unlock(&pca->lock); + pca9685_pwm_clear_inuse(pca, offset); } static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip, @@ -228,12 +227,17 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca) return devm_gpiochip_add_data(dev, &pca->gpio, pca); } #else -static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca, - struct pwm_device *pwm) +static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, + int pwm_idx) { return false; } +static inline void +pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx) +{ +} + static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca) { return 0; @@ -417,7 +421,7 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct pca9685 *pca = to_pca(chip); - if (pca9685_pwm_is_gpio(pca, pwm)) + if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm)) return -EBUSY; pm_runtime_get_sync(chip->dev); @@ -426,8 +430,11 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { + struct pca9685 *pca = to_pca(chip); + pca9685_pwm_disable(chip, pwm); pm_runtime_put(chip->dev); + pca9685_pwm_clear_inuse(pca, pwm->hwpwm); } static const struct pwm_ops pca9685_pwm_ops = { diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 0fcf94ffad321d8bb10911c6cdb65eebd8c8161b..c298bec25a90a30670845bc17cb0316e7112f99d 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -236,24 +236,28 @@ static int rcar_pwm_probe(struct platform_device *pdev) rcar_pwm->chip.base = -1; rcar_pwm->chip.npwm = 1; + pm_runtime_enable(&pdev->dev); + ret = pwmchip_add(&rcar_pwm->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret); + pm_runtime_disable(&pdev->dev); return ret; } - pm_runtime_enable(&pdev->dev); - return 0; } static int rcar_pwm_remove(struct platform_device *pdev) { struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev); + int ret; + + ret = pwmchip_remove(&rcar_pwm->chip); pm_runtime_disable(&pdev->dev); - return pwmchip_remove(&rcar_pwm->chip); + return ret; } static const struct of_device_id rcar_pwm_of_table[] = { diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index 29267d12fb4c9d3cf9283c38b114b00430704b09..9c7962f2f0aa4c058f497c58e9107e02e18168cf 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -423,16 +423,17 @@ static int tpu_probe(struct platform_device *pdev) tpu->chip.base = -1; tpu->chip.npwm = TPU_CHANNEL_MAX; + pm_runtime_enable(&pdev->dev); + ret = pwmchip_add(&tpu->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to register PWM chip\n"); + pm_runtime_disable(&pdev->dev); return ret; } dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id); - pm_runtime_enable(&pdev->dev); - return 0; } @@ -442,12 +443,10 @@ static int tpu_remove(struct platform_device *pdev) int ret; ret = pwmchip_remove(&tpu->chip); - if (ret) - return ret; pm_runtime_disable(&pdev->dev); - return 0; + return ret; } #ifdef CONFIG_OF diff --git a/drivers/regulator/qcom_pm8008-regulator.c b/drivers/regulator/qcom_pm8008-regulator.c index 3127508154de1de890e88b98898e36989cb4dc18..81aaa56e494e7250af8e7a77aa46c1c221664e71 100644 --- a/drivers/regulator/qcom_pm8008-regulator.c +++ b/drivers/regulator/qcom_pm8008-regulator.c @@ -53,8 +53,6 @@ #define LDO_VSET_LB_REG(base) (base + 0x40) -#define LDO_VSET_VALID_LB_REG(base) (base + 0x42) - #define LDO_MODE_CTL1_REG(base) (base + 0x45) #define MODE_PRIMARY_MASK GENMASK(2, 0) #define LDO_MODE_NPM 7 @@ -156,7 +154,7 @@ static int pm8008_regulator_get_voltage(struct regulator_dev *rdev) int rc; rc = pm8008_read(pm8008_reg->regmap, - LDO_VSET_VALID_LB_REG(pm8008_reg->base), + LDO_VSET_LB_REG(pm8008_reg->base), vset_raw, 2); if (rc < 0) { pm8008_err(pm8008_reg, diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 213b68743cc89bd00571a12e8870a36434dd43cc..92498ac503035c54c3742929fd2978833226fb5d 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -714,7 +714,7 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev, } if (!pdata->dvs_gpio[i]) { - dev_warn(dev, "there is no dvs%d gpio\n", i); + dev_info(dev, "there is no dvs%d gpio\n", i); continue; } diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index eab14b414bf0dda6e7461b7b05246f4842844090..8f4fa1a52f0578c05f6bd3046a90982d65e20453 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -288,7 +288,7 @@ void rproc_free_vring(struct rproc_vring *rvring) { int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); struct rproc *rproc = rvring->rvdev->rproc; - int idx = rvring->rvdev->vring - rvring; + int idx = rvring - rvring->rvdev->vring; struct fw_rsc_vdev *rsc; dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); @@ -1620,7 +1620,7 @@ static int __init remoteproc_init(void) return 0; } -module_init(remoteproc_init); +subsys_initcall(remoteproc_init); static void __exit remoteproc_exit(void) { diff --git a/drivers/rpmsg/qcom_glink_bgcom.c b/drivers/rpmsg/qcom_glink_bgcom.c index 31f9f0cdb47cf08a07779f3d07ab449953167cd1..09318fa0928e44d37c1baf2c180c0299043f480a 100644 --- a/drivers/rpmsg/qcom_glink_bgcom.c +++ b/drivers/rpmsg/qcom_glink_bgcom.c @@ -255,6 +255,7 @@ struct glink_bgcom_channel { struct mutex intent_req_lock; bool intent_req_result; struct completion intent_req_comp; + struct completion intent_alloc_comp; }; struct rx_pkt { @@ -306,6 +307,7 @@ glink_bgcom_alloc_channel(struct glink_bgcom *glink, const char *name) init_completion(&channel->open_req); init_completion(&channel->open_ack); init_completion(&channel->intent_req_comp); + init_completion(&channel->intent_alloc_comp); idr_init(&channel->liids); idr_init(&channel->riids); @@ -325,6 +327,7 @@ static void glink_bgcom_channel_release(struct kref *ref) channel->intent_req_result = 0; complete(&channel->intent_req_comp); + complete(&channel->intent_alloc_comp); mutex_lock(&channel->intent_lock); idr_for_each_entry(&channel->liids, tmp, iid) { @@ -557,6 +560,7 @@ static int glink_bgcom_send_data(struct glink_bgcom_channel *channel, struct glink_bgcom_msg msg; __le32 chunk_size; __le32 left_size; + uint64_t addr; } __packed req; CH_INFO(channel, "chunk:%d, left:%d\n", chunk_size, left_size); @@ -571,6 +575,7 @@ static int glink_bgcom_send_data(struct glink_bgcom_channel *channel, req.msg.param2 = cpu_to_le32(intent->id); req.chunk_size = cpu_to_le32(chunk_size); req.left_size = cpu_to_le32(left_size); + req.addr = 0; mutex_lock(&glink->tx_lock); while (glink_bgcom_tx_avail(glink) < sizeof(req)/WORD_SIZE) { @@ -762,6 +767,7 @@ static int glink_bgcom_request_intent(struct glink_bgcom *glink, mutex_lock(&channel->intent_req_lock); reinit_completion(&channel->intent_req_comp); + reinit_completion(&channel->intent_alloc_comp); req.cmd = cpu_to_le16(BGCOM_CMD_RX_INTENT_REQ); req.param1 = cpu_to_le16(channel->lcid); @@ -775,12 +781,17 @@ static int glink_bgcom_request_intent(struct glink_bgcom *glink, ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); if (!ret) { - dev_err(glink->dev, "intent request timed out\n"); + dev_err(glink->dev, "intent request ack timed out\n"); + ret = -ETIMEDOUT; + } + + ret = wait_for_completion_timeout(&channel->intent_alloc_comp, 10 * HZ); + if (!ret) { + dev_err(glink->dev, "intent request alloc timed out\n"); ret = -ETIMEDOUT; } else { ret = channel->intent_req_result ? 0 : -ECANCELED; } - unlock: mutex_unlock(&channel->intent_req_lock); kref_put(&channel->refcount, glink_bgcom_channel_release); @@ -1814,6 +1825,7 @@ static int glink_bgcom_handle_intent(struct glink_bgcom *glink, dev_err(glink->dev, "failed to store remote intent\n"); } + complete(&channel->intent_alloc_comp); return msglen; } @@ -2004,6 +2016,51 @@ static void glink_bgcom_linkup(struct glink_bgcom *glink) GLINK_ERR(glink, "Failed to link up %d\n", ret); } +static int glink_bgcom_remove_device(struct device *dev, void *data) +{ + device_unregister(dev); + + return 0; +} + +static int glink_bgcom_cleanup(struct glink_bgcom *glink) +{ + struct glink_bgcom_channel *channel; + int cid; + int ret; + + GLINK_INFO(glink, "\n"); + + atomic_set(&glink->in_reset, 1); + + kthread_flush_worker(&glink->kworker); + cancel_work_sync(&glink->rx_defer_work); + + ret = device_for_each_child(glink->dev, NULL, + glink_bgcom_remove_device); + if (ret) + dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); + + mutex_lock(&glink->idr_lock); + /* Release any defunct local channels, waiting for close-ack */ + idr_for_each_entry(&glink->lcids, channel, cid) { + /* Wakeup threads waiting for intent*/ + complete(&channel->intent_req_comp); + kref_put(&channel->refcount, glink_bgcom_channel_release); + idr_remove(&glink->lcids, cid); + } + + /* Release any defunct local channels, waiting for close-req */ + idr_for_each_entry(&glink->rcids, channel, cid) { + kref_put(&channel->refcount, glink_bgcom_channel_release); + idr_remove(&glink->rcids, cid); + } + + mutex_unlock(&glink->idr_lock); + + return ret; +} + static void glink_bgcom_event_handler(void *handle, void *priv_data, enum bgcom_event_type event, union bgcom_event_data_type *data) @@ -2054,7 +2111,7 @@ static void glink_bgcom_event_handler(void *handle, break; case BGCOM_EVENT_RESET_OCCURRED: glink->bgcom_status = BGCOM_RESET; - atomic_set(&glink->in_reset, 1); + glink_bgcom_cleanup(glink); break; case BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN: case BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR: @@ -2183,18 +2240,9 @@ static int glink_bgcom_probe(struct platform_device *pdev) } EXPORT_SYMBOL(glink_bgcom_probe); -static int glink_bgcom_remove_device(struct device *dev, void *data) -{ - device_unregister(dev); - - return 0; -} - static int glink_bgcom_remove(struct platform_device *pdev) { struct glink_bgcom *glink = platform_get_drvdata(pdev); - struct glink_bgcom_channel *channel; - int cid; int ret; GLINK_INFO(glink, "\n"); @@ -2203,30 +2251,11 @@ static int glink_bgcom_remove(struct platform_device *pdev) bgcom_close(glink->bgcom_handle); - kthread_flush_worker(&glink->kworker); - kthread_stop(glink->rx_task); - cancel_work_sync(&glink->rx_defer_work); + ret = glink_bgcom_cleanup(glink); - ret = device_for_each_child(glink->dev, NULL, - glink_bgcom_remove_device); - if (ret) - dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); + kthread_stop(glink->rx_task); mutex_lock(&glink->idr_lock); - /* Release any defunct local channels, waiting for close-ack */ - idr_for_each_entry(&glink->lcids, channel, cid) { - /* Wakeup threads waiting for intent*/ - complete(&channel->intent_req_comp); - kref_put(&channel->refcount, glink_bgcom_channel_release); - idr_remove(&glink->lcids, cid); - } - - /* Release any defunct local channels, waiting for close-req */ - idr_for_each_entry(&glink->rcids, channel, cid) { - kref_put(&channel->refcount, glink_bgcom_channel_release); - idr_remove(&glink->rcids, cid); - } - idr_destroy(&glink->lcids); idr_destroy(&glink->rcids); mutex_unlock(&glink->idr_lock); diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 2b051b54ae4b5f251e2ee62043dc148681e496cc..b138be016ca58128889fc01d634d522a6a708c4b 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -2040,7 +2040,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (vm_support) irqflags = IRQF_TRIGGER_RISING; else - irqflags = IRQF_NO_SUSPEND | IRQF_SHARED; + irqflags = IRQF_SHARED; ret = devm_request_irq(dev, irq, qcom_glink_native_intr, @@ -2053,6 +2053,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, glink->irq = irq; + ret = enable_irq_wake(irq); + if (ret < 0) + dev_err(dev, "enable_irq_wake() failed on %d\n", irq); + size = of_property_count_u32_elems(dev->of_node, "cpu-affinity"); if (size > 0) { arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL); diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 600c3619051cf16c3e675b983bdb5b48c50470c2..71669b6cca6366b79b81136fd7d35c2f78fab0ea 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -231,6 +231,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent, ret = device_register(dev); if (ret) { pr_err("failed to register glink edge\n"); + put_device(dev); kfree(dev); return ERR_PTR(ret); } diff --git a/drivers/rpmsg/rpm-smd.c b/drivers/rpmsg/rpm-smd.c index 9039d1ea1810641c9cc11cca2090daf0ed59fd52..4dc6be8514660913f370d41f840604648b52e261 100644 --- a/drivers/rpmsg/rpm-smd.c +++ b/drivers/rpmsg/rpm-smd.c @@ -707,6 +707,24 @@ static struct msm_rpm_driver_data msm_rpm_data = { .smd_open = COMPLETION_INITIALIZER(msm_rpm_data.smd_open), }; +static int trysend_count = 20; +module_param(trysend_count, int, 0664); +static int msm_rpm_trysend_smd_buffer(char *buf, uint32_t size) +{ + int ret; + int count = 0; + + do { + ret = rpmsg_trysend(rpm->rpm_channel, buf, size); + if (!ret) + break; + udelay(10); + count++; + } while (count < trysend_count); + + return ret; +} + static int msm_rpm_flush_requests(bool print) { struct rb_node *t; @@ -724,7 +742,7 @@ static int msm_rpm_flush_requests(bool print) set_msg_id(s->buf, msm_rpm_get_next_msg_id()); - ret = rpmsg_send(rpm->rpm_channel, s->buf, get_buf_len(s->buf)); + ret = msm_rpm_trysend_smd_buffer(s->buf, get_buf_len(s->buf)); WARN_ON(ret != 0); trace_rpm_smd_send_sleep_set(get_msg_id(s->buf), type, id); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 623fdec0f9c3385491a5751e8d9d5ae6c635ca6d..acae8d23731f905f13f63a51453c343536fe9a13 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -323,6 +323,7 @@ config RTC_DRV_MAX6900 config RTC_DRV_MAX8907 tristate "Maxim MAX8907" depends on MFD_MAX8907 || COMPILE_TEST + select REGMAP_IRQ help If you say yes here you will get support for the RTC of Maxim MAX8907 PMIC. diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 7d3e5168fcefcdb1ad637e9091cb16e3e2893e20..efbbde7379f13e9130c90310321508e73bb39056 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -341,6 +341,10 @@ static int pm860x_rtc_probe(struct platform_device *pdev) info->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, info); + info->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(info->rtc_dev)) + return PTR_ERR(info->rtc_dev); + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, rtc_update_handler, IRQF_ONESHOT, "rtc", info); @@ -382,13 +386,11 @@ static int pm860x_rtc_probe(struct platform_device *pdev) } } - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm860x-rtc", - &pm860x_rtc_ops, THIS_MODULE); - ret = PTR_ERR(info->rtc_dev); - if (IS_ERR(info->rtc_dev)) { - dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + info->rtc_dev->ops = &pm860x_rtc_ops; + + ret = rtc_register_device(info->rtc_dev); + if (ret) return ret; - } /* * enable internal XO instead of internal 3.25MHz clock since it can diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 9dca53df35845cc64366a5428d9927bff7f28220..5b7c16b85dc08c944969ed5a0bb66a4042bf1fc1 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -806,7 +806,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = cmos_interrupt; retval = request_irq(rtc_irq, rtc_cmos_int_handler, - IRQF_SHARED, dev_name(&cmos_rtc.rtc->dev), + 0, dev_name(&cmos_rtc.rtc->dev), cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index e5ad527cb75e369945a7a533105d6d0d8573ac10..a8c2d38b24112f53b9e7561c9843ab3deca86db7 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -105,7 +105,7 @@ static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) if (!hym8563->valid) { dev_warn(&client->dev, "no valid clock/calendar values available\n"); - return -EPERM; + return -EINVAL; } ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index ae6506a8b4f5c8725536cbd5f69d4db934fd0d2e..b25a2ba5ac483843568ff084daffc992afcb356d 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -559,9 +559,7 @@ static const struct pinctrl_ops rtc_pinctrl_ops = { .dt_free_map = pinconf_generic_dt_free_map, }; -enum rtc_pin_config_param { - PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1, -}; +#define PIN_CONFIG_ACTIVE_HIGH (PIN_CONFIG_END + 1) static const struct pinconf_generic_params rtc_params[] = { {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 2a3f874a21d548ef6a04bca6e3a8955f3668d291..9cebff8e8d74001f38f0148cf9118a163f2a1c37 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -303,8 +303,10 @@ static void * cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) { struct ccwdev_iter *iter; + loff_t p = *offset; - if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) + (*offset)++; + if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) return NULL; iter = it; if (iter->devno == __MAX_SUBCHANNEL) { @@ -314,7 +316,6 @@ cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) return NULL; } else iter->devno++; - (*offset)++; return iter; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e5c32f4b5287ebc4da569d403475d5624bac43ef..d2203cd1781382f234886bae21ce146b877d293d 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -828,8 +828,10 @@ static void io_subchannel_register(struct ccw_device *cdev) * Now we know this subchannel will stay, we can throw * our delayed uevent. */ - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + if (dev_get_uevent_suppress(&sch->dev)) { + dev_set_uevent_suppress(&sch->dev, 0); + kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + } /* make it known to the system */ ret = ccw_device_add(cdev); if (ret) { @@ -1037,8 +1039,11 @@ static int io_subchannel_probe(struct subchannel *sch) * Throw the delayed uevent for the subchannel, register * the ccw_device and exit. */ - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + if (dev_get_uevent_suppress(&sch->dev)) { + /* should always be the case for the console */ + dev_set_uevent_suppress(&sch->dev, 0); + kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + } cdev = sch_get_cdev(sch); rc = ccw_device_add(cdev); if (rc) { diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 8f90e4cea2545faef39920f0762f7355ded6989a..168f7c84edba38067d9b86bbd21ee5adc0d06c25 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -747,7 +747,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) adapter->peer_d_id); if (IS_ERR(port)) /* error or port already attached */ return; - _zfcp_erp_port_reopen(port, 0, "ereptp1"); + zfcp_erp_port_reopen(port, 0, "ereptp1"); } static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 381846164003129458d4bab4020587f4276c67f6..fdbb0a3dc9b4f27298968c8043844aff83b7f8f2 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -2321,7 +2321,7 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, * At some speeds, we only support * ST transfers. */ - if ((syncrate->sxfr_u2 & ST_SXFR) != 0) + if ((syncrate->sxfr_u2 & ST_SXFR) != 0) *ppr_options &= ~MSG_EXT_PPR_DT_REQ; break; } diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index e09c7f360dbde90d0b8eb54c8509956c8d93012a..0cb585759de6ae3da041da0b9fdb7c729508881a 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -1383,7 +1383,7 @@ csio_device_reset(struct device *dev, return -EINVAL; /* Delete NPIV lnodes */ - csio_lnodes_exit(hw, 1); + csio_lnodes_exit(hw, 1); /* Block upper IOs */ csio_lnodes_block_request(hw); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 35d54ee1c5c74464526f8b56c25c46efb6c9404e..b172f0a02083491382e8c72d0edc95cc06c131cf 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -9962,6 +9962,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, ioa_cfg->max_devs_supported = ipr_max_devs; if (ioa_cfg->sis64) { + host->max_channel = IPR_MAX_SIS64_BUSES; host->max_id = IPR_MAX_SIS64_TARGETS_PER_BUS; host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET; if (ipr_max_devs > IPR_MAX_SIS64_DEVS) @@ -9970,6 +9971,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, + ((sizeof(struct ipr_config_table_entry64) * ioa_cfg->max_devs_supported))); } else { + host->max_channel = IPR_VSET_BUS; host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS; host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET; if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS) @@ -9979,7 +9981,6 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, * ioa_cfg->max_devs_supported))); } - host->max_channel = IPR_VSET_BUS; host->unique_id = host->host_no; host->max_cmd_len = IPR_MAX_CDB_LEN; host->can_queue = ioa_cfg->max_cmds; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 085e6c90f9e6a3255469757c2d6febbaa0d66e25..89b36987ff309f6fa08e410d1d918628281445ea 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1306,6 +1306,7 @@ struct ipr_resource_entry { #define IPR_ARRAY_VIRTUAL_BUS 0x1 #define IPR_VSET_VIRTUAL_BUS 0x2 #define IPR_IOAFP_VIRTUAL_BUS 0x3 +#define IPR_MAX_SIS64_BUSES 0x4 #define IPR_GET_RES_PHYS_LOC(res) \ (((res)->bus << 24) | ((res)->target << 8) | (res)->lun) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7e3a77d3c6f018d62a2fd5b196c1373155bf0f33..e3ca16043f9af459d94c7cd5ece0360c0b045594 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -890,6 +890,10 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session) { struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct iscsi_session *session = cls_session->dd_data; + + if (WARN_ON_ONCE(session->leadconn)) + return; iscsi_tcp_r2tpool_free(cls_session->dd_data); iscsi_session_teardown(cls_session); diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index bb9c1c01664390a31ddb7fd225825467bf95f134..28b50ab2fbb015e856e3595d862f4927b925363b 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -652,6 +652,8 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, } out: kref_put(&rdata->kref, fc_rport_destroy); + if (!IS_ERR(fp)) + fc_frame_free(fp); } /** diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index af937b91765e60d1cd8f1f8c9c18e4d5b2725b63..fcf4b4175d771a4711154f4c8ee55ba1f1fd2aeb 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1591,8 +1591,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Declare and initialization an instance of the FC NVME template. */ static struct nvme_fc_port_template lpfc_nvme_template = { - .module = THIS_MODULE, - /* initiator-based functions */ .localport_delete = lpfc_nvme_localport_delete, .remoteport_delete = lpfc_nvme_remoteport_delete, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d8e0ba68879c3ca162cf8ef4d992f60e75d78038..480d2d467f7a68d906b6f8e052e14b975128a186 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2271,6 +2271,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) !pmb->u.mb.mbxStatus) { rpi = pmb->u.mb.un.varWords[0]; vpi = pmb->u.mb.un.varRegLogin.vpi; + if (phba->sli_rev == LPFC_SLI_REV4) + vpi -= phba->sli4_hba.max_cfg_param.vpi_base; lpfc_unreg_login(phba, vpi, rpi, pmb); pmb->vport = vport; pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 6abad63b127affa0a9d352f98cfc0569f5e9d804..42d876034741c7524dd5cab37286c92914e61b81 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4109,7 +4109,8 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) { if (instance->adapter_type == MFI_SERIES) return KILL_ADAPTER; else if (instance->unload || - test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags)) + test_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, + &instance->reset_flags)) return IGNORE_TIMEOUT; else return INITIATE_OCR; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 7be2b9e1133296dce7070170722791612520234b..b13721290f4b1ffdb004c410477ca9765a2be903 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -4212,6 +4212,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); + set_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags); atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING); instance->instancet->disable_intr(instance); megasas_sync_irqs((unsigned long)instance); @@ -4399,7 +4400,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); } out: - clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); + clear_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags); mutex_unlock(&instance->reset_mutex); return retval; } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 7c1f7ccf031dac522b3e2594f80843ab9a39f131..40724df20780ab47b34017317300386fdc635e69 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -100,6 +100,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 +#define MEGASAS_FUSION_OCR_NOT_POSSIBLE 1 #define THRESHOLD_REPLY_COUNT 50 #define RAID_1_PEER_CMDS 2 #define JBOD_MAPS_COUNT 2 diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5fb87cfac84dc0c9918eed7c2259faf102d70ab7..ac6870a56401febdfca47cdda4e79b705c2be142 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -8280,8 +8280,8 @@ static void scsih_remove(struct pci_dev *pdev) ioc->remove_host = 1; - mpt3sas_wait_for_commands_to_complete(ioc); - _scsih_flush_running_cmds(ioc); + if (!pci_device_is_present(pdev)) + _scsih_flush_running_cmds(ioc); _scsih_fw_event_cleanup_queue(ioc); @@ -8354,8 +8354,8 @@ scsih_shutdown(struct pci_dev *pdev) ioc->remove_host = 1; - mpt3sas_wait_for_commands_to_complete(ioc); - _scsih_flush_running_cmds(ioc); + if (!pci_device_is_present(pdev)) + _scsih_flush_running_cmds(ioc); _scsih_fw_event_cleanup_queue(ioc); diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 3e9dc54b89a32f1704e4d68569d667ee673d34e4..91e185731b1ee28440bebb2d65f52ea371499751 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -2517,12 +2517,6 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) /* Driver Debug Functions. */ /****************************************************************************/ -static inline int -ql_mask_match(uint32_t level) -{ - return (level & ql2xextended_error_logging) == level; -} - /* * This function is for formatting and logging debug information. * It is to be used when vha is available. It formats the message diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 8877aa97d829f00ba72a9ae29e27c98ac6b7afdd..ceca6dd34db12f8e5ae1c4ae32258b706afdcdbb 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -374,3 +374,9 @@ extern int qla24xx_dump_ram(struct qla_hw_data *, uint32_t, uint32_t *, extern void qla24xx_pause_risc(struct device_reg_24xx __iomem *, struct qla_hw_data *); extern int qla24xx_soft_reset(struct qla_hw_data *); + +static inline int +ql_mask_match(uint level) +{ + return (level & ql2xextended_error_logging) == level; +} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 648916a9082c09ad8041b7712bebb362e2f95bd8..b39faf2bfa0db82b0590cd2acfd556da6f7ef33f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1853,6 +1853,18 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) inbuf = (uint32_t *)&sts->nvme_ersp_data; outbuf = (uint32_t *)fd->rspaddr; iocb->u.nvme.rsp_pyld_len = le16_to_cpu(sts->nvme_rsp_pyld_len); + if (unlikely(iocb->u.nvme.rsp_pyld_len > + sizeof(struct nvme_fc_ersp_iu))) { + if (ql_mask_match(ql_dbg_io)) { + WARN_ONCE(1, "Unexpected response payload length %u.\n", + iocb->u.nvme.rsp_pyld_len); + ql_log(ql_log_warn, fcport->vha, 0x5100, + "Unexpected response payload length %u.\n", + iocb->u.nvme.rsp_pyld_len); + } + iocb->u.nvme.rsp_pyld_len = + sizeof(struct nvme_fc_ersp_iu); + } iter = iocb->u.nvme.rsp_pyld_len >> 2; for (; iter; iter--) *outbuf++ = swab32(*inbuf++); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 459481ce5872d97822d764022b80d74f9dc8224f..5e8ae510aef80f1d4e608131bbaad988c5400007 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -5853,9 +5853,8 @@ qla2x00_dump_mctp_data(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr, mcp->mb[7] = LSW(MSD(req_dma)); mcp->mb[8] = MSW(addr); /* Setting RAM ID to valid */ - mcp->mb[10] |= BIT_7; /* For MCTP RAM ID is 0x40 */ - mcp->mb[10] |= 0x40; + mcp->mb[10] = BIT_7 | 0x40; mcp->out_mb |= MBX_10|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1| MBX_0; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 7dceed02123617a12bbf0de47e3517aed0087c55..6b33a1f24f56169a3a17803e5a6952da2e6445a6 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -578,7 +578,6 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) } static struct nvme_fc_port_template qla_nvme_fc_transport = { - .module = THIS_MODULE, .localport_delete = qla_nvme_localport_delete, .remoteport_delete = qla_nvme_remoteport_delete, .create_queue = qla_nvme_alloc_queue, diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index a77c33987703678e07f05022c0fcd67844c09de8..a5b8313cf4916096f7c533570adf50a87a0a0943 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1605,8 +1605,7 @@ qla82xx_get_bootld_offset(struct qla_hw_data *ha) return (u8 *)&ha->hablob->fw->data[offset]; } -static __le32 -qla82xx_get_fw_size(struct qla_hw_data *ha) +static u32 qla82xx_get_fw_size(struct qla_hw_data *ha) { struct qla82xx_uri_data_desc *uri_desc = NULL; @@ -1617,7 +1616,7 @@ qla82xx_get_fw_size(struct qla_hw_data *ha) return cpu_to_le32(uri_desc->size); } - return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]); + return get_unaligned_le32(&ha->hablob->fw->data[FW_SIZE_OFFSET]); } static u8 * @@ -1808,7 +1807,7 @@ qla82xx_fw_load_from_blob(struct qla_hw_data *ha) } flashaddr = FLASH_ADDR_START; - size = (__force u32)qla82xx_get_fw_size(ha) / 8; + size = qla82xx_get_fw_size(ha) / 8; ptr64 = (u64 *)qla82xx_get_fw_offs(ha); for (i = 0; i < size; i++) { diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5f9d4dbc4a98e6806b86a2f8a27e57101498fff3..d4024015f859f1b6183d71c51fca502acc0386e7 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3178,6 +3178,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) base_vha->mgmt_svr_loop_id, host->sg_tablesize); ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); + if (unlikely(!ha->wq)) { + ret = -ENOMEM; + goto probe_failed; + } if (ha->mqenable) { bool mq = false; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index b0ad60565fe943fa5ca41a3d8086f9c58ac3ebc7..fb3abaf817a35f9cec55f99c5bdbdb1aaf6247f8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -4150,7 +4150,7 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, ha->queues_dma); - if (ha->fw_dump) + if (ha->fw_dump) vfree(ha->fw_dump); ha->queues_len = 0; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e29a46abfd4fbd15c97920cda6efb9c994f1261a..2adab19052d0f58894ea97bd638e48310b4c72d6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2172,8 +2172,6 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) if (!shost->use_clustering) q->limits.cluster = 0; - if (shost->inlinecrypt_support) - queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); /* * Set a reasonable default alignment: The larger of 32-byte (dword), * which is a common minimum for HBAs, and the minimum DMA alignment, diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 95d71e301a53420b72f92aee0e2580fed3deb339..9589015234693441f82dcb33e3ff2e7b984ccf5b 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2010,7 +2010,7 @@ static void __iscsi_unbind_session(struct work_struct *work) if (session->target_id == ISCSI_MAX_TARGET) { spin_unlock_irqrestore(&session->lock, flags); mutex_unlock(&ihost->mutex); - return; + goto unbind_session_exit; } target_id = session->target_id; @@ -2022,6 +2022,8 @@ static void __iscsi_unbind_session(struct work_struct *work) ida_simple_remove(&iscsi_sess_ida, target_id); scsi_remove_target(&session->dev); + +unbind_session_exit: iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); } @@ -2945,6 +2947,24 @@ iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) return err; } +static int iscsi_session_has_conns(int sid) +{ + struct iscsi_cls_conn *conn; + unsigned long flags; + int found = 0; + + spin_lock_irqsave(&connlock, flags); + list_for_each_entry(conn, &connlist, conn_list) { + if (iscsi_conn_get_sid(conn) == sid) { + found = 1; + break; + } + } + spin_unlock_irqrestore(&connlock, flags); + + return found; +} + static int iscsi_set_iface_params(struct iscsi_transport *transport, struct iscsi_uevent *ev, uint32_t len) @@ -3522,10 +3542,12 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); - if (session) - transport->destroy_session(session); - else + if (!session) err = -EINVAL; + else if (iscsi_session_has_conns(ev->u.d_session.sid)) + err = -EBUSY; + else + transport->destroy_session(session); break; case ISCSI_UEVENT_UNBIND_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 22025a5818dd010b312521284253169f475d42c2..489737392c37c93d8fc50d30cb3f8b8c0b3f408b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3120,12 +3120,14 @@ static int sd_revalidate_disk(struct gendisk *disk) dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks); q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max); - if (sd_validate_opt_xfer_size(sdkp, dev_max)) + if (sd_validate_opt_xfer_size(sdkp, dev_max)) { rw_max = q->limits.io_opt = sdkp->opt_xfer_blocks * sdp->sector_size; - else + } else { + q->limits.io_opt = 0; rw_max = min_not_zero(logical_to_sectors(sdp, dev_max), (sector_t)BLK_DEF_MAX_SECTORS); + } /* Do not exceed controller limit */ rw_max = min(rw_max, queue_max_hw_sectors(q)); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6dc7f6150c131c00778920e020a3852e0cfc77f2..8d6b13827c3906864c738f127acd75e370045984 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -809,8 +809,10 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, "sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) cmnd[0], (int) hp->cmd_len)); - if (hp->dxfer_len >= SZ_256M) + if (hp->dxfer_len >= SZ_256M) { + sg_remove_request(sfp, srp); return -EINVAL; + } k = sg_start_req(srp, cmnd); if (k) { diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index a3c906c78a69bf615fa569ca55ee64444f342ec1..8fa2313508ea41d135f36795f240a65105333975 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -101,19 +101,6 @@ config SCSI_UFS_QCOM Select this if you have UFS controller on QCOM chipset. If unsure, say N. -config SCSI_UFS_QCOM_ICE - bool "QCOM specific hooks to Inline Crypto Engine for UFS driver" - depends on SCSI_UFS_QCOM && CRYPTO_DEV_QCOM_ICE - help - This selects the QCOM specific additions to support Inline Crypto - Engine (ICE). - ICE accelerates the crypto operations and maintains the high UFS - performance. - - Select this if you have ICE supported for UFS on QCOM chipset. - If unsure, say N. - - config SCSI_UFS_TEST tristate "Universal Flash Storage host controller driver unit-tests" depends on SCSI_UFSHCD && IOSCHED_TEST @@ -135,3 +122,20 @@ config SCSI_UFSHCD_CMD_LOGGING Select this if you want above mentioned debug information captured. If unsure, say N. + +config SCSI_UFS_CRYPTO + bool "UFS Crypto Engine Support" + depends on SCSI_UFSHCD && BLK_INLINE_ENCRYPTION + help + Enable Crypto Engine Support in UFS. + Enabling this makes it possible for the kernel to use the crypto + capabilities of the UFS device (if present) to perform crypto + operations on data being transferred to/from the device. + +config SCSI_UFS_CRYPTO_QTI + tristate "Vendor specific UFS Crypto Engine Support" + depends on SCSI_UFS_CRYPTO + help + Enable Vendor Crypto Engine Support in UFS + Enabling this allows kernel to use UFS crypto operations defined + and implemented by QTI. diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 935b34a2fa0bfa8532cdb957aba01f998fa67f77..fe4c092c006b9b13b81093503a996d75c9e72ddd 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -3,9 +3,11 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o -obj-$(CONFIG_SCSI_UFS_QCOM_ICE) += ufs-qcom-ice.o -obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o +obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o +ufshcd-core-y := ufshcd.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o obj-$(CONFIG_DEBUG_FS) += ufs-debugfs.o ufs-qcom-debugfs.o +ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o +ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO_QTI) += ufshcd-crypto-qti.o diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c deleted file mode 100644 index 8bb1f54455d1a989b75ac4244e6069d65a9ff19f..0000000000000000000000000000000000000000 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ /dev/null @@ -1,777 +0,0 @@ -/* - * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include "ufshcd.h" -#include "ufs-qcom-ice.h" -#include "ufs-qcom-debugfs.h" - -#define UFS_QCOM_CRYPTO_LABEL "ufs-qcom-crypto" -/* Timeout waiting for ICE initialization, that requires TZ access */ -#define UFS_QCOM_ICE_COMPLETION_TIMEOUT_MS 500 - -#define UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN 0 - -static struct workqueue_struct *ice_workqueue; - -static void ufs_qcom_ice_dump_regs(struct ufs_qcom_host *qcom_host, int offset, - int len, char *prefix) -{ - print_hex_dump(KERN_ERR, prefix, - len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE, - 16, 4, qcom_host->hba->mmio_base + offset, len * 4, - false); -} - -void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host) -{ - int i; - - if (!(qcom_host->dbg_print_en & UFS_QCOM_DBG_PRINT_ICE_REGS_EN)) - return; - - ufs_qcom_ice_dump_regs(qcom_host, REG_UFS_QCOM_ICE_CFG, 1, - "REG_UFS_QCOM_ICE_CFG "); - for (i = 0; i < NUM_QCOM_ICE_CTRL_INFO_n_REGS; i++) { - pr_err("REG_UFS_QCOM_ICE_CTRL_INFO_1_%d = 0x%08X\n", i, - ufshcd_readl(qcom_host->hba, - (REG_UFS_QCOM_ICE_CTRL_INFO_1_n + 8 * i))); - - pr_err("REG_UFS_QCOM_ICE_CTRL_INFO_2_%d = 0x%08X\n", i, - ufshcd_readl(qcom_host->hba, - (REG_UFS_QCOM_ICE_CTRL_INFO_2_n + 8 * i))); - } - - if (qcom_host->ice.pdev && qcom_host->ice.vops && - qcom_host->ice.vops->debug) - qcom_host->ice.vops->debug(qcom_host->ice.pdev); -} - -static void ufs_qcom_ice_error_cb(void *host_ctrl, u32 error) -{ - struct ufs_qcom_host *qcom_host = (struct ufs_qcom_host *)host_ctrl; - - dev_err(qcom_host->hba->dev, "%s: Error in ice operation 0x%x", - __func__, error); - - if (qcom_host->ice.state == UFS_QCOM_ICE_STATE_ACTIVE) - qcom_host->ice.state = UFS_QCOM_ICE_STATE_DISABLED; -} - -static struct platform_device *ufs_qcom_ice_get_pdevice(struct device *ufs_dev) -{ - struct device_node *node; - struct platform_device *ice_pdev = NULL; - - node = of_parse_phandle(ufs_dev->of_node, UFS_QCOM_CRYPTO_LABEL, 0); - - if (!node) { - dev_err(ufs_dev, "%s: ufs-qcom-crypto property not specified\n", - __func__); - goto out; - } - - ice_pdev = qcom_ice_get_pdevice(node); -out: - return ice_pdev; -} - -static -struct qcom_ice_variant_ops *ufs_qcom_ice_get_vops(struct device *ufs_dev) -{ - struct qcom_ice_variant_ops *ice_vops = NULL; - struct device_node *node; - - node = of_parse_phandle(ufs_dev->of_node, UFS_QCOM_CRYPTO_LABEL, 0); - - if (!node) { - dev_err(ufs_dev, "%s: ufs-qcom-crypto property not specified\n", - __func__); - goto out; - } - - ice_vops = qcom_ice_get_variant_ops(node); - - if (!ice_vops) - dev_err(ufs_dev, "%s: invalid ice_vops\n", __func__); - - of_node_put(node); -out: - return ice_vops; -} - -/** - * ufs_qcom_ice_get_dev() - sets pointers to ICE data structs in UFS QCom host - * @qcom_host: Pointer to a UFS QCom internal host structure. - * - * Sets ICE platform device pointer and ICE vops structure - * corresponding to the current UFS device. - * - * Return: -EINVAL in-case of invalid input parameters: - * qcom_host, qcom_host->hba or qcom_host->hba->dev - * -ENODEV in-case ICE device is not required - * -EPROBE_DEFER in-case ICE is required and hasn't been probed yet - * 0 otherwise - */ -int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host) -{ - struct device *ufs_dev; - int err = 0; - - if (!qcom_host || !qcom_host->hba || !qcom_host->hba->dev) { - pr_err("%s: invalid qcom_host %p or qcom_host->hba or qcom_host->hba->dev\n", - __func__, qcom_host); - err = -EINVAL; - goto out; - } - - ufs_dev = qcom_host->hba->dev; - - qcom_host->ice.vops = ufs_qcom_ice_get_vops(ufs_dev); - qcom_host->ice.pdev = ufs_qcom_ice_get_pdevice(ufs_dev); - - if (qcom_host->ice.pdev == ERR_PTR(-EPROBE_DEFER)) { - dev_err(ufs_dev, "%s: ICE device not probed yet\n", - __func__); - qcom_host->ice.pdev = NULL; - qcom_host->ice.vops = NULL; - err = -EPROBE_DEFER; - goto out; - } - - if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { - dev_err(ufs_dev, "%s: invalid platform device %p or vops %p\n", - __func__, qcom_host->ice.pdev, qcom_host->ice.vops); - qcom_host->ice.pdev = NULL; - qcom_host->ice.vops = NULL; - err = -ENODEV; - goto out; - } - - qcom_host->ice.state = UFS_QCOM_ICE_STATE_DISABLED; - -out: - return err; -} - -static void ufs_qcom_ice_cfg_work(struct work_struct *work) -{ - unsigned long flags; - struct ufs_qcom_host *qcom_host = - container_of(work, struct ufs_qcom_host, ice_cfg_work); - - if (!qcom_host->ice.vops->config_start) - return; - - spin_lock_irqsave(&qcom_host->ice_work_lock, flags); - if (!qcom_host->req_pending || - ufshcd_is_shutdown_ongoing(qcom_host->hba)) { - qcom_host->work_pending = false; - spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); - return; - } - spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); - - /* - * config_start is called again as previous attempt returned -EAGAIN, - * this call shall now take care of the necessary key setup. - */ - qcom_host->ice.vops->config_start(qcom_host->ice.pdev, - qcom_host->req_pending, NULL, false); - - spin_lock_irqsave(&qcom_host->ice_work_lock, flags); - qcom_host->req_pending = NULL; - qcom_host->work_pending = false; - spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); -} - -/** - * ufs_qcom_ice_init() - initializes the ICE-UFS interface and ICE device - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and qcom_host->hba->dev should all - * be valid pointers. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host) -{ - struct device *ufs_dev = qcom_host->hba->dev; - int err; - - err = qcom_host->ice.vops->init(qcom_host->ice.pdev, - qcom_host, - ufs_qcom_ice_error_cb); - if (err) { - dev_err(ufs_dev, "%s: ice init failed. err = %d\n", - __func__, err); - goto out; - } else { - qcom_host->ice.state = UFS_QCOM_ICE_STATE_ACTIVE; - } - - qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN; - if (!ice_workqueue) { - ice_workqueue = alloc_workqueue("ice-set-key", - WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 0); - if (!ice_workqueue) { - dev_err(ufs_dev, "%s: workqueue allocation failed.\n", - __func__); - err = -ENOMEM; - goto out; - } - INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work); - } - -out: - return err; -} - -static inline bool ufs_qcom_is_data_cmd(char cmd_op, bool is_write) -{ - if (is_write) { - if (cmd_op == WRITE_6 || cmd_op == WRITE_10 || - cmd_op == WRITE_16) - return true; - } else { - if (cmd_op == READ_6 || cmd_op == READ_10 || - cmd_op == READ_16) - return true; - } - - return false; -} - -int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, - struct scsi_cmnd *cmd, u8 *cc_index, bool *enable) -{ - struct ice_data_setting ice_set; - char cmd_op = cmd->cmnd[0]; - int err; - unsigned long flags; - - if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { - dev_dbg(qcom_host->hba->dev, "%s: ice device is not enabled\n", - __func__); - return 0; - } - - if (qcom_host->ice.vops->config_start) { - memset(&ice_set, 0, sizeof(ice_set)); - - spin_lock_irqsave( - &qcom_host->ice_work_lock, flags); - - err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev, - cmd->request, &ice_set, true); - if (err) { - /* - * config_start() returns -EAGAIN when a key slot is - * available but still not configured. As configuration - * requires a non-atomic context, this means we should - * call the function again from the worker thread to do - * the configuration. For this request the error will - * propagate so it will be re-queued. - */ - if (err == -EAGAIN) { - if (!ice_workqueue) { - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, - flags); - - dev_err(qcom_host->hba->dev, - "%s: error %d workqueue NULL\n", - __func__, err); - return -EINVAL; - } - - dev_dbg(qcom_host->hba->dev, - "%s: scheduling task for ice setup\n", - __func__); - - if (!qcom_host->work_pending) { - qcom_host->req_pending = cmd->request; - - if (!queue_work(ice_workqueue, - &qcom_host->ice_cfg_work)) { - qcom_host->req_pending = NULL; - - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, - flags); - - return err; - } - qcom_host->work_pending = true; - } - - } else { - if (err != -EBUSY) - dev_err(qcom_host->hba->dev, - "%s: error in ice_vops->config %d\n", - __func__, err); - } - - spin_unlock_irqrestore(&qcom_host->ice_work_lock, - flags); - - return err; - } - - spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); - - if (ufs_qcom_is_data_cmd(cmd_op, true)) - *enable = !ice_set.encr_bypass; - else if (ufs_qcom_is_data_cmd(cmd_op, false)) - *enable = !ice_set.decr_bypass; - - if (ice_set.crypto_data.key_index >= 0) - *cc_index = (u8)ice_set.crypto_data.key_index; - } - return 0; -} - -/** - * ufs_qcom_ice_cfg_start() - starts configuring UFS's ICE registers - * for an ICE transaction - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and qcom_host->hba->dev should all - * be valid pointers. - * @cmd: Pointer to a valid scsi command. cmd->request should also be - * a valid pointer. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, - struct scsi_cmnd *cmd) -{ - struct device *dev = qcom_host->hba->dev; - int err = 0; - struct ice_data_setting ice_set; - unsigned int slot = 0; - sector_t lba = 0; - unsigned int ctrl_info_val = 0; - unsigned int bypass = 0; - struct request *req; - char cmd_op; - unsigned long flags; - - if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { - dev_dbg(dev, "%s: ice device is not enabled\n", __func__); - goto out; - } - - if (qcom_host->ice.state != UFS_QCOM_ICE_STATE_ACTIVE) { - dev_err(dev, "%s: ice state (%d) is not active\n", - __func__, qcom_host->ice.state); - return -EINVAL; - } - - if (qcom_host->hw_ver.major >= 0x3) { - /* - * ICE 3.0 crypto sequences were changed, - * CTRL_INFO register no longer exists - * and doesn't need to be configured. - * The configuration is done via utrd. - */ - return 0; - } - - req = cmd->request; - if (req->bio) - lba = (req->bio->bi_iter.bi_sector) >> - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; - - slot = req->tag; - if (slot < 0 || slot > qcom_host->hba->nutrs) { - dev_err(dev, "%s: slot (%d) is out of boundaries (0...%d)\n", - __func__, slot, qcom_host->hba->nutrs); - return -EINVAL; - } - - - memset(&ice_set, 0, sizeof(ice_set)); - if (qcom_host->ice.vops->config_start) { - - spin_lock_irqsave( - &qcom_host->ice_work_lock, flags); - - err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev, - req, &ice_set, true); - if (err) { - /* - * config_start() returns -EAGAIN when a key slot is - * available but still not configured. As configuration - * requires a non-atomic context, this means we should - * call the function again from the worker thread to do - * the configuration. For this request the error will - * propagate so it will be re-queued. - */ - if (err == -EAGAIN) { - if (!ice_workqueue) { - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, - flags); - - dev_err(qcom_host->hba->dev, - "%s: error %d workqueue NULL\n", - __func__, err); - return -EINVAL; - } - - dev_dbg(qcom_host->hba->dev, - "%s: scheduling task for ice setup\n", - __func__); - - if (!qcom_host->work_pending) { - - qcom_host->req_pending = cmd->request; - if (!queue_work(ice_workqueue, - &qcom_host->ice_cfg_work)) { - qcom_host->req_pending = NULL; - - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, - flags); - - return err; - } - qcom_host->work_pending = true; - } - - } else { - if (err != -EBUSY) - dev_err(qcom_host->hba->dev, - "%s: error in ice_vops->config %d\n", - __func__, err); - } - - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, flags); - - return err; - } - - spin_unlock_irqrestore( - &qcom_host->ice_work_lock, flags); - } - - cmd_op = cmd->cmnd[0]; - -#define UFS_QCOM_DIR_WRITE true -#define UFS_QCOM_DIR_READ false - /* if non data command, bypass shall be enabled */ - if (!ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_WRITE) && - !ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_READ)) - bypass = UFS_QCOM_ICE_ENABLE_BYPASS; - /* if writing data command */ - else if (ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_WRITE)) - bypass = ice_set.encr_bypass ? UFS_QCOM_ICE_ENABLE_BYPASS : - UFS_QCOM_ICE_DISABLE_BYPASS; - /* if reading data command */ - else if (ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_READ)) - bypass = ice_set.decr_bypass ? UFS_QCOM_ICE_ENABLE_BYPASS : - UFS_QCOM_ICE_DISABLE_BYPASS; - - - /* Configure ICE index */ - ctrl_info_val = - (ice_set.crypto_data.key_index & - MASK_UFS_QCOM_ICE_CTRL_INFO_KEY_INDEX) - << OFFSET_UFS_QCOM_ICE_CTRL_INFO_KEY_INDEX; - - /* Configure data unit size of transfer request */ - ctrl_info_val |= - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB - << OFFSET_UFS_QCOM_ICE_CTRL_INFO_CDU; - - /* Configure ICE bypass mode */ - ctrl_info_val |= - (bypass & MASK_UFS_QCOM_ICE_CTRL_INFO_BYPASS) - << OFFSET_UFS_QCOM_ICE_CTRL_INFO_BYPASS; - - if (qcom_host->hw_ver.major == 0x1) { - ufshcd_writel(qcom_host->hba, lba, - (REG_UFS_QCOM_ICE_CTRL_INFO_1_n + 8 * slot)); - - ufshcd_writel(qcom_host->hba, ctrl_info_val, - (REG_UFS_QCOM_ICE_CTRL_INFO_2_n + 8 * slot)); - } - if (qcom_host->hw_ver.major == 0x2) { - ufshcd_writel(qcom_host->hba, (lba & 0xFFFFFFFF), - (REG_UFS_QCOM_ICE_CTRL_INFO_1_n + 16 * slot)); - - ufshcd_writel(qcom_host->hba, ((lba >> 32) & 0xFFFFFFFF), - (REG_UFS_QCOM_ICE_CTRL_INFO_2_n + 16 * slot)); - - ufshcd_writel(qcom_host->hba, ctrl_info_val, - (REG_UFS_QCOM_ICE_CTRL_INFO_3_n + 16 * slot)); - } - - /* - * Ensure UFS-ICE registers are being configured - * before next operation, otherwise UFS Host Controller might - * set get errors - */ - mb(); -out: - return err; -} - -/** - * ufs_qcom_ice_cfg_end() - finishes configuring UFS's ICE registers - * for an ICE transaction - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and - * qcom_host->hba->dev should all - * be valid pointers. - * @cmd: Pointer to a valid scsi command. cmd->request should also be - * a valid pointer. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_cfg_end(struct ufs_qcom_host *qcom_host, struct request *req) -{ - int err = 0; - struct device *dev = qcom_host->hba->dev; - - if (qcom_host->ice.vops->config_end) { - err = qcom_host->ice.vops->config_end(req); - if (err) { - dev_err(dev, "%s: error in ice_vops->config_end %d\n", - __func__, err); - return err; - } - } - - return 0; -} - -/** - * ufs_qcom_ice_reset() - resets UFS-ICE interface and ICE device - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and qcom_host->hba->dev should all - * be valid pointers. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_reset(struct ufs_qcom_host *qcom_host) -{ - struct device *dev = qcom_host->hba->dev; - int err = 0; - - if (!qcom_host->ice.pdev) { - dev_dbg(dev, "%s: ice device is not enabled\n", __func__); - goto out; - } - - if (!qcom_host->ice.vops) { - dev_err(dev, "%s: invalid ice_vops\n", __func__); - return -EINVAL; - } - - if (qcom_host->ice.state != UFS_QCOM_ICE_STATE_ACTIVE) - goto out; - - if (qcom_host->ice.vops->reset) { - err = qcom_host->ice.vops->reset(qcom_host->ice.pdev); - if (err) { - dev_err(dev, "%s: ice_vops->reset failed. err %d\n", - __func__, err); - goto out; - } - } - - if (qcom_host->ice.state != UFS_QCOM_ICE_STATE_ACTIVE) { - dev_err(qcom_host->hba->dev, - "%s: error. ice.state (%d) is not in active state\n", - __func__, qcom_host->ice.state); - err = -EINVAL; - } - -out: - return err; -} - - -/** - * ufs_qcom_ice_resume() - resumes UFS-ICE interface and ICE device from power - * collapse - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and qcom_host->hba->dev should all - * be valid pointers. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host) -{ - struct device *dev = qcom_host->hba->dev; - int err = 0; - - if (!qcom_host->ice.pdev) { - dev_dbg(dev, "%s: ice device is not enabled\n", __func__); - goto out; - } - - if (qcom_host->ice.state != - UFS_QCOM_ICE_STATE_SUSPENDED) { - goto out; - } - - if (!qcom_host->ice.vops) { - dev_err(dev, "%s: invalid ice_vops\n", __func__); - return -EINVAL; - } - - if (qcom_host->ice.vops->resume) { - err = qcom_host->ice.vops->resume(qcom_host->ice.pdev); - if (err) { - dev_err(dev, "%s: ice_vops->resume failed. err %d\n", - __func__, err); - return err; - } - } - qcom_host->ice.state = UFS_QCOM_ICE_STATE_ACTIVE; -out: - return err; -} - -/** - * ufs_qcom_is_ice_busy() - lets the caller of the function know if - * there is any ongoing operation in ICE in workqueue context. - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host should be a valid pointer. - * - * Return: 1 if ICE is busy, 0 if it is free. - * -EINVAL in case of error. - */ -int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host) -{ - if (!qcom_host) { - pr_err("%s: invalid qcom_host %pK", __func__, qcom_host); - return -EINVAL; - } - - if (qcom_host->req_pending) - return 1; - else - return 0; -} - -/** - * ufs_qcom_ice_suspend() - suspends UFS-ICE interface and ICE device - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and qcom_host->hba->dev should all - * be valid pointers. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_suspend(struct ufs_qcom_host *qcom_host) -{ - struct device *dev = qcom_host->hba->dev; - int err = 0; - - if (!qcom_host->ice.pdev) { - dev_dbg(dev, "%s: ice device is not enabled\n", __func__); - goto out; - } - - if (qcom_host->ice.vops->suspend) { - err = qcom_host->ice.vops->suspend(qcom_host->ice.pdev); - if (err) { - dev_err(qcom_host->hba->dev, - "%s: ice_vops->suspend failed. err %d\n", - __func__, err); - return -EINVAL; - } - } - - if (qcom_host->ice.state == UFS_QCOM_ICE_STATE_ACTIVE) { - qcom_host->ice.state = UFS_QCOM_ICE_STATE_SUSPENDED; - } else if (qcom_host->ice.state == UFS_QCOM_ICE_STATE_DISABLED) { - dev_err(qcom_host->hba->dev, - "%s: ice state is invalid: disabled\n", - __func__); - err = -EINVAL; - } - -out: - return err; -} - -/** - * ufs_qcom_ice_get_status() - returns the status of an ICE transaction - * @qcom_host: Pointer to a UFS QCom internal host structure. - * qcom_host, qcom_host->hba and qcom_host->hba->dev should all - * be valid pointers. - * @ice_status: Pointer to a valid output parameter. - * < 0 in case of ICE transaction failure. - * 0 otherwise. - * - * Return: -EINVAL in-case of an error - * 0 otherwise - */ -int ufs_qcom_ice_get_status(struct ufs_qcom_host *qcom_host, int *ice_status) -{ - struct device *dev = NULL; - int err = 0; - int stat = -EINVAL; - - *ice_status = 0; - - dev = qcom_host->hba->dev; - if (!dev) { - err = -EINVAL; - goto out; - } - - if (!qcom_host->ice.pdev) { - dev_dbg(dev, "%s: ice device is not enabled\n", __func__); - goto out; - } - - if (qcom_host->ice.state != UFS_QCOM_ICE_STATE_ACTIVE) { - err = -EINVAL; - goto out; - } - - if (!qcom_host->ice.vops) { - dev_err(dev, "%s: invalid ice_vops\n", __func__); - return -EINVAL; - } - - if (qcom_host->ice.vops->status) { - stat = qcom_host->ice.vops->status(qcom_host->ice.pdev); - if (stat < 0) { - dev_err(dev, "%s: ice_vops->status failed. stat %d\n", - __func__, stat); - err = -EINVAL; - goto out; - } - - *ice_status = stat; - } - -out: - return err; -} diff --git a/drivers/scsi/ufs/ufs-qcom-ice.h b/drivers/scsi/ufs/ufs-qcom-ice.h deleted file mode 100644 index 88ffeb35f9f3bad1e1f2b000f10563f6332846ce..0000000000000000000000000000000000000000 --- a/drivers/scsi/ufs/ufs-qcom-ice.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _UFS_QCOM_ICE_H_ -#define _UFS_QCOM_ICE_H_ - -#include - -#include "ufs-qcom.h" - -/* - * UFS host controller ICE registers. There are n [0..31] - * of each of these registers - */ -enum { - REG_UFS_QCOM_ICE_CFG = 0x2200, - REG_UFS_QCOM_ICE_CTRL_INFO_1_n = 0x2204, - REG_UFS_QCOM_ICE_CTRL_INFO_2_n = 0x2208, - REG_UFS_QCOM_ICE_CTRL_INFO_3_n = 0x220C, -}; -#define NUM_QCOM_ICE_CTRL_INFO_n_REGS 32 - -/* UFS QCOM ICE CTRL Info register offset */ -enum { - OFFSET_UFS_QCOM_ICE_CTRL_INFO_BYPASS = 0, - OFFSET_UFS_QCOM_ICE_CTRL_INFO_KEY_INDEX = 0x1, - OFFSET_UFS_QCOM_ICE_CTRL_INFO_CDU = 0x6, -}; - -/* UFS QCOM ICE CTRL Info register masks */ -enum { - MASK_UFS_QCOM_ICE_CTRL_INFO_BYPASS = 0x1, - MASK_UFS_QCOM_ICE_CTRL_INFO_KEY_INDEX = 0x1F, - MASK_UFS_QCOM_ICE_CTRL_INFO_CDU = 0x8, -}; - -/* UFS QCOM ICE encryption/decryption bypass state */ -enum { - UFS_QCOM_ICE_DISABLE_BYPASS = 0, - UFS_QCOM_ICE_ENABLE_BYPASS = 1, -}; - -/* UFS QCOM ICE Crypto Data Unit of target DUN of Transfer Request */ -enum { - UFS_QCOM_ICE_TR_DATA_UNIT_512_B = 0, - UFS_QCOM_ICE_TR_DATA_UNIT_1_KB = 1, - UFS_QCOM_ICE_TR_DATA_UNIT_2_KB = 2, - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB = 3, - UFS_QCOM_ICE_TR_DATA_UNIT_8_KB = 4, - UFS_QCOM_ICE_TR_DATA_UNIT_16_KB = 5, - UFS_QCOM_ICE_TR_DATA_UNIT_32_KB = 6, -}; - -/* UFS QCOM ICE internal state */ -enum { - UFS_QCOM_ICE_STATE_DISABLED = 0, - UFS_QCOM_ICE_STATE_ACTIVE = 1, - UFS_QCOM_ICE_STATE_SUSPENDED = 2, -}; - -#ifdef CONFIG_SCSI_UFS_QCOM_ICE -int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host); -int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host); -int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, - struct scsi_cmnd *cmd, u8 *cc_index, bool *enable); -int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, - struct scsi_cmnd *cmd); -int ufs_qcom_ice_cfg_end(struct ufs_qcom_host *qcom_host, - struct request *req); -int ufs_qcom_ice_reset(struct ufs_qcom_host *qcom_host); -int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host); -int ufs_qcom_ice_suspend(struct ufs_qcom_host *qcom_host); -int ufs_qcom_ice_get_status(struct ufs_qcom_host *qcom_host, int *ice_status); -void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host); -int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host); -#else -inline int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host) -{ - if (qcom_host) { - qcom_host->ice.pdev = NULL; - qcom_host->ice.vops = NULL; - } - return -ENODEV; -} -inline int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host) -{ - return 0; -} -inline int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, - struct scsi_cmnd *cmd) -{ - return 0; -} -inline int ufs_qcom_ice_cfg_end(struct ufs_qcom_host *qcom_host, - struct request *req) -{ - return 0; -} -inline int ufs_qcom_ice_reset(struct ufs_qcom_host *qcom_host) -{ - return 0; -} -inline int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host) -{ - return 0; -} -inline int ufs_qcom_ice_suspend(struct ufs_qcom_host *qcom_host) -{ - return 0; -} -inline int ufs_qcom_ice_get_status(struct ufs_qcom_host *qcom_host, - int *ice_status) -{ - return 0; -} -inline void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host) -{ - return; -} -inline int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host) -{ - return 0; -} -#endif /* CONFIG_SCSI_UFS_QCOM_ICE */ - -#endif /* UFS_QCOM_ICE_H_ */ diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 195e0428cb548c8a921abaedcbb8ae711478c9c6..4b76913104f7ba3c1e41f075d816c584ffaa5410 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2020, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,9 +28,9 @@ #include "unipro.h" #include "ufs-qcom.h" #include "ufshci.h" -#include "ufs-qcom-ice.h" #include "ufs-qcom-debugfs.h" #include "ufs_quirks.h" +#include "ufshcd-crypto-qti.h" #define MAX_PROP_SIZE 32 #define VDDP_REF_CLK_MIN_UV 1200000 @@ -406,14 +406,6 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, * is initialized. */ err = ufs_qcom_enable_lane_clks(host); - if (!err && host->ice.pdev) { - err = ufs_qcom_ice_init(host); - if (err) { - dev_err(hba->dev, "%s: ICE init failed (%d)\n", - __func__, err); - err = -EINVAL; - } - } break; case POST_CHANGE: @@ -849,7 +841,6 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufs_qcom_config_vreg(hba->dev, host->vccq_parent, false); - ufs_qcom_ice_suspend(host); if (ufs_qcom_is_link_off(hba)) { /* Assert PHY soft reset */ ufs_qcom_assert_reset(hba); @@ -889,13 +880,6 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (err) goto out; - err = ufs_qcom_ice_resume(host); - if (err) { - dev_err(hba->dev, "%s: ufs_qcom_ice_resume failed, err = %d\n", - __func__, err); - goto out; - } - hba->is_sys_suspended = false; out: @@ -935,119 +919,6 @@ static int ufs_qcom_full_reset(struct ufs_hba *hba) return ret; } -#ifdef CONFIG_SCSI_UFS_QCOM_ICE -static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp, u8 *cc_index, bool *enable, u64 *dun) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct request *req; - int ret; - - if (lrbp->cmd && lrbp->cmd->request) - req = lrbp->cmd->request; - else - return 0; - - /* Use request LBA or given dun as the DUN value */ - if (req->bio) { -#ifdef CONFIG_PFK - if (bio_dun(req->bio)) { - /* dun @bio can be split, so we have to adjust offset */ - *dun = bio_dun(req->bio); - } else { - *dun = req->bio->bi_iter.bi_sector; - *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; - } -#else - *dun = req->bio->bi_iter.bi_sector; - *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; -#endif - } - ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable); - - return ret; -} - -static -int ufs_qcom_crytpo_engine_cfg_start(struct ufs_hba *hba, unsigned int task_tag) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufshcd_lrb *lrbp = &hba->lrb[task_tag]; - int err = 0; - - if (!host->ice.pdev || - !lrbp->cmd || - (lrbp->command_type != UTP_CMD_TYPE_SCSI && - lrbp->command_type != UTP_CMD_TYPE_UFS_STORAGE)) - goto out; - - err = ufs_qcom_ice_cfg_start(host, lrbp->cmd); -out: - return err; -} - -static -int ufs_qcom_crytpo_engine_cfg_end(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp, struct request *req) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; - - if (!host->ice.pdev || (lrbp->command_type != UTP_CMD_TYPE_SCSI && - lrbp->command_type != UTP_CMD_TYPE_UFS_STORAGE)) - goto out; - - err = ufs_qcom_ice_cfg_end(host, req); -out: - return err; -} - -static -int ufs_qcom_crytpo_engine_reset(struct ufs_hba *hba) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; - - if (!host->ice.pdev) - goto out; - - err = ufs_qcom_ice_reset(host); -out: - return err; -} - -static int ufs_qcom_crypto_engine_get_status(struct ufs_hba *hba, u32 *status) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - - if (!status) - return -EINVAL; - - return ufs_qcom_ice_get_status(host, status); -} - -static int ufs_qcom_crypto_get_pending_req_status(struct ufs_hba *hba) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; - - if (!host->ice.pdev) - goto out; - - err = ufs_qcom_is_ice_busy(host); -out: - return err; -} - -#else /* !CONFIG_SCSI_UFS_QCOM_ICE */ -#define ufs_qcom_crypto_req_setup NULL -#define ufs_qcom_crytpo_engine_cfg_start NULL -#define ufs_qcom_crytpo_engine_cfg_end NULL -#define ufs_qcom_crytpo_engine_reset NULL -#define ufs_qcom_crypto_engine_get_status NULL -#define ufs_qcom_crypto_get_pending_req_status NULL -#endif /* CONFIG_SCSI_UFS_QCOM_ICE */ - struct ufs_qcom_dev_params { u32 pwm_rx_gear; /* pwm rx gear to work in */ u32 pwm_tx_gear; /* pwm tx gear to work in */ @@ -1582,6 +1453,12 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) if (host->disable_lpm) hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; + /* + * Inline crypto is currently broken with ufs-qcom at least because the + * device tree doesn't include the crypto registers. There are likely + * to be other issues that will need to be addressed too. + */ + //hba->quirks |= UFSHCD_QUIRK_BROKEN_CRYPTO; } static void ufs_qcom_set_caps(struct ufs_hba *hba) @@ -1629,7 +1506,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -1648,14 +1524,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, if (ufshcd_is_hs_mode(&hba->pwr_info)) ufs_qcom_dev_ref_clk_ctrl(host, true); - err = ufs_qcom_ice_resume(host); - if (err) - goto out; } else if (!on && (status == PRE_CHANGE)) { - err = ufs_qcom_ice_suspend(host); - if (err) - goto out; - /* * If auto hibern8 is supported then the link will already * be in hibern8 state and the ref clock can be gated. @@ -1674,8 +1543,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, } } -out: - return err; + return 0; } #ifdef CONFIG_SMP /* CONFIG_SMP */ @@ -2209,36 +2077,9 @@ static int ufs_qcom_init(struct ufs_hba *hba) /* Make a two way bind between the qcom host and the hba */ host->hba = hba; - spin_lock_init(&host->ice_work_lock); ufshcd_set_variant(hba, host); - err = ufs_qcom_ice_get_dev(host); - if (err == -EPROBE_DEFER) { - /* - * UFS driver might be probed before ICE driver does. - * In that case we would like to return EPROBE_DEFER code - * in order to delay its probing. - */ - dev_err(dev, "%s: required ICE device not probed yet err = %d\n", - __func__, err); - goto out_variant_clear; - - } else if (err == -ENODEV) { - /* - * ICE device is not enabled in DTS file. No need for further - * initialization of ICE driver. - */ - dev_warn(dev, "%s: ICE device is not enabled", - __func__); - } else if (err) { - dev_err(dev, "%s: ufs_qcom_ice_get_dev failed %d\n", - __func__, err); - goto out_variant_clear; - } else { - hba->host->inlinecrypt_support = 1; - } - host->generic_phy = devm_phy_get(dev, "ufsphy"); if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) { @@ -2263,6 +2104,12 @@ static int ufs_qcom_init(struct ufs_hba *hba) /* restore the secure configuration */ ufs_qcom_update_sec_cfg(hba, true); + /* + * Set the vendor specific ops needed for ICE. + * Default implementation if the ops are not set. + */ + ufshcd_crypto_qti_set_vops(hba); + err = ufs_qcom_bus_register(host); if (err) goto out_variant_clear; @@ -2812,7 +2659,6 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep) usleep_range(1000, 1100); ufs_qcom_phy_dbg_register_dump(phy); usleep_range(1000, 1100); - ufs_qcom_ice_print_regs(host); } /** @@ -2843,15 +2689,6 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { #endif }; -static struct ufs_hba_crypto_variant_ops ufs_hba_crypto_variant_ops = { - .crypto_req_setup = ufs_qcom_crypto_req_setup, - .crypto_engine_cfg_start = ufs_qcom_crytpo_engine_cfg_start, - .crypto_engine_cfg_end = ufs_qcom_crytpo_engine_cfg_end, - .crypto_engine_reset = ufs_qcom_crytpo_engine_reset, - .crypto_engine_get_status = ufs_qcom_crypto_engine_get_status, - .crypto_get_req_status = ufs_qcom_crypto_get_pending_req_status, -}; - static struct ufs_hba_pm_qos_variant_ops ufs_hba_pm_qos_variant_ops = { .req_start = ufs_qcom_pm_qos_req_start, .req_end = ufs_qcom_pm_qos_req_end, @@ -2860,7 +2697,6 @@ static struct ufs_hba_pm_qos_variant_ops ufs_hba_pm_qos_variant_ops = { static struct ufs_hba_variant ufs_hba_qcom_variant = { .name = "qcom", .vops = &ufs_hba_qcom_vops, - .crypto_vops = &ufs_hba_crypto_variant_ops, .pm_qos_vops = &ufs_hba_pm_qos_variant_ops, }; diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 95304a581453cc805867a22d2565a970c67f09f7..34140f91437db530760ff95b659edac842759f81 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -236,26 +236,6 @@ struct ufs_qcom_testbus { u8 select_minor; }; -/** - * struct ufs_qcom_ice_data - ICE related information - * @vops: pointer to variant operations of ICE - * @async_done: completion for supporting ICE's driver asynchronous nature - * @pdev: pointer to the proper ICE platform device - * @state: UFS-ICE interface's internal state (see - * ufs-qcom-ice.h for possible internal states) - * @quirks: UFS-ICE interface related quirks - * @crypto_engine_err: crypto engine errors - */ -struct ufs_qcom_ice_data { - struct qcom_ice_variant_ops *vops; - struct platform_device *pdev; - int state; - - u16 quirks; - - bool crypto_engine_err; -}; - #ifdef CONFIG_DEBUG_FS struct qcom_debugfs_files { struct dentry *debugfs_root; @@ -363,7 +343,6 @@ struct ufs_qcom_host { bool disable_lpm; bool is_lane_clks_enabled; bool sec_cfg_updated; - struct ufs_qcom_ice_data ice; void __iomem *dev_ref_clk_ctrl_mmio; bool is_dev_ref_clk_enabled; @@ -378,8 +357,6 @@ struct ufs_qcom_host { u32 dbg_print_en; struct ufs_qcom_testbus testbus; - spinlock_t ice_work_lock; - struct work_struct ice_cfg_work; struct request *req_pending; struct ufs_vreg *vddp_ref_clk; struct ufs_vreg *vccq_parent; diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.c b/drivers/scsi/ufs/ufshcd-crypto-qti.c new file mode 100644 index 0000000000000000000000000000000000000000..cfae1e5dede23274d2b0338dace83f3f581255c2 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "ufshcd-crypto-qti.h" + +#define MINIMUM_DUN_SIZE 512 +#define MAXIMUM_DUN_SIZE 65536 + +#define NUM_KEYSLOTS(hba) (hba->crypto_capabilities.config_count + 1) + +static struct ufs_hba_crypto_variant_ops ufshcd_crypto_qti_variant_ops = { + .hba_init_crypto = ufshcd_crypto_qti_init_crypto, + .enable = ufshcd_crypto_qti_enable, + .disable = ufshcd_crypto_qti_disable, + .resume = ufshcd_crypto_qti_resume, + .debug = ufshcd_crypto_qti_debug, +}; + +static uint8_t get_data_unit_size_mask(unsigned int data_unit_size) +{ + if (data_unit_size < MINIMUM_DUN_SIZE || + data_unit_size > MAXIMUM_DUN_SIZE || + !is_power_of_2(data_unit_size)) + return 0; + + return data_unit_size / MINIMUM_DUN_SIZE; +} + +static bool ice_cap_idx_valid(struct ufs_hba *hba, + unsigned int cap_idx) +{ + return cap_idx < hba->crypto_capabilities.num_crypto_cap; +} + +void ufshcd_crypto_qti_enable(struct ufs_hba *hba) +{ + int err = 0; + + if (!ufshcd_hba_is_crypto_supported(hba)) + return; + + err = crypto_qti_enable(hba->crypto_vops->priv); + if (err) { + pr_err("%s: Error enabling crypto, err %d\n", + __func__, err); + ufshcd_crypto_qti_disable(hba); + } + + ufshcd_crypto_enable_spec(hba); + +} + +void ufshcd_crypto_qti_disable(struct ufs_hba *hba) +{ + ufshcd_crypto_disable_spec(hba); + crypto_qti_disable(hba->crypto_vops->priv); +} + + +static int ufshcd_crypto_qti_keyslot_program(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct ufs_hba *hba = keyslot_manager_private(ksm); + int err = 0; + u8 data_unit_mask; + int crypto_alg_id; + + crypto_alg_id = ufshcd_crypto_cap_find(hba, key->crypto_mode, + key->data_unit_size); + + if (!ufshcd_is_crypto_enabled(hba) || + !ufshcd_keyslot_valid(hba, slot) || + !ice_cap_idx_valid(hba, crypto_alg_id)) + return -EINVAL; + + data_unit_mask = get_data_unit_size_mask(key->data_unit_size); + + if (!(data_unit_mask & + hba->crypto_cap_array[crypto_alg_id].sdus_mask)) + return -EINVAL; + + pm_runtime_get_sync(hba->dev); + err = ufshcd_hold(hba, false); + if (err) { + pr_err("%s: failed to enable clocks, err %d\n", __func__, err); + return err; + } + + err = crypto_qti_keyslot_program(hba->crypto_vops->priv, key, slot, + data_unit_mask, crypto_alg_id); + if (err) { + pr_err("%s: failed with error %d\n", __func__, err); + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + return err; + } + + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + + return 0; +} + +static int ufshcd_crypto_qti_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + int err = 0; + struct ufs_hba *hba = keyslot_manager_private(ksm); + + if (!ufshcd_is_crypto_enabled(hba) || + !ufshcd_keyslot_valid(hba, slot)) + return -EINVAL; + + pm_runtime_get_sync(hba->dev); + err = ufshcd_hold(hba, false); + if (err) { + pr_err("%s: failed to enable clocks, err %d\n", __func__, err); + return err; + } + + err = crypto_qti_keyslot_evict(hba->crypto_vops->priv, slot); + if (err) { + pr_err("%s: failed with error %d\n", + __func__, err); + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + return err; + } + + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + + return err; +} + +static int ufshcd_crypto_qti_derive_raw_secret(struct keyslot_manager *ksm, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, + unsigned int secret_size) +{ + return crypto_qti_derive_raw_secret(wrapped_key, wrapped_key_size, + secret, secret_size); +} + +static const struct keyslot_mgmt_ll_ops ufshcd_crypto_qti_ksm_ops = { + .keyslot_program = ufshcd_crypto_qti_keyslot_program, + .keyslot_evict = ufshcd_crypto_qti_keyslot_evict, + .derive_raw_secret = ufshcd_crypto_qti_derive_raw_secret, +}; + +static enum blk_crypto_mode_num ufshcd_blk_crypto_qti_mode_num_for_alg_dusize( + enum ufs_crypto_alg ufs_crypto_alg, + enum ufs_crypto_key_size key_size) +{ + /* + * This is currently the only mode that UFS and blk-crypto both support. + */ + if (ufs_crypto_alg == UFS_CRYPTO_ALG_AES_XTS && + key_size == UFS_CRYPTO_KEY_SIZE_256) + return BLK_ENCRYPTION_MODE_AES_256_XTS; + + return BLK_ENCRYPTION_MODE_INVALID; +} + +static int ufshcd_hba_init_crypto_qti_spec(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int cap_idx = 0; + int err = 0; + unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX]; + enum blk_crypto_mode_num blk_mode_num; + + /* Default to disabling crypto */ + hba->caps &= ~UFSHCD_CAP_CRYPTO; + + if (!(hba->capabilities & MASK_CRYPTO_SUPPORT)) { + err = -ENODEV; + goto out; + } + + /* + * Crypto Capabilities should never be 0, because the + * config_array_ptr > 04h. So we use a 0 value to indicate that + * crypto init failed, and can't be enabled. + */ + hba->crypto_capabilities.reg_val = + cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP)); + hba->crypto_cfg_register = + (u32)hba->crypto_capabilities.config_array_ptr * 0x100; + hba->crypto_cap_array = + devm_kcalloc(hba->dev, + hba->crypto_capabilities.num_crypto_cap, + sizeof(hba->crypto_cap_array[0]), + GFP_KERNEL); + if (!hba->crypto_cap_array) { + err = -ENOMEM; + goto out; + } + + memset(crypto_modes_supported, 0, sizeof(crypto_modes_supported)); + /* + * Store all the capabilities now so that we don't need to repeatedly + * access the device each time we want to know its capabilities + */ + for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap; + cap_idx++) { + hba->crypto_cap_array[cap_idx].reg_val = + cpu_to_le32(ufshcd_readl(hba, + REG_UFS_CRYPTOCAP + + cap_idx * sizeof(__le32))); + blk_mode_num = ufshcd_blk_crypto_qti_mode_num_for_alg_dusize( + hba->crypto_cap_array[cap_idx].algorithm_id, + hba->crypto_cap_array[cap_idx].key_size); + if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID) + continue; + crypto_modes_supported[blk_mode_num] |= + hba->crypto_cap_array[cap_idx].sdus_mask * 512; + } + + hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), ksm_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS | + BLK_CRYPTO_FEATURE_WRAPPED_KEYS, + crypto_modes_supported, hba); + + if (!hba->ksm) { + err = -ENOMEM; + goto out; + } + keyslot_manager_set_max_dun_bytes(hba->ksm, sizeof(u64)); + + pr_debug("%s: keyslot manager created\n", __func__); + + return 0; + +out: + /* Indicate that init failed by setting crypto_capabilities to 0 */ + hba->crypto_capabilities.reg_val = 0; + return err; +} + +int ufshcd_crypto_qti_init_crypto(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int err = 0; + struct platform_device *pdev = to_platform_device(hba->dev); + void __iomem *mmio_base; + struct resource *mem_res; + + mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "ufs_ice"); + mmio_base = devm_ioremap_resource(hba->dev, mem_res); + if (IS_ERR(mmio_base)) { + pr_err("%s: Unable to get ufs_crypto mmio base\n", __func__); + return PTR_ERR(mmio_base); + } + + err = ufshcd_hba_init_crypto_qti_spec(hba, &ufshcd_crypto_qti_ksm_ops); + if (err) { + pr_err("%s: Error initiating crypto capabilities, err %d\n", + __func__, err); + return err; + } + + err = crypto_qti_init_crypto(hba->dev, + mmio_base, (void **)&hba->crypto_vops->priv); + if (err) { + pr_err("%s: Error initiating crypto, err %d\n", + __func__, err); + } + return err; +} + +int ufshcd_crypto_qti_debug(struct ufs_hba *hba) +{ + return crypto_qti_debug(hba->crypto_vops->priv); +} + +void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba) +{ + return ufshcd_crypto_set_vops(hba, &ufshcd_crypto_qti_variant_ops); +} + +int ufshcd_crypto_qti_resume(struct ufs_hba *hba, + enum ufs_pm_op pm_op) +{ + return crypto_qti_resume(hba->crypto_vops->priv); +} diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.h b/drivers/scsi/ufs/ufshcd-crypto-qti.h new file mode 100644 index 0000000000000000000000000000000000000000..1e75ce0a5c92661ad146542423217c75a3e914b1 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UFSHCD_CRYPTO_QTI_H +#define _UFSHCD_CRYPTO_QTI_H + +#include "ufshcd.h" +#include "ufshcd-crypto.h" + +void ufshcd_crypto_qti_enable(struct ufs_hba *hba); + +void ufshcd_crypto_qti_disable(struct ufs_hba *hba); + +int ufshcd_crypto_qti_init_crypto(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops); + +void ufshcd_crypto_qti_setup_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q); + +void ufshcd_crypto_qti_destroy_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q); + +int ufshcd_crypto_qti_prepare_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, struct ufshcd_lrb *lrbp); + +int ufshcd_crypto_qti_complete_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, struct ufshcd_lrb *lrbp); + +int ufshcd_crypto_qti_debug(struct ufs_hba *hba); + +int ufshcd_crypto_qti_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op); + +int ufshcd_crypto_qti_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op); + +#ifdef CONFIG_SCSI_UFS_CRYPTO_QTI +void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba); +#else +static inline void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba) +{} +#endif /* CONFIG_SCSI_UFS_CRYPTO_QTI */ +#endif /* _UFSHCD_CRYPTO_QTI_H */ diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..240745526135807887e832584b21274ca130d42b --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-crypto.c @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include +#include "ufshcd.h" +#include "ufshcd-crypto.h" + +static bool ufshcd_cap_idx_valid(struct ufs_hba *hba, unsigned int cap_idx) +{ + return cap_idx < hba->crypto_capabilities.num_crypto_cap; +} + +static u8 get_data_unit_size_mask(unsigned int data_unit_size) +{ + if (data_unit_size < 512 || data_unit_size > 65536 || + !is_power_of_2(data_unit_size)) + return 0; + + return data_unit_size / 512; +} + +static size_t get_keysize_bytes(enum ufs_crypto_key_size size) +{ + switch (size) { + case UFS_CRYPTO_KEY_SIZE_128: + return 16; + case UFS_CRYPTO_KEY_SIZE_192: + return 24; + case UFS_CRYPTO_KEY_SIZE_256: + return 32; + case UFS_CRYPTO_KEY_SIZE_512: + return 64; + default: + return 0; + } +} + +int ufshcd_crypto_cap_find(struct ufs_hba *hba, + enum blk_crypto_mode_num crypto_mode, + unsigned int data_unit_size) +{ + enum ufs_crypto_alg ufs_alg; + u8 data_unit_mask; + int cap_idx; + enum ufs_crypto_key_size ufs_key_size; + union ufs_crypto_cap_entry *ccap_array = hba->crypto_cap_array; + + if (!ufshcd_hba_is_crypto_supported(hba)) + return -EINVAL; + + switch (crypto_mode) { + case BLK_ENCRYPTION_MODE_AES_256_XTS: + ufs_alg = UFS_CRYPTO_ALG_AES_XTS; + ufs_key_size = UFS_CRYPTO_KEY_SIZE_256; + break; + default: + return -EINVAL; + } + + data_unit_mask = get_data_unit_size_mask(data_unit_size); + + for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap; + cap_idx++) { + if (ccap_array[cap_idx].algorithm_id == ufs_alg && + (ccap_array[cap_idx].sdus_mask & data_unit_mask) && + ccap_array[cap_idx].key_size == ufs_key_size) + return cap_idx; + } + + return -EINVAL; +} +EXPORT_SYMBOL(ufshcd_crypto_cap_find); + +/** + * ufshcd_crypto_cfg_entry_write_key - Write a key into a crypto_cfg_entry + * + * Writes the key with the appropriate format - for AES_XTS, + * the first half of the key is copied as is, the second half is + * copied with an offset halfway into the cfg->crypto_key array. + * For the other supported crypto algs, the key is just copied. + * + * @cfg: The crypto config to write to + * @key: The key to write + * @cap: The crypto capability (which specifies the crypto alg and key size) + * + * Returns 0 on success, or -EINVAL + */ +static int ufshcd_crypto_cfg_entry_write_key(union ufs_crypto_cfg_entry *cfg, + const u8 *key, + union ufs_crypto_cap_entry cap) +{ + size_t key_size_bytes = get_keysize_bytes(cap.key_size); + + if (key_size_bytes == 0) + return -EINVAL; + + switch (cap.algorithm_id) { + case UFS_CRYPTO_ALG_AES_XTS: + key_size_bytes *= 2; + if (key_size_bytes > UFS_CRYPTO_KEY_MAX_SIZE) + return -EINVAL; + + memcpy(cfg->crypto_key, key, key_size_bytes/2); + memcpy(cfg->crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2, + key + key_size_bytes/2, key_size_bytes/2); + return 0; + case UFS_CRYPTO_ALG_BITLOCKER_AES_CBC: + /* fall through */ + case UFS_CRYPTO_ALG_AES_ECB: + /* fall through */ + case UFS_CRYPTO_ALG_ESSIV_AES_CBC: + memcpy(cfg->crypto_key, key, key_size_bytes); + return 0; + } + + return -EINVAL; +} + +static int ufshcd_program_key(struct ufs_hba *hba, + const union ufs_crypto_cfg_entry *cfg, int slot) +{ + int i; + u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg); + int err; + + pm_runtime_get_sync(hba->dev); + ufshcd_hold(hba, false); + + if (hba->var->vops->program_key) { + err = hba->var->vops->program_key(hba, cfg, slot); + goto out; + } + + /* Clear the dword 16 */ + ufshcd_writel(hba, 0, slot_offset + 16 * sizeof(cfg->reg_val[0])); + /* Ensure that CFGE is cleared before programming the key */ + wmb(); + for (i = 0; i < 16; i++) { + ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[i]), + slot_offset + i * sizeof(cfg->reg_val[0])); + /* Spec says each dword in key must be written sequentially */ + wmb(); + } + /* Write dword 17 */ + ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[17]), + slot_offset + 17 * sizeof(cfg->reg_val[0])); + /* Dword 16 must be written last */ + wmb(); + /* Write dword 16 */ + ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[16]), + slot_offset + 16 * sizeof(cfg->reg_val[0])); + wmb(); + err = 0; +out: + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + return err; +} + +static void ufshcd_clear_keyslot(struct ufs_hba *hba, int slot) +{ + union ufs_crypto_cfg_entry cfg = { {0} }; + int err; + + err = ufshcd_program_key(hba, &cfg, slot); + WARN_ON_ONCE(err); +} + +/* Clear all keyslots at driver init time */ +static void ufshcd_clear_all_keyslots(struct ufs_hba *hba) +{ + int slot; + + for (slot = 0; slot < ufshcd_num_keyslots(hba); slot++) + ufshcd_clear_keyslot(hba, slot); +} + +static int ufshcd_crypto_keyslot_program(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct ufs_hba *hba = keyslot_manager_private(ksm); + int err = 0; + u8 data_unit_mask; + union ufs_crypto_cfg_entry cfg; + int cap_idx; + + cap_idx = ufshcd_crypto_cap_find(hba, key->crypto_mode, + key->data_unit_size); + + if (!ufshcd_is_crypto_enabled(hba) || + !ufshcd_keyslot_valid(hba, slot) || + !ufshcd_cap_idx_valid(hba, cap_idx)) + return -EINVAL; + + data_unit_mask = get_data_unit_size_mask(key->data_unit_size); + + if (!(data_unit_mask & hba->crypto_cap_array[cap_idx].sdus_mask)) + return -EINVAL; + + memset(&cfg, 0, sizeof(cfg)); + cfg.data_unit_size = data_unit_mask; + cfg.crypto_cap_idx = cap_idx; + cfg.config_enable |= UFS_CRYPTO_CONFIGURATION_ENABLE; + + err = ufshcd_crypto_cfg_entry_write_key(&cfg, key->raw, + hba->crypto_cap_array[cap_idx]); + if (err) + return err; + + err = ufshcd_program_key(hba, &cfg, slot); + + memzero_explicit(&cfg, sizeof(cfg)); + + return err; +} + +static int ufshcd_crypto_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct ufs_hba *hba = keyslot_manager_private(ksm); + + if (!ufshcd_is_crypto_enabled(hba) || + !ufshcd_keyslot_valid(hba, slot)) + return -EINVAL; + + /* + * Clear the crypto cfg on the device. Clearing CFGE + * might not be sufficient, so just clear the entire cfg. + */ + ufshcd_clear_keyslot(hba, slot); + + return 0; +} + +/* Functions implementing UFSHCI v2.1 specification behaviour */ +void ufshcd_crypto_enable_spec(struct ufs_hba *hba) +{ + if (!ufshcd_hba_is_crypto_supported(hba)) + return; + + hba->caps |= UFSHCD_CAP_CRYPTO; + + /* Reset might clear all keys, so reprogram all the keys. */ + keyslot_manager_reprogram_all_keys(hba->ksm); +} +EXPORT_SYMBOL_GPL(ufshcd_crypto_enable_spec); + +void ufshcd_crypto_disable_spec(struct ufs_hba *hba) +{ + hba->caps &= ~UFSHCD_CAP_CRYPTO; +} +EXPORT_SYMBOL_GPL(ufshcd_crypto_disable_spec); + +static const struct keyslot_mgmt_ll_ops ufshcd_ksm_ops = { + .keyslot_program = ufshcd_crypto_keyslot_program, + .keyslot_evict = ufshcd_crypto_keyslot_evict, +}; + +enum blk_crypto_mode_num ufshcd_blk_crypto_mode_num_for_alg_dusize( + enum ufs_crypto_alg ufs_crypto_alg, + enum ufs_crypto_key_size key_size) +{ + /* + * This is currently the only mode that UFS and blk-crypto both support. + */ + if (ufs_crypto_alg == UFS_CRYPTO_ALG_AES_XTS && + key_size == UFS_CRYPTO_KEY_SIZE_256) + return BLK_ENCRYPTION_MODE_AES_256_XTS; + + return BLK_ENCRYPTION_MODE_INVALID; +} + +/** + * ufshcd_hba_init_crypto - Read crypto capabilities, init crypto fields in hba + * @hba: Per adapter instance + * + * Return: 0 if crypto was initialized or is not supported, else a -errno value. + */ +int ufshcd_hba_init_crypto_spec(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int cap_idx = 0; + int err = 0; + unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX]; + enum blk_crypto_mode_num blk_mode_num; + + /* Default to disabling crypto */ + hba->caps &= ~UFSHCD_CAP_CRYPTO; + + /* Return 0 if crypto support isn't present */ + if (!(hba->capabilities & MASK_CRYPTO_SUPPORT) || + (hba->quirks & UFSHCD_QUIRK_BROKEN_CRYPTO)) + goto out; + + /* + * Crypto Capabilities should never be 0, because the + * config_array_ptr > 04h. So we use a 0 value to indicate that + * crypto init failed, and can't be enabled. + */ + hba->crypto_capabilities.reg_val = + cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP)); + hba->crypto_cfg_register = + (u32)hba->crypto_capabilities.config_array_ptr * 0x100; + hba->crypto_cap_array = + devm_kcalloc(hba->dev, + hba->crypto_capabilities.num_crypto_cap, + sizeof(hba->crypto_cap_array[0]), + GFP_KERNEL); + if (!hba->crypto_cap_array) { + err = -ENOMEM; + goto out; + } + + memset(crypto_modes_supported, 0, sizeof(crypto_modes_supported)); + /* + * Store all the capabilities now so that we don't need to repeatedly + * access the device each time we want to know its capabilities + */ + for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap; + cap_idx++) { + hba->crypto_cap_array[cap_idx].reg_val = + cpu_to_le32(ufshcd_readl(hba, + REG_UFS_CRYPTOCAP + + cap_idx * sizeof(__le32))); + blk_mode_num = ufshcd_blk_crypto_mode_num_for_alg_dusize( + hba->crypto_cap_array[cap_idx].algorithm_id, + hba->crypto_cap_array[cap_idx].key_size); + if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID) + continue; + crypto_modes_supported[blk_mode_num] |= + hba->crypto_cap_array[cap_idx].sdus_mask * 512; + } + + ufshcd_clear_all_keyslots(hba); + + hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), + ksm_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS, + crypto_modes_supported, hba); + + if (!hba->ksm) { + err = -ENOMEM; + goto out_free_caps; + } + keyslot_manager_set_max_dun_bytes(hba->ksm, sizeof(u64)); + + return 0; + +out_free_caps: + devm_kfree(hba->dev, hba->crypto_cap_array); +out: + /* Indicate that init failed by setting crypto_capabilities to 0 */ + hba->crypto_capabilities.reg_val = 0; + return err; +} +EXPORT_SYMBOL_GPL(ufshcd_hba_init_crypto_spec); + +void ufshcd_crypto_setup_rq_keyslot_manager_spec(struct ufs_hba *hba, + struct request_queue *q) +{ + if (!ufshcd_hba_is_crypto_supported(hba) || !q) + return; + + q->ksm = hba->ksm; +} +EXPORT_SYMBOL_GPL(ufshcd_crypto_setup_rq_keyslot_manager_spec); + +void ufshcd_crypto_destroy_rq_keyslot_manager_spec(struct ufs_hba *hba, + struct request_queue *q) +{ + keyslot_manager_destroy(hba->ksm); +} +EXPORT_SYMBOL_GPL(ufshcd_crypto_destroy_rq_keyslot_manager_spec); + +int ufshcd_prepare_lrbp_crypto_spec(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp) +{ + struct bio_crypt_ctx *bc; + + if (!bio_crypt_should_process(cmd->request)) { + lrbp->crypto_enable = false; + return 0; + } + bc = cmd->request->bio->bi_crypt_context; + + if (WARN_ON(!ufshcd_is_crypto_enabled(hba))) { + /* + * Upper layer asked us to do inline encryption + * but that isn't enabled, so we fail this request. + */ + return -EINVAL; + } + if (!ufshcd_keyslot_valid(hba, bc->bc_keyslot)) + return -EINVAL; + + lrbp->crypto_enable = true; + lrbp->crypto_key_slot = bc->bc_keyslot; + lrbp->data_unit_num = bc->bc_dun[0]; + + return 0; +} +EXPORT_SYMBOL_GPL(ufshcd_prepare_lrbp_crypto_spec); + +/* Crypto Variant Ops Support */ + +void ufshcd_crypto_enable(struct ufs_hba *hba) +{ + if (hba->crypto_vops && hba->crypto_vops->enable) + return hba->crypto_vops->enable(hba); + + return ufshcd_crypto_enable_spec(hba); +} + +void ufshcd_crypto_disable(struct ufs_hba *hba) +{ + if (hba->crypto_vops && hba->crypto_vops->disable) + return hba->crypto_vops->disable(hba); + + return ufshcd_crypto_disable_spec(hba); +} + +int ufshcd_hba_init_crypto(struct ufs_hba *hba) +{ + if (hba->crypto_vops && hba->crypto_vops->hba_init_crypto) + return hba->crypto_vops->hba_init_crypto(hba, + &ufshcd_ksm_ops); + + return ufshcd_hba_init_crypto_spec(hba, &ufshcd_ksm_ops); +} + +void ufshcd_crypto_setup_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q) +{ + if (hba->crypto_vops && hba->crypto_vops->setup_rq_keyslot_manager) + return hba->crypto_vops->setup_rq_keyslot_manager(hba, q); + + return ufshcd_crypto_setup_rq_keyslot_manager_spec(hba, q); +} + +void ufshcd_crypto_destroy_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q) +{ + if (hba->crypto_vops && hba->crypto_vops->destroy_rq_keyslot_manager) + return hba->crypto_vops->destroy_rq_keyslot_manager(hba, q); + + return ufshcd_crypto_destroy_rq_keyslot_manager_spec(hba, q); +} + +int ufshcd_prepare_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp) +{ + if (hba->crypto_vops && hba->crypto_vops->prepare_lrbp_crypto) + return hba->crypto_vops->prepare_lrbp_crypto(hba, cmd, lrbp); + + return ufshcd_prepare_lrbp_crypto_spec(hba, cmd, lrbp); +} + +int ufshcd_map_sg_crypto(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +{ + if (hba->crypto_vops && hba->crypto_vops->map_sg_crypto) + return hba->crypto_vops->map_sg_crypto(hba, lrbp); + + return 0; +} + +int ufshcd_complete_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp) +{ + if (hba->crypto_vops && hba->crypto_vops->complete_lrbp_crypto) + return hba->crypto_vops->complete_lrbp_crypto(hba, cmd, lrbp); + + return 0; +} + +void ufshcd_crypto_debug(struct ufs_hba *hba) +{ + if (hba->crypto_vops && hba->crypto_vops->debug) + hba->crypto_vops->debug(hba); +} + +int ufshcd_crypto_suspend(struct ufs_hba *hba, + enum ufs_pm_op pm_op) +{ + if (hba->crypto_vops && hba->crypto_vops->suspend) + return hba->crypto_vops->suspend(hba, pm_op); + + return 0; +} + +int ufshcd_crypto_resume(struct ufs_hba *hba, + enum ufs_pm_op pm_op) +{ + if (hba->crypto_vops && hba->crypto_vops->resume) + return hba->crypto_vops->resume(hba, pm_op); + + return 0; +} + +void ufshcd_crypto_set_vops(struct ufs_hba *hba, + struct ufs_hba_crypto_variant_ops *crypto_vops) +{ + hba->crypto_vops = crypto_vops; +} diff --git a/drivers/scsi/ufs/ufshcd-crypto.h b/drivers/scsi/ufs/ufshcd-crypto.h new file mode 100644 index 0000000000000000000000000000000000000000..f223a06fbf930c8158f81d1c4c9406e2cc106a23 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-crypto.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef _UFSHCD_CRYPTO_H +#define _UFSHCD_CRYPTO_H + +#ifdef CONFIG_SCSI_UFS_CRYPTO +#include +#include "ufshcd.h" +#include "ufshci.h" + +static inline int ufshcd_num_keyslots(struct ufs_hba *hba) +{ + return hba->crypto_capabilities.config_count + 1; +} + +static inline bool ufshcd_keyslot_valid(struct ufs_hba *hba, unsigned int slot) +{ + /* + * The actual number of configurations supported is (CFGC+1), so slot + * numbers range from 0 to config_count inclusive. + */ + return slot < ufshcd_num_keyslots(hba); +} + +static inline bool ufshcd_hba_is_crypto_supported(struct ufs_hba *hba) +{ + return hba->crypto_capabilities.reg_val != 0; +} + +static inline bool ufshcd_is_crypto_enabled(struct ufs_hba *hba) +{ + return hba->caps & UFSHCD_CAP_CRYPTO; +} + +/* Functions implementing UFSHCI v2.1 specification behaviour */ +int ufshcd_crypto_cap_find(struct ufs_hba *hba, + enum blk_crypto_mode_num crypto_mode, + unsigned int data_unit_size); + +int ufshcd_prepare_lrbp_crypto_spec(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp); + +void ufshcd_crypto_enable_spec(struct ufs_hba *hba); + +void ufshcd_crypto_disable_spec(struct ufs_hba *hba); + +struct keyslot_mgmt_ll_ops; +int ufshcd_hba_init_crypto_spec(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops); + +void ufshcd_crypto_setup_rq_keyslot_manager_spec(struct ufs_hba *hba, + struct request_queue *q); + +void ufshcd_crypto_destroy_rq_keyslot_manager_spec(struct ufs_hba *hba, + struct request_queue *q); + +static inline bool ufshcd_lrbp_crypto_enabled(struct ufshcd_lrb *lrbp) +{ + return lrbp->crypto_enable; +} + +/* Crypto Variant Ops Support */ +void ufshcd_crypto_enable(struct ufs_hba *hba); + +void ufshcd_crypto_disable(struct ufs_hba *hba); + +int ufshcd_hba_init_crypto(struct ufs_hba *hba); + +void ufshcd_crypto_setup_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q); + +void ufshcd_crypto_destroy_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q); + +int ufshcd_prepare_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp); + +int ufshcd_map_sg_crypto(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); + +int ufshcd_complete_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp); + +void ufshcd_crypto_debug(struct ufs_hba *hba); + +int ufshcd_crypto_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op); + +int ufshcd_crypto_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op); + +void ufshcd_crypto_set_vops(struct ufs_hba *hba, + struct ufs_hba_crypto_variant_ops *crypto_vops); + +#else /* CONFIG_SCSI_UFS_CRYPTO */ + +static inline bool ufshcd_keyslot_valid(struct ufs_hba *hba, + unsigned int slot) +{ + return false; +} + +static inline bool ufshcd_hba_is_crypto_supported(struct ufs_hba *hba) +{ + return false; +} + +static inline bool ufshcd_is_crypto_enabled(struct ufs_hba *hba) +{ + return false; +} + +static inline void ufshcd_crypto_enable(struct ufs_hba *hba) { } + +static inline void ufshcd_crypto_disable(struct ufs_hba *hba) { } + +static inline int ufshcd_hba_init_crypto(struct ufs_hba *hba) +{ + return 0; +} + +static inline void ufshcd_crypto_setup_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q) { } + +static inline void ufshcd_crypto_destroy_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q) { } + +static inline int ufshcd_prepare_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp) +{ + return 0; +} + +static inline int ufshcd_map_sg_crypto(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp) +{ + return 0; +} + +static inline bool ufshcd_lrbp_crypto_enabled(struct ufshcd_lrb *lrbp) +{ + return false; +} + +static inline int ufshcd_complete_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp) +{ + return 0; +} + +static inline void ufshcd_crypto_debug(struct ufs_hba *hba) { } + +static inline int ufshcd_crypto_suspend(struct ufs_hba *hba, + enum ufs_pm_op pm_op) +{ + return 0; +} + +static inline int ufshcd_crypto_resume(struct ufs_hba *hba, + enum ufs_pm_op pm_op) +{ + return 0; +} + +static inline void ufshcd_crypto_set_vops(struct ufs_hba *hba, + struct ufs_hba_crypto_variant_ops *crypto_vops) { } + +#endif /* CONFIG_SCSI_UFS_CRYPTO */ + +#endif /* _UFSHCD_CRYPTO_H */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b2af53cadd6f2056f72ed39e60504c688ccae591..abedcca0e79378bf976a0b2a2b6f4ddb5d952497 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -197,6 +197,7 @@ static void ufshcd_update_uic_error_cnt(struct ufs_hba *hba, u32 reg, int type) break; } } +#include "ufshcd-crypto.h" #define CREATE_TRACE_POINTS #include @@ -918,6 +919,8 @@ static inline void __ufshcd_print_host_regs(struct ufs_hba *hba, bool no_sleep) static void ufshcd_print_host_regs(struct ufs_hba *hba) { __ufshcd_print_host_regs(hba, false); + + ufshcd_crypto_debug(hba); } static @@ -950,8 +953,11 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) ufshcd_hex_dump(hba, "UPIU RSP", lrbp->ucd_rsp_ptr, sizeof(struct utp_upiu_rsp)); - prdt_length = le16_to_cpu( - lrbp->utr_descriptor_ptr->prd_table_length); + prdt_length = + le16_to_cpu(lrbp->utr_descriptor_ptr->prd_table_length); + if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) + prdt_length /= hba->sg_entry_size; + dev_err(hba->dev, "UPIU[%d] - PRDT - %d entries phys@0x%llx\n", tag, prdt_length, @@ -959,7 +965,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) if (pr_prdt) ufshcd_hex_dump(hba, "UPIU PRDT", lrbp->ucd_prdt_ptr, - sizeof(struct ufshcd_sg_entry) * prdt_length); + hba->sg_entry_size * prdt_length); } } @@ -1406,8 +1412,11 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba) { u32 val = CONTROLLER_ENABLE; - if (ufshcd_is_crypto_supported(hba)) + if (ufshcd_hba_is_crypto_supported(hba)) { + ufshcd_crypto_enable(hba); val |= CRYPTO_GENERAL_ENABLE; + } + ufshcd_writel(hba, val, REG_CONTROLLER_ENABLE); } @@ -2184,7 +2193,6 @@ int ufshcd_hold(struct ufs_hba *hba, bool async) hba->clk_gating.active_reqs--; break; } - spin_unlock_irqrestore(hba->host->host_lock, flags); flush_work(&hba->clk_gating.ungate_work); spin_lock_irqsave(hba->host->host_lock, flags); @@ -3277,7 +3285,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) */ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { - struct ufshcd_sg_entry *prd_table; + struct ufshcd_sg_entry *prd; struct scatterlist *sg; struct scsi_cmnd *cmd; int sg_segments; @@ -3292,27 +3300,28 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16((u16)(sg_segments * - sizeof(struct ufshcd_sg_entry))); + hba->sg_entry_size)); else lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16((u16) (sg_segments)); - prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; + prd = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; scsi_for_each_sg(cmd, sg, sg_segments, i) { - prd_table[i].size = + prd->size = cpu_to_le32(((u32) sg_dma_len(sg))-1); - prd_table[i].base_addr = + prd->base_addr = cpu_to_le32(lower_32_bits(sg->dma_address)); - prd_table[i].upper_addr = + prd->upper_addr = cpu_to_le32(upper_32_bits(sg->dma_address)); - prd_table[i].reserved = 0; + prd->reserved = 0; + prd = (void *)prd + hba->sg_entry_size; } } else { lrbp->utr_descriptor_ptr->prd_table_length = 0; } - return 0; + return ufshcd_map_sg_crypto(hba, lrbp); } /** @@ -3357,41 +3366,6 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs) ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); } -static int ufshcd_prepare_crypto_utrd(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp) -{ - struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr; - u8 cc_index = 0; - bool enable = false; - u64 dun = 0; - int ret; - - /* - * Call vendor specific code to get crypto info for this request: - * enable, crypto config. index, DUN. - * If bypass is set, don't bother setting the other fields. - */ - ret = ufshcd_vops_crypto_req_setup(hba, lrbp, &cc_index, &enable, &dun); - if (ret) { - if (ret != -EAGAIN) { - dev_err(hba->dev, - "%s: failed to setup crypto request (%d)\n", - __func__, ret); - } - - return ret; - } - - if (!enable) - goto out; - - req_desc->header.dword_0 |= cc_index | UTRD_CRYPTO_ENABLE; - req_desc->header.dword_1 = (u32)(dun & 0xFFFFFFFF); - req_desc->header.dword_3 = (u32)((dun >> 32) & 0xFFFFFFFF); -out: - return 0; -} - /** * ufshcd_prepare_req_desc_hdr() - Fills the requests header * descriptor according to request @@ -3425,9 +3399,23 @@ static int ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, dword_0 |= UTP_REQ_DESC_INT_CMD; /* Transfer request descriptor header fields */ + if (ufshcd_lrbp_crypto_enabled(lrbp)) { +#if IS_ENABLED(CONFIG_SCSI_UFS_CRYPTO) + dword_0 |= UTP_REQ_DESC_CRYPTO_ENABLE_CMD; + dword_0 |= lrbp->crypto_key_slot; + req_desc->header.dword_1 = + cpu_to_le32(lower_32_bits(lrbp->data_unit_num)); + req_desc->header.dword_3 = + cpu_to_le32(upper_32_bits(lrbp->data_unit_num)); +#endif /* CONFIG_SCSI_UFS_CRYPTO */ + } else { + /* dword_1 and dword_3 are reserved, hence they are set to 0 */ + req_desc->header.dword_1 = 0; + req_desc->header.dword_3 = 0; + } + req_desc->header.dword_0 = cpu_to_le32(dword_0); - /* dword_1 is reserved, hence it is set to 0 */ - req_desc->header.dword_1 = 0; + /* * assigning invalid value for command status. Controller * updates OCS on command completion, with the command @@ -3435,14 +3423,9 @@ static int ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, */ req_desc->header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); - /* dword_3 is reserved, hence it is set to 0 */ - req_desc->header.dword_3 = 0; req_desc->prd_table_length = 0; - if (ufshcd_is_crypto_supported(hba)) - return ufshcd_prepare_crypto_utrd(hba, lrbp); - return 0; } @@ -3706,13 +3689,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) err = ufshcd_get_read_lock(hba, cmd->device->lun); if (unlikely(err < 0)) { if (err == -EPERM) { - if (!ufshcd_vops_crypto_engine_get_req_status(hba)) { - set_host_byte(cmd, DID_ERROR); - cmd->scsi_done(cmd); - return 0; - } else { - return SCSI_MLQUEUE_HOST_BUSY; - } + return SCSI_MLQUEUE_HOST_BUSY; } if (err == -EAGAIN) return SCSI_MLQUEUE_HOST_BUSY; @@ -3823,6 +3800,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) lrbp->task_tag = tag; lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false; + + err = ufshcd_prepare_lrbp_crypto(hba, cmd, lrbp); + if (err) { + lrbp->cmd = NULL; + clear_bit_unlock(tag, &hba->lrb_in_use); + goto out; + } lrbp->req_abort_skip = false; err = ufshcd_comp_scsi_upiu(hba, lrbp); @@ -3848,22 +3832,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto out; } - err = ufshcd_vops_crypto_engine_cfg_start(hba, tag); - if (err) { - if (err != -EAGAIN) - dev_err(hba->dev, - "%s: failed to configure crypto engine %d\n", - __func__, err); - - scsi_dma_unmap(lrbp->cmd); - lrbp->cmd = NULL; - clear_bit_unlock(tag, &hba->lrb_in_use); - ufshcd_release_all(hba); - ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); - - goto out; - } - /* Make sure descriptors are ready before ringing the doorbell */ wmb(); @@ -3879,7 +3847,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) clear_bit_unlock(tag, &hba->lrb_in_use); ufshcd_release_all(hba); ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); - ufshcd_vops_crypto_engine_cfg_end(hba, lrbp, cmd->request); dev_err(hba->dev, "%s: failed sending command, %d\n", __func__, err); err = DID_ERROR; @@ -3903,6 +3870,9 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba, lrbp->task_tag = tag; lrbp->lun = 0; /* device management cmd is not specific to any LUN */ lrbp->intr_cmd = true; /* No interrupt aggregation */ +#if IS_ENABLED(CONFIG_SCSI_UFS_CRYPTO) + lrbp->crypto_enable = false; /* No crypto operations */ +#endif hba->dev_cmd.type = cmd_type; return ufshcd_comp_devman_upiu(hba, lrbp); @@ -4760,7 +4730,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) size_t utmrdl_size, utrdl_size, ucdl_size; /* Allocate memory for UTP command descriptors */ - ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs); + ucdl_size = (sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs); hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, ucdl_size, &hba->ucdl_dma_addr, @@ -4856,7 +4826,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); - cmd_desc_size = sizeof(struct utp_transfer_cmd_desc); + cmd_desc_size = sizeof_utp_transfer_cmd_desc(hba); cmd_desc_dma_addr = hba->ucdl_dma_addr; for (i = 0; i < hba->nutrs; i++) { @@ -4888,17 +4858,17 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) hba->lrb[i].utr_descriptor_ptr = (utrdlp + i); hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr + (i * sizeof(struct utp_transfer_req_desc)); - hba->lrb[i].ucd_req_ptr = - (struct utp_upiu_req *)(cmd_descp + i); + hba->lrb[i].ucd_req_ptr = (struct utp_upiu_req *)cmd_descp; hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr; hba->lrb[i].ucd_rsp_ptr = - (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; + (struct utp_upiu_rsp *)cmd_descp->response_upiu; hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; hba->lrb[i].ucd_prdt_ptr = - (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; + (struct ufshcd_sg_entry *)cmd_descp->prd_table; hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset; + cmd_descp = (void *)cmd_descp + cmd_desc_size; } } @@ -5756,6 +5726,8 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep) { int err; + ufshcd_crypto_disable(hba); + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE); err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE, CONTROLLER_ENABLE, CONTROLLER_DISABLE, @@ -6127,8 +6099,8 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) */ static int ufshcd_slave_configure(struct scsi_device *sdev) { - struct request_queue *q = sdev->request_queue; struct ufs_hba *hba = shost_priv(sdev->host); + struct request_queue *q = sdev->request_queue; blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX); @@ -6140,6 +6112,7 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) sdev->autosuspend_delay = UFSHCD_AUTO_SUSPEND_DELAY_MS; sdev->use_rpm_auto = 1; + ufshcd_crypto_setup_rq_keyslot_manager(hba, q); return 0; } @@ -6151,6 +6124,7 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) static void ufshcd_slave_destroy(struct scsi_device *sdev) { struct ufs_hba *hba; + struct request_queue *q = sdev->request_queue; hba = shost_priv(sdev->host); /* Drop the reference as it won't be needed anymore */ @@ -6161,6 +6135,8 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) hba->sdev_ufs_device = NULL; spin_unlock_irqrestore(hba->host->host_lock, flags); } + + ufshcd_crypto_destroy_rq_keyslot_manager(hba, q); } /** @@ -6436,6 +6412,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, clear_bit_unlock(index, &hba->lrb_in_use); lrbp->complete_time_stamp = ktime_get(); update_req_stats(hba, lrbp); + ufshcd_complete_lrbp_crypto(hba, cmd, lrbp); /* Mark completed command as NULL in LRB */ lrbp->cmd = NULL; hba->ufs_stats.clk_rel.ctx = XFR_REQ_COMPL; @@ -6449,8 +6426,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, */ ufshcd_vops_pm_qos_req_end(hba, cmd->request, false); - ufshcd_vops_crypto_engine_cfg_end(hba, - lrbp, cmd->request); } req = cmd->request; @@ -6533,8 +6508,6 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result) */ ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); - ufshcd_vops_crypto_engine_cfg_end(hba, - lrbp, cmd->request); } /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); @@ -6720,6 +6693,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) hba->auto_bkops_enabled = false; trace_ufshcd_auto_bkops_state(dev_name(hba->dev), 0); + hba->is_urgent_bkops_lvl_checked = false; out: return err; } @@ -6744,6 +6718,7 @@ static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS; ufshcd_disable_auto_bkops(hba); } + hba->is_urgent_bkops_lvl_checked = false; } static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status) @@ -6790,6 +6765,7 @@ static int ufshcd_bkops_ctrl(struct ufs_hba *hba, err = ufshcd_enable_auto_bkops(hba); else err = ufshcd_disable_auto_bkops(hba); + hba->urgent_bkops_lvl = curr_status; out: return err; } @@ -7468,8 +7444,6 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) ufsdbg_error_inject_dispatcher(hba, ERR_INJECT_INTR, intr_status, &intr_status); - ufshcd_vops_crypto_engine_get_status(hba, &hba->ce_error); - hba->errors = UFSHCD_ERROR_MASK & intr_status; if (hba->errors || hba->ce_error) retval |= ufshcd_check_errors(hba); @@ -7946,16 +7920,6 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) goto out; } - if (!err) { - err = ufshcd_vops_crypto_engine_reset(hba); - if (err) { - dev_err(hba->dev, - "%s: failed to reset crypto engine %d\n", - __func__, err); - goto out; - } - } - out: if (err) dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err); @@ -7992,7 +7956,6 @@ static int ufshcd_detect_device(struct ufs_hba *hba) static int ufshcd_reset_and_restore(struct ufs_hba *hba) { int err = 0; - unsigned long flags; int retries = MAX_HOST_RESET_RETRIES; ufshcd_enable_irq(hba); @@ -8008,15 +7971,6 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) if (err && ufshcd_is_embedded_dev(hba)) BUG(); - /* - * After reset the door-bell might be cleared, complete - * outstanding requests in s/w here. - */ - spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_transfer_req_compl(hba); - ufshcd_tmc_handler(hba); - spin_unlock_irqrestore(hba->host->host_lock, flags); - return err; } @@ -8910,7 +8864,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) hba->dev_info.f_power_on_wp_en = flag; /* Add required well known logical units to scsi mid layer */ - if (ufshcd_scsi_add_wlus(hba)) + ret = ufshcd_scsi_add_wlus(hba); + if (ret) goto out; /* lower VCC voltage level */ @@ -10187,6 +10142,10 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) req_link_state = UIC_LINK_OFF_STATE; } + ret = ufshcd_crypto_suspend(hba, pm_op); + if (ret) + goto out; + /* * If we can't transition into any of the low power modes * just gate the clocks. @@ -10307,6 +10266,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) hba->hibern8_on_idle.is_suspended = false; hba->clk_gating.is_suspended = false; ufshcd_release_all(hba); + ufshcd_crypto_resume(hba, pm_op); out: hba->pm_op_in_progress = 0; @@ -10330,9 +10290,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) { int ret; enum uic_link_state old_link_state; + enum ufs_dev_pwr_mode old_pwr_mode; hba->pm_op_in_progress = 1; old_link_state = hba->uic_link_state; + old_pwr_mode = hba->curr_dev_pwr_mode; ufshcd_hba_vreg_set_hpm(hba); /* Make sure clocks are enabled before accessing controller */ @@ -10409,6 +10371,10 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto set_old_link_state; } + ret = ufshcd_crypto_resume(hba, pm_op); + if (ret) + goto set_old_dev_pwr_mode; + if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) ufshcd_enable_auto_bkops(hba); else @@ -10429,6 +10395,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_release_all(hba); goto out; +set_old_dev_pwr_mode: + if (old_pwr_mode != hba->curr_dev_pwr_mode) + ufshcd_set_dev_pwr_mode(hba, old_pwr_mode); set_old_link_state: ufshcd_link_state_transition(hba, old_link_state, 0); if (ufshcd_is_link_hibern8(hba) && @@ -11107,6 +11076,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) hba->host = host; hba->dev = dev; *hba_handle = hba; + hba->sg_entry_size = sizeof(struct ufshcd_sg_entry); INIT_LIST_HEAD(&hba->clk_list_head); @@ -11258,6 +11228,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) if (hba->force_g4) hba->reinit_g4_rate_A = true; + /* Init crypto */ + err = ufshcd_hba_init_crypto(hba); + if (err) { + dev_err(hba->dev, "crypto setup failed\n"); + goto out_remove_scsi_host; + } /* Host controller enable */ err = ufshcd_hba_enable(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 52f1b21bb58d6454398de6476a76cbc044d5bc2a..7621eaf514044a60ddaa89846bb609bcc396ef0d 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -197,6 +197,9 @@ struct ufs_pm_lvl_states { * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation) * @issue_time_stamp: time stamp for debug purposes * @complete_time_stamp: time stamp for statistics + * @crypto_enable: whether or not the request needs inline crypto operations + * @crypto_key_slot: the key slot to use for inline crypto + * @data_unit_num: the data unit number for the first block for inline crypto * @req_abort_skip: skip request abort task flag */ struct ufshcd_lrb { @@ -221,6 +224,11 @@ struct ufshcd_lrb { bool intr_cmd; ktime_t issue_time_stamp; ktime_t complete_time_stamp; +#if IS_ENABLED(CONFIG_SCSI_UFS_CRYPTO) + bool crypto_enable; + u8 crypto_key_slot; + u64 data_unit_num; +#endif /* CONFIG_SCSI_UFS_CRYPTO */ bool req_abort_skip; }; @@ -302,6 +310,8 @@ struct ufs_pwr_mode_info { struct ufs_pa_layer_attr info; }; +union ufs_crypto_cfg_entry; + /** * struct ufs_hba_variant_ops - variant specific callbacks * @init: called when the driver is initialized @@ -332,6 +342,7 @@ struct ufs_pwr_mode_info { * scale down * @set_bus_vote: called to vote for the required bus bandwidth * @phy_initialization: used to initialize phys + * @program_key: program an inline encryption key into a keyslot */ struct ufs_hba_variant_ops { int (*init)(struct ufs_hba *); @@ -367,30 +378,8 @@ struct ufs_hba_variant_ops { void (*add_debugfs)(struct ufs_hba *hba, struct dentry *root); void (*remove_debugfs)(struct ufs_hba *hba); #endif -}; - -/** - * struct ufs_hba_crypto_variant_ops - variant specific crypto callbacks - * @crypto_req_setup: retreieve the necessary cryptographic arguments to setup - a requests's transfer descriptor. - * @crypto_engine_cfg_start: start configuring cryptographic engine - * according to tag - * parameter - * @crypto_engine_cfg_end: end configuring cryptographic engine - * according to tag parameter - * @crypto_engine_reset: perform reset to the cryptographic engine - * @crypto_engine_get_status: get errors status of the cryptographic engine - * @crypto_get_req_status: Check if crypto driver still holds request or not - */ -struct ufs_hba_crypto_variant_ops { - int (*crypto_req_setup)(struct ufs_hba *, struct ufshcd_lrb *lrbp, - u8 *cc_index, bool *enable, u64 *dun); - int (*crypto_engine_cfg_start)(struct ufs_hba *, unsigned int); - int (*crypto_engine_cfg_end)(struct ufs_hba *, struct ufshcd_lrb *, - struct request *); - int (*crypto_engine_reset)(struct ufs_hba *); - int (*crypto_engine_get_status)(struct ufs_hba *, u32 *); - int (*crypto_get_req_status)(struct ufs_hba *); + int (*program_key)(struct ufs_hba *hba, + const union ufs_crypto_cfg_entry *cfg, int slot); }; /** @@ -409,10 +398,32 @@ struct ufs_hba_variant { struct device *dev; const char *name; struct ufs_hba_variant_ops *vops; - struct ufs_hba_crypto_variant_ops *crypto_vops; struct ufs_hba_pm_qos_variant_ops *pm_qos_vops; }; +struct keyslot_mgmt_ll_ops; +struct ufs_hba_crypto_variant_ops { + void (*setup_rq_keyslot_manager)(struct ufs_hba *hba, + struct request_queue *q); + void (*destroy_rq_keyslot_manager)(struct ufs_hba *hba, + struct request_queue *q); + int (*hba_init_crypto)(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops); + void (*enable)(struct ufs_hba *hba); + void (*disable)(struct ufs_hba *hba); + int (*suspend)(struct ufs_hba *hba, enum ufs_pm_op pm_op); + int (*resume)(struct ufs_hba *hba, enum ufs_pm_op pm_op); + int (*debug)(struct ufs_hba *hba); + int (*prepare_lrbp_crypto)(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp); + int (*map_sg_crypto)(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); + int (*complete_lrbp_crypto)(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp); + void *priv; +}; + /* clock gating state */ enum clk_gating_state { CLKS_OFF, @@ -733,6 +744,7 @@ enum ufshcd_card_state { * @ufs_version: UFS Version to which controller complies * @var: pointer to variant specific data * @priv: pointer to variant specific private data + * @sg_entry_size: size of struct ufshcd_sg_entry (may include variant fields) * @irq: Irq number of the controller * @active_uic_cmd: handle of active UIC command * @uic_cmd_mutex: mutex for uic command @@ -752,6 +764,7 @@ enum ufshcd_card_state { * @uic_error: UFS interconnect layer error status * @saved_err: sticky error mask * @saved_uic_err: sticky UIC error mask + * @silence_err_logs: flag to silence error logs * @dev_cmd: ufs device management command information * @last_dme_cmd_tstamp: time stamp of the last completed DME command * @auto_bkops_enabled: to track whether bkops is enabled in device @@ -772,6 +785,10 @@ enum ufshcd_card_state { * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for * device is known or not. * @scsi_block_reqs_cnt: reference counting for scsi block requests + * @crypto_capabilities: Content of crypto capabilities register (0x100) + * @crypto_cap_array: Array of crypto capabilities + * @crypto_cfg_register: Start of the crypto cfg array + * @ksm: the keyslot manager tied to this hba */ struct ufs_hba { void __iomem *mmio_base; @@ -816,6 +833,8 @@ struct ufs_hba { u32 ufs_version; struct ufs_hba_variant *var; void *priv; + size_t sg_entry_size; + const struct ufs_hba_crypto_variant_ops *crypto_vops; unsigned int irq; bool is_irq_enabled; bool crash_on_err; @@ -905,6 +924,12 @@ struct ufs_hba { /* Auto hibern8 support is broken */ #define UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 UFS_BIT(15) + /* + * This quirk needs to be enabled if the host controller advertises + * inline encryption support but it doesn't work correctly. + */ + #define UFSHCD_QUIRK_BROKEN_CRYPTO UFS_BIT(16) + unsigned int quirks; /* Deviations from standard UFSHCI spec. */ wait_queue_head_t tm_wq; @@ -1017,6 +1042,11 @@ struct ufs_hba { * in hibern8 then enable this cap. */ #define UFSHCD_CAP_POWER_COLLAPSE_DURING_HIBERN8 (1 << 7) + /* + * This capability allows the host controller driver to use the + * inline crypto engine, if it is present + */ +#define UFSHCD_CAP_CRYPTO (1 << 8) struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; @@ -1049,6 +1079,14 @@ struct ufs_hba { bool force_g4; /* distinguish between resume and restore */ bool restore; + +#ifdef CONFIG_SCSI_UFS_CRYPTO + /* crypto */ + union ufs_crypto_capabilities crypto_capabilities; + union ufs_crypto_cap_entry *crypto_cap_array; + u32 crypto_cfg_register; + struct keyslot_manager *ksm; +#endif /* CONFIG_SCSI_UFS_CRYPTO */ }; static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba) @@ -1498,55 +1536,6 @@ static inline void ufshcd_vops_remove_debugfs(struct ufs_hba *hba) } #endif -static inline int ufshcd_vops_crypto_req_setup(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp, u8 *cc_index, bool *enable, u64 *dun) -{ - if (hba->var && hba->var->crypto_vops && - hba->var->crypto_vops->crypto_req_setup) - return hba->var->crypto_vops->crypto_req_setup(hba, lrbp, - cc_index, enable, dun); - return 0; -} - -static inline int ufshcd_vops_crypto_engine_cfg_start(struct ufs_hba *hba, - unsigned int task_tag) -{ - if (hba->var && hba->var->crypto_vops && - hba->var->crypto_vops->crypto_engine_cfg_start) - return hba->var->crypto_vops->crypto_engine_cfg_start - (hba, task_tag); - return 0; -} - -static inline int ufshcd_vops_crypto_engine_cfg_end(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp, - struct request *req) -{ - if (hba->var && hba->var->crypto_vops && - hba->var->crypto_vops->crypto_engine_cfg_end) - return hba->var->crypto_vops->crypto_engine_cfg_end - (hba, lrbp, req); - return 0; -} - -static inline int ufshcd_vops_crypto_engine_reset(struct ufs_hba *hba) -{ - if (hba->var && hba->var->crypto_vops && - hba->var->crypto_vops->crypto_engine_reset) - return hba->var->crypto_vops->crypto_engine_reset(hba); - return 0; -} - -static inline int ufshcd_vops_crypto_engine_get_status(struct ufs_hba *hba, - u32 *status) -{ - if (hba->var && hba->var->crypto_vops && - hba->var->crypto_vops->crypto_engine_get_status) - return hba->var->crypto_vops->crypto_engine_get_status(hba, - status); - return 0; -} - static inline void ufshcd_vops_pm_qos_req_start(struct ufs_hba *hba, struct request *req) { @@ -1562,13 +1551,4 @@ static inline void ufshcd_vops_pm_qos_req_end(struct ufs_hba *hba, hba->var->pm_qos_vops->req_end(hba, req, lock); } -static inline int ufshcd_vops_crypto_engine_get_req_status(struct ufs_hba *hba) - -{ - if (hba->var && hba->var->crypto_vops && - hba->var->crypto_vops->crypto_get_req_status) - return hba->var->crypto_vops->crypto_get_req_status(hba); - return 0; -} - #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 173cffe4226ddfbda37df0111298b9608973cc74..764662fc685d43a8ae6b1bf6e86598f1a48b242c 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -347,6 +347,61 @@ enum { INTERRUPT_MASK_ALL_VER_21 = 0x71FFF, }; +/* CCAP - Crypto Capability 100h */ +union ufs_crypto_capabilities { + __le32 reg_val; + struct { + u8 num_crypto_cap; + u8 config_count; + u8 reserved; + u8 config_array_ptr; + }; +}; + +enum ufs_crypto_key_size { + UFS_CRYPTO_KEY_SIZE_INVALID = 0x0, + UFS_CRYPTO_KEY_SIZE_128 = 0x1, + UFS_CRYPTO_KEY_SIZE_192 = 0x2, + UFS_CRYPTO_KEY_SIZE_256 = 0x3, + UFS_CRYPTO_KEY_SIZE_512 = 0x4, +}; + +enum ufs_crypto_alg { + UFS_CRYPTO_ALG_AES_XTS = 0x0, + UFS_CRYPTO_ALG_BITLOCKER_AES_CBC = 0x1, + UFS_CRYPTO_ALG_AES_ECB = 0x2, + UFS_CRYPTO_ALG_ESSIV_AES_CBC = 0x3, +}; + +/* x-CRYPTOCAP - Crypto Capability X */ +union ufs_crypto_cap_entry { + __le32 reg_val; + struct { + u8 algorithm_id; + u8 sdus_mask; /* Supported data unit size mask */ + u8 key_size; + u8 reserved; + }; +}; + +#define UFS_CRYPTO_CONFIGURATION_ENABLE (1 << 7) +#define UFS_CRYPTO_KEY_MAX_SIZE 64 +/* x-CRYPTOCFG - Crypto Configuration X */ +union ufs_crypto_cfg_entry { + __le32 reg_val[32]; + struct { + u8 crypto_key[UFS_CRYPTO_KEY_MAX_SIZE]; + u8 data_unit_size; + u8 crypto_cap_idx; + u8 reserved_1; + u8 config_enable; + u8 reserved_multi_host; + u8 reserved_2; + u8 vsb[2]; + u8 reserved_3[56]; + }; +}; + /* * Request Descriptor Definitions */ @@ -368,6 +423,7 @@ enum { UTP_NATIVE_UFS_COMMAND = 0x10000000, UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000, UTP_REQ_DESC_INT_CMD = 0x01000000, + UTP_REQ_DESC_CRYPTO_ENABLE_CMD = 0x00800000, }; /* UTP Transfer Request Data Direction (DD) */ @@ -411,21 +467,28 @@ struct ufshcd_sg_entry { __le32 upper_addr; __le32 reserved; __le32 size; + /* + * followed by variant-specific fields if + * hba->sg_entry_size != sizeof(struct ufshcd_sg_entry) + */ }; /** * struct utp_transfer_cmd_desc - UFS Command Descriptor structure * @command_upiu: Command UPIU Frame address * @response_upiu: Response UPIU Frame address - * @prd_table: Physical Region Descriptor + * @prd_table: Physical Region Descriptor: an array of SG_ALL struct + * ufshcd_sg_entry's. Variant-specific fields may be present after each. */ struct utp_transfer_cmd_desc { u8 command_upiu[ALIGNED_UPIU_SIZE]; u8 response_upiu[ALIGNED_UPIU_SIZE]; - struct ufshcd_sg_entry prd_table[SG_ALL]; + u8 prd_table[]; }; #define UTRD_CRYPTO_ENABLE UFS_BIT(23) +#define sizeof_utp_transfer_cmd_desc(hba) \ + (sizeof(struct utp_transfer_cmd_desc) + SG_ALL * (hba)->sg_entry_size) /** * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 3a12123de46629d4c0271b8e325449b2eaa94ce6..0e083fe8b893f6ea1769383662caa7fe3e03ba9b 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -97,8 +97,8 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) { struct imx_pm_domain *pd = to_imx_pm_domain(genpd); - int i, ret, sw, sw2iso; - u32 val; + int i, ret; + u32 val, req; if (pd->supply) { ret = regulator_enable(pd->supply); @@ -117,17 +117,18 @@ static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, 0x1, 0x1); - /* Read ISO and ISO2SW power up delays */ - regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); - sw = val & 0x3f; - sw2iso = (val >> 8) & 0x3f; - /* Request GPC to power up domain */ - val = BIT(pd->cntr_pdn_bit + 1); - regmap_update_bits(pd->regmap, GPC_CNTR, val, val); + req = BIT(pd->cntr_pdn_bit + 1); + regmap_update_bits(pd->regmap, GPC_CNTR, req, req); - /* Wait ISO + ISO2SW IPG clock cycles */ - udelay(DIV_ROUND_UP(sw + sw2iso, pd->ipg_rate_mhz)); + /* Wait for the PGC to handle the request */ + ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req), + 1, 50); + if (ret) + pr_err("powerup request on domain %s timed out\n", genpd->name); + + /* Wait for reset to propagate through peripherals */ + usleep_range(5, 10); /* Disable reset clocks for all devices in the domain */ for (i = 0; i < pd->num_clks; i++) @@ -329,6 +330,7 @@ static const struct regmap_config imx_gpc_regmap_config = { .rd_table = &access_table, .wr_table = &access_table, .max_register = 0x2ac, + .fast_io = true, }; static struct generic_pm_domain *imx_gpc_onecell_domains[] = { diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 8d9c0e27508f0958ff749857eaa48819495da895..8e393e7bf8da47a1b2bb08be2c3283247ad8604c 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1031,6 +1031,24 @@ config MSM_BAM_DMUX communication between G-Link/bg_com_dev and BG processor over SPI. This handle the interrupts raised by BG and notify the G-link with interrupt event and event data. + +config MSM_BGRSB + bool "Provide support for rsb events on Blackghost chipset" + help + BGRSB communicates to BG over rpmsg driver for RSB configuration and + enable/disable on device power state change. It enables/disables + the regulator specific to RSB. Sends the side band events generated + by BG to input framework. + +config MSM_BGRSB_RPMSG + bool "Provide support for Blackghost events to RSB" + depends on MSM_BGRSB + help + BGRSB-RPMSG informs BGRSB driver if GLINK channel has been + opened by remote processor. It doesn't maintain state machine + and is probed when BG opens channel and removed when the + channel is closed by remote processor. + config MSM_PIL_SSR_BG tristate "MSM Subsystem Blackghost(BG) Support" depends on MSM_PIL && MSM_SUBSYSTEM_RESTART @@ -1050,6 +1068,23 @@ config QCOM_SOC_INFO based on the chip ID and querying the SoC revision. This information is loaded by the bootloader into SMEM during the boot up process. +config QTI_CRYPTO_COMMON + tristate "Enable common crypto functionality used for FBE" + depends on BLK_INLINE_ENCRYPTION + help + Say 'Y' to enable the common crypto implementation to be used by + different storage layers such as UFS and EMMC for file based hardware + encryption. This library implements API to program and evict + keys using Trustzone or Hardware Key Manager. + +config QTI_CRYPTO_TZ + tristate "Enable Trustzone to be used for FBE" + depends on QTI_CRYPTO_COMMON + help + Say 'Y' to enable routing crypto requests to Trustzone while + performing hardware based file encryption. This means keys are + programmed and managed through SCM calls to TZ where ICE driver + will configure keys. endmenu config QCOM_HYP_CORE_CTL @@ -1061,4 +1096,10 @@ config QCOM_HYP_CORE_CTL An offline CPU is considered as a reserved CPU since this OS can't use it. +config RENAME_BLOCK_DEVICE + bool "Rename block device node in /dev" + help + This driver is used to rename the block device node assigned by generic driver + to a name that is needed. + source "drivers/soc/qcom/wcnss/Kconfig" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 9c2a3fb9fd36a34f1811c1d9a03f99aef3f5d2d7..cbc9f4da85b8cafbb506697a68371338e1de72c9 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -71,6 +71,8 @@ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o obj-$(CONFIG_SDX_EXT_IPC) += sdx_ext_ipc.o obj-$(CONFIG_MSM_PIL_SSR_BG) += subsys-pil-bg.o obj-$(CONFIG_QTI_NOTIFY_SIDEBAND) += sideband_notify.o +obj-$(CONFIG_MSM_BGRSB) += bg_rsb.o +obj-$(CONFIG_MSM_BGRSB_RPMSG) += bgrsb_rpmsg.o ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += subsystem_notif.o @@ -118,3 +120,6 @@ obj-$(CONFIG_QCOM_ADSP_MANUAL_VOTE) += adsp_vote_qmi.o adsp_lpm_voting_v01.o obj-$(CONFIG_CPU_V7) += idle-v7.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o obj-$(CONFIG_WCNSS_CORE) += wcnss/ +obj-$(CONFIG_RENAME_BLOCK_DEVICE) += rename_block_device.o +obj-$(CONFIG_QTI_CRYPTO_COMMON) += crypto-qti-common.o +obj-$(CONFIG_QTI_CRYPTO_TZ) += crypto-qti-tz.o diff --git a/drivers/soc/qcom/bg_rsb.c b/drivers/soc/qcom/bg_rsb.c new file mode 100644 index 0000000000000000000000000000000000000000..b3bc5145c5c202fbd9f089275ee3674236ba3cce --- /dev/null +++ b/drivers/soc/qcom/bg_rsb.c @@ -0,0 +1,888 @@ +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(msg) "bgrsb: %s: " msg, __func__ +#include "bgrsb.h" + +struct bgrsb_priv { + void *handle; + struct input_dev *input; + struct mutex glink_mutex; + struct mutex rsb_state_mutex; + enum bgrsb_state bgrsb_current_state; + void *lhndl; + struct work_struct bg_up_work; + struct work_struct bg_down_work; + struct work_struct rsb_up_work; + struct work_struct rsb_down_work; + struct work_struct rsb_calibration_work; + struct work_struct bttn_configr_work; + struct workqueue_struct *bgrsb_wq; + struct bgrsb_regulator rgltr; + enum ldo_task ldo_action; + void *bgwear_subsys_handle; + struct completion bg_resp_cmplt; + struct completion wrk_cmplt; + struct completion bg_lnikup_cmplt; + struct completion tx_done; + struct device *ldev; + struct wakeup_source bgrsb_ws; + wait_queue_head_t link_state_wait; + uint32_t calbrtion_intrvl; + uint32_t calbrtion_cpi; + uint8_t bttn_configs; + int msmrsb_gpio; + bool rsb_rpmsg; + bool rsb_use_msm_gpio; + bool is_in_twm; + bool calibration_needed; + bool is_calibrd; + bool is_cnfgrd; + bool blk_rsb_cmnds; + bool pending_enable; +}; + +static void *bgrsb_drv; +static int bgrsb_enable(struct bgrsb_priv *dev, bool enable); + +void bgrsb_send_input(struct event *evnt) +{ + uint8_t press_code; + uint8_t value; + struct bgrsb_priv *dev = + container_of(bgrsb_drv, struct bgrsb_priv, lhndl); + + pr_debug("%s: Called\n", __func__); + if (!evnt) { + pr_err("%s: No event received\n", __func__); + return; + } + if (evnt->sub_id == 1) { + input_report_rel(dev->input, REL_WHEEL, evnt->evnt_data); + input_sync(dev->input); + } else if (evnt->sub_id == 2) { + press_code = (uint8_t) evnt->evnt_data; + value = (uint8_t) (evnt->evnt_data >> 8); + + switch (press_code) { + case 0x1: + if (value == 0) { + input_report_key(dev->input, KEY_VOLUMEDOWN, 1); + input_sync(dev->input); + } else { + input_report_key(dev->input, KEY_VOLUMEDOWN, 0); + input_sync(dev->input); + } + break; + case 0x2: + if (value == 0) { + input_report_key(dev->input, KEY_VOLUMEUP, 1); + input_sync(dev->input); + } else { + input_report_key(dev->input, KEY_VOLUMEUP, 0); + input_sync(dev->input); + } + break; + case 0x3: + if (value == 0) { + input_report_key(dev->input, KEY_POWER, 1); + input_sync(dev->input); + } else { + input_report_key(dev->input, KEY_POWER, 0); + input_sync(dev->input); + } + break; + default: + pr_info("event: type[%d] , data: %d\n", + evnt->sub_id, evnt->evnt_data); + } + } + pr_debug("%s: Ended\n", __func__); +} +EXPORT_SYMBOL(bgrsb_send_input); + +static int bgrsb_init_regulators(struct device *pdev) +{ + struct regulator *reg11; + struct regulator *reg15; + struct bgrsb_priv *dev = dev_get_drvdata(pdev); + + reg11 = devm_regulator_get(pdev, "vdd-ldo1"); + if (IS_ERR_OR_NULL(reg11)) { + pr_err("Unable to get regulator for LDO-11\n"); + return PTR_ERR(reg11); + } + + reg15 = devm_regulator_get(pdev, "vdd-ldo2"); + if (IS_ERR_OR_NULL(reg15)) { + pr_err("Unable to get regulator for LDO-15\n"); + return PTR_ERR(reg15); + } + + dev->rgltr.regldo11 = reg11; + dev->rgltr.regldo15 = reg15; + return 0; +} + +static int bgrsb_set_ldo(struct bgrsb_priv *dev, enum ldo_task ldo_action) +{ + int ret = 0; + bool value; + + switch (ldo_action) { + case BGRSB_HW_TURN_ON: + ret = regulator_set_voltage(dev->rgltr.regldo11, + BGRSB_LDO11_VTG_MIN_UV, BGRSB_LDO11_VTG_MAX_UV); + if (ret) { + pr_err("Failed to request LDO-11 voltage %d\n", ret); + goto err_ret; + } + ret = regulator_enable(dev->rgltr.regldo11); + if (ret) { + pr_err("Failed to enable LDO-11 %d\n", ret); + goto err_ret; + } + break; + case BGRSB_ENABLE_WHEEL_EVENTS: + if (dev->rsb_use_msm_gpio == true) { + if (!gpio_is_valid(dev->msmrsb_gpio)) { + pr_err("gpio %d is not valid\n", + dev->msmrsb_gpio); + ret = -ENXIO; + goto err_ret; + } + + /* Sleep 50ms for h/w to detect signal */ + msleep(50); + + gpio_set_value(dev->msmrsb_gpio, 1); + value = gpio_get_value(dev->msmrsb_gpio); + if (value == true) { + pr_debug("gpio %d set properly\n", + dev->msmrsb_gpio); + } else { + pr_debug("gpio %d set failed\n", + dev->msmrsb_gpio); + ret = -ENXIO; + goto err_ret; + } + } else { + ret = regulator_set_voltage(dev->rgltr.regldo15, + BGRSB_LDO15_VTG_MIN_UV, BGRSB_LDO15_VTG_MAX_UV); + if (ret) { + pr_err("Request failed LDO-15 %d\n", + ret); + goto err_ret; + } + ret = regulator_enable(dev->rgltr.regldo15); + if (ret) { + pr_err("LDO-15 not enabled%d\n", + ret); + goto err_ret; + } + } + break; + case BGRSB_HW_TURN_OFF: + ret = regulator_disable(dev->rgltr.regldo11); + if (ret) { + pr_err("Failed to disable LDO-11 %d\n", ret); + goto err_ret; + } + break; + case BGRSB_DISABLE_WHEEL_EVENTS: + if (dev->rsb_use_msm_gpio == true) { + if (!gpio_is_valid(dev->msmrsb_gpio)) { + pr_err("Invalid gpio %d\n", + dev->msmrsb_gpio); + ret = -ENXIO; + goto err_ret; + } + /* Sleep 50ms for h/w to detect signal */ + msleep(50); + gpio_set_value(dev->msmrsb_gpio, 0); + } else { + ret = regulator_disable(dev->rgltr.regldo15); + if (ret) { + pr_err("Failed to disable LDO-15 %d\n", ret); + goto err_ret; + } + regulator_set_load(dev->rgltr.regldo15, 0); + } + break; + default: + ret = -EINVAL; + } + +err_ret: + return ret; +} + +static void bgrsb_bgdown_work(struct work_struct *work) +{ + int ret = 0; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + bg_down_work); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + ret = bgrsb_set_ldo(dev, BGRSB_DISABLE_WHEEL_EVENTS); + if (ret == 0) + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + else + pr_err("Failed to unvote LDO-15 on BG down\n"); + } + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_CONFIGURED) { + ret = bgrsb_set_ldo(dev, BGRSB_HW_TURN_OFF); + if (ret == 0) + dev->bgrsb_current_state = BGRSB_STATE_INIT; + else + pr_err("Failed to unvote LDO-11 on BG down\n"); + } + + dev->is_cnfgrd = false; + dev->blk_rsb_cmnds = false; + pr_debug("RSB current state is : %d\n", dev->bgrsb_current_state); + + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) { + if (dev->is_calibrd) + dev->calibration_needed = true; + } + mutex_unlock(&dev->rsb_state_mutex); +} + +static int bgrsb_tx_msg(struct bgrsb_priv *dev, void *msg, size_t len) +{ + int rc = 0; + + __pm_stay_awake(&dev->bgrsb_ws); + mutex_lock(&dev->glink_mutex); + if (!dev->rsb_rpmsg) { + pr_err("bgrsb-rpmsg is not probed yet, waiting for it to be probed\n"); + goto err_ret; + } + rc = bgrsb_rpmsg_tx_msg(msg, len); + if (rc != 0) + pr_err("bgrsb_rpmsg_tx_msg failed %d\n", rc); + +err_ret: + mutex_unlock(&dev->glink_mutex); + __pm_relax(&dev->bgrsb_ws); + return rc; +} + +static int bgrsb_enable(struct bgrsb_priv *dev, bool enable) +{ + struct bgrsb_msg req = {0}; + + req.cmd_id = 0x02; + req.data = enable ? 0x01 : 0x00; + + return bgrsb_tx_msg(dev, &req, BGRSB_MSG_SIZE); +} + +static int bgrsb_configr_rsb(struct bgrsb_priv *dev, bool enable) +{ + struct bgrsb_msg req = {0}; + + req.cmd_id = 0x01; + req.data = enable ? 0x01 : 0x00; + + return bgrsb_tx_msg(dev, &req, BGRSB_MSG_SIZE); +} + +void bgrsb_notify_glink_channel_state(bool state) +{ + struct bgrsb_priv *dev = + container_of(bgrsb_drv, struct bgrsb_priv, lhndl); + + pr_debug("%s: RSB-CTRL channel state: %d\n", __func__, state); + dev->rsb_rpmsg = state; +} +EXPORT_SYMBOL(bgrsb_notify_glink_channel_state); + +static void bgrsb_bgup_work(struct work_struct *work) +{ + int ret = 0; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, bg_up_work); + + mutex_lock(&dev->rsb_state_mutex); + ret = bgrsb_set_ldo(dev, BGRSB_HW_TURN_ON); + if (ret == 0) { + if (!dev->rsb_rpmsg) + pr_err("bgrsb-rpmsg is not probed yet\n"); + + ret = wait_event_timeout(dev->link_state_wait, + (dev->rsb_rpmsg == true), msecs_to_jiffies(TIMEOUT_MS)); + if (ret == 0) { + pr_err("channel connection time out %d\n", + ret); + goto unlock; + } + pr_debug("bgrsb-rpmsg is probed\n"); + ret = bgrsb_configr_rsb(dev, true); + if (ret != 0) { + pr_err("BG failed to configure RSB %d\n", ret); + if (bgrsb_set_ldo(dev, BGRSB_HW_TURN_OFF) == 0) + dev->bgrsb_current_state = BGRSB_STATE_INIT; + goto unlock; + } + dev->is_cnfgrd = true; + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("RSB Cofigured\n"); + if (dev->pending_enable) + queue_work(dev->bgrsb_wq, &dev->rsb_up_work); + } +unlock: + mutex_unlock(&dev->rsb_state_mutex); +} + +/** + * ssr_bg_cb(): callback function is called. + * @arg1: a notifier_block. + * @arg2: opcode that defines the event. + * @arg3: void pointer. + * + * by ssr framework when BG goes down, up and during + * ramdump collection. It handles BG shutdown and + * power up events. + * + * Return: NOTIFY_DONE. + */ +static int ssr_bgrsb_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bgrsb_priv *dev = container_of(bgrsb_drv, + struct bgrsb_priv, lhndl); + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) + dev->pending_enable = true; + queue_work(dev->bgrsb_wq, &dev->bg_down_work); + break; + case SUBSYS_AFTER_POWERUP: + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) + queue_work(dev->bgrsb_wq, &dev->bg_up_work); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block ssr_bg_nb = { + .notifier_call = ssr_bgrsb_cb, + .priority = 0, +}; + +/** + * bgrsb_ssr_register(): callback function is called. + * @arg1: pointer to bgrsb_priv structure. + * + * ssr_register checks that domain id should be in range + * and register SSR framework for value at domain id. + * + * Return: 0 for success and -ENODEV otherwise. + */ +static int bgrsb_ssr_register(struct bgrsb_priv *dev) +{ + struct notifier_block *nb; + + if (!dev) + return -ENODEV; + + nb = &ssr_bg_nb; + dev->bgwear_subsys_handle = + subsys_notif_register_notifier(BGRSB_BGWEAR_SUBSYS, nb); + + if (!dev->bgwear_subsys_handle) { + dev->bgwear_subsys_handle = NULL; + return -ENODEV; + } + return 0; +} + +static void bgrsb_enable_rsb(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, rsb_up_work); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + pr_debug("RSB is already enabled\n"); + goto unlock; + } + if (dev->bgrsb_current_state != BGRSB_STATE_RSB_CONFIGURED) { + pr_err("BG is not yet configured for RSB\n"); + dev->pending_enable = true; + goto unlock; + } + rc = bgrsb_set_ldo(dev, BGRSB_ENABLE_WHEEL_EVENTS); + if (rc == 0) { + rc = bgrsb_enable(dev, true); + if (rc != 0) { + pr_err("Failed to send enable command to BG %d\n", rc); + bgrsb_set_ldo(dev, BGRSB_DISABLE_WHEEL_EVENTS); + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + goto unlock; + } + } + dev->bgrsb_current_state = BGRSB_STATE_RSB_ENABLED; + dev->pending_enable = false; + pr_debug("RSB Enabled\n"); + + if (dev->calibration_needed) { + dev->calibration_needed = false; + queue_work(dev->bgrsb_wq, &dev->rsb_calibration_work); + } +unlock: + mutex_unlock(&dev->rsb_state_mutex); + +} + +static void bgrsb_disable_rsb(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv, + rsb_down_work); + + mutex_lock(&dev->rsb_state_mutex); + dev->pending_enable = false; + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + rc = bgrsb_enable(dev, false); + if (rc != 0) { + pr_err("Failed to send disable command to BG\n"); + goto unlock; + } + rc = bgrsb_set_ldo(dev, BGRSB_DISABLE_WHEEL_EVENTS); + if (rc != 0) + goto unlock; + + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("RSB Disabled\n"); + } + +unlock: + mutex_unlock(&dev->rsb_state_mutex); +} + +static void bgrsb_calibration(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_msg req = {0}; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, + rsb_calibration_work); + + mutex_lock(&dev->rsb_state_mutex); + if (!dev->is_cnfgrd) { + pr_err("RSB is not configured\n"); + goto unlock; + } + + req.cmd_id = 0x03; + req.data = dev->calbrtion_cpi; + + rc = bgrsb_tx_msg(dev, &req, 5); + if (rc != 0) { + pr_err("Failed to send resolution value to BG %d\n", rc); + goto unlock; + } + + req.cmd_id = 0x04; + req.data = dev->calbrtion_intrvl; + + rc = bgrsb_tx_msg(dev, &req, 5); + if (rc != 0) { + pr_err("Failed to send interval value to BG %d\n", rc); + goto unlock; + } + dev->is_calibrd = true; + pr_debug("RSB Calibrated\n"); + +unlock: + mutex_unlock(&dev->rsb_state_mutex); +} + +static void bgrsb_buttn_configration(struct work_struct *work) +{ + int rc = 0; + struct bgrsb_msg req = {0}; + struct bgrsb_priv *dev = + container_of(work, struct bgrsb_priv, + bttn_configr_work); + + mutex_lock(&dev->rsb_state_mutex); + if (!dev->is_cnfgrd) { + pr_err("RSB is not configured\n"); + goto unlock; + } + + req.cmd_id = 0x05; + req.data = dev->bttn_configs; + + rc = bgrsb_tx_msg(dev, &req, 5); + if (rc != 0) { + pr_err("configuration cmnd failed %d\n", + rc); + goto unlock; + } + + dev->bttn_configs = 0; + pr_debug("RSB Button configured\n"); + +unlock: + mutex_unlock(&dev->rsb_state_mutex); +} + +static int bgrsb_handle_cmd_in_ssr(struct bgrsb_priv *dev, char *str) +{ + long val; + int ret; + char *tmp; + + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + if (val == BGRSB_POWER_ENABLE) + dev->pending_enable = true; + else if (val == BGRSB_POWER_DISABLE) + dev->pending_enable = false; + + return 0; +} + +static int split_bg_work(struct bgrsb_priv *dev, char *str) +{ + long val; + int ret; + char *tmp; + + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + switch (val) { + case BGRSB_IN_TWM: + dev->is_in_twm = true; + case BGRSB_POWER_DISABLE: + queue_work(dev->bgrsb_wq, &dev->rsb_down_work); + break; + case BGRSB_OUT_TWM: + dev->is_in_twm = false; + case BGRSB_POWER_ENABLE: + queue_work(dev->bgrsb_wq, &dev->rsb_up_work); + break; + case BGRSB_POWER_CALIBRATION: + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + dev->calbrtion_intrvl = (uint32_t)val; + + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + dev->calbrtion_cpi = (uint32_t)val; + + queue_work(dev->bgrsb_wq, &dev->rsb_calibration_work); + break; + case BGRSB_BTTN_CONFIGURE: + tmp = strsep(&str, ":"); + if (!tmp) + return -EINVAL; + + ret = kstrtol(tmp, 10, &val); + if (ret < 0) + return ret; + + dev->bttn_configs = (uint8_t)val; + queue_work(dev->bgrsb_wq, &dev->bttn_configr_work); + break; + } + return 0; +} + +static int store_enable(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t count) +{ + int rc; + struct bgrsb_priv *dev = dev_get_drvdata(pdev); + char *arr; + + if (dev->blk_rsb_cmnds) { + pr_err("Device is in TWM state\n"); + return count; + } + arr = kstrdup(buff, GFP_KERNEL); + if (!arr) + return -ENOMEM; + + rc = split_bg_work(dev, arr); + if (!dev->is_cnfgrd) { + bgrsb_handle_cmd_in_ssr(dev, arr); + kfree(arr); + return -ENOMEDIUM; + } + + if (rc != 0) + pr_err("Not able to process request\n"); + + kfree(arr); + return count; +} + +static int show_enable(struct device *dev, struct device_attribute *attr, + char *buff) +{ + return 0; +} + +static struct device_attribute dev_attr_rsb = { + .attr = { + .name = "enable", + .mode = 00660, + }, + .show = show_enable, + .store = store_enable, +}; + +static int bgrsb_init(struct bgrsb_priv *dev) +{ + bgrsb_drv = &dev->lhndl; + mutex_init(&dev->glink_mutex); + mutex_init(&dev->rsb_state_mutex); + + dev->ldo_action = BGRSB_NO_ACTION; + + dev->bgrsb_wq = + create_singlethread_workqueue("bg-work-queue"); + if (!dev->bgrsb_wq) { + pr_err("Failed to init BG-RSB work-queue\n"); + return -ENOMEM; + } + + init_waitqueue_head(&dev->link_state_wait); + + /* set default bgrsb state */ + dev->bgrsb_current_state = BGRSB_STATE_INIT; + + /* Init all works */ + INIT_WORK(&dev->bg_up_work, bgrsb_bgup_work); + INIT_WORK(&dev->bg_down_work, bgrsb_bgdown_work); + INIT_WORK(&dev->rsb_up_work, bgrsb_enable_rsb); + INIT_WORK(&dev->rsb_down_work, bgrsb_disable_rsb); + INIT_WORK(&dev->rsb_calibration_work, bgrsb_calibration); + INIT_WORK(&dev->bttn_configr_work, bgrsb_buttn_configration); + + return 0; +} + +static int bg_rsb_probe(struct platform_device *pdev) +{ + struct bgrsb_priv *dev; + struct input_dev *input; + struct device_node *node; + int rc; + unsigned int rsb_gpio; + + node = pdev->dev.of_node; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + /* Add wake lock for PM suspend */ + wakeup_source_init(&dev->bgrsb_ws, "BGRSB_wake_lock"); + + dev->bgrsb_current_state = BGRSB_STATE_UNKNOWN; + rc = bgrsb_init(dev); + if (rc) + goto err_ret_dev; + /* Set up input device */ + input = devm_input_allocate_device(&pdev->dev); + if (!input) + goto err_ret_dev; + + input_set_capability(input, EV_REL, REL_WHEEL); + input_set_capability(input, EV_KEY, KEY_VOLUMEUP); + input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN); + input->name = "bg-spi"; + + rc = input_register_device(input); + if (rc) { + pr_err("Input device registration failed\n"); + goto err_ret_inp; + } + dev->input = input; + + /* register device for bg-wear ssr */ + rc = bgrsb_ssr_register(dev); + if (rc) { + pr_err("Failed to register for bg ssr\n"); + goto err_ret_inp; + } + rc = device_create_file(&pdev->dev, &dev_attr_rsb); + if (rc) { + pr_err("Not able to create the file bg-rsb/enable\n"); + goto err_ret_inp; + } + + dev->rsb_use_msm_gpio = + of_property_read_bool(node, "qcom,rsb-use-msm-gpio"); + + if (dev->rsb_use_msm_gpio == true) { + rsb_gpio = of_get_named_gpio(node, "qcom,bg-rsb-gpio", 0); + pr_debug("gpio %d is configured\n", rsb_gpio); + + if (!gpio_is_valid(rsb_gpio)) { + pr_err("gpio %d found is not valid\n", rsb_gpio); + goto err_ret; + } + + if (gpio_request(rsb_gpio, "msm_rsb_gpio")) { + pr_err("gpio %d request failed\n", rsb_gpio); + goto err_ret; + } + + if (gpio_direction_output(rsb_gpio, 1)) { + pr_err("gpio %d direction not set\n", rsb_gpio); + goto err_ret; + } + pr_debug("rsb gpio successfully requested\n"); + dev->msmrsb_gpio = rsb_gpio; + } + dev_set_drvdata(&pdev->dev, dev); + rc = bgrsb_init_regulators(&pdev->dev); + if (rc) { + pr_err("Failed to set regulators\n"); + goto err_ret_inp; + } + + pr_debug("RSB probe successfully\n"); + return 0; +err_ret: + return 0; +err_ret_inp: + input_free_device(input); +err_ret_dev: + devm_kfree(&pdev->dev, dev); + return -ENODEV; +} + +static int bg_rsb_remove(struct platform_device *pdev) +{ + struct bgrsb_priv *dev = platform_get_drvdata(pdev); + + destroy_workqueue(dev->bgrsb_wq); + input_free_device(dev->input); + wakeup_source_trash(&dev->bgrsb_ws); + return 0; +} + +static int bg_rsb_resume(struct device *pldev) +{ + struct platform_device *pdev = to_platform_device(pldev); + struct bgrsb_priv *dev = platform_get_drvdata(pdev); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_CONFIGURED) + goto ret_success; + + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) { + if (dev->is_cnfgrd && + bgrsb_set_ldo(dev, BGRSB_HW_TURN_ON) == 0) { + dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED; + pr_debug("RSB Cofigured\n"); + goto ret_success; + } + pr_err("RSB failed to resume\n"); + } + mutex_unlock(&dev->rsb_state_mutex); + return -EINVAL; + +ret_success: + mutex_unlock(&dev->rsb_state_mutex); + return 0; +} + +static int bg_rsb_suspend(struct device *pldev) +{ + struct platform_device *pdev = to_platform_device(pldev); + struct bgrsb_priv *dev = platform_get_drvdata(pdev); + + mutex_lock(&dev->rsb_state_mutex); + if (dev->bgrsb_current_state == BGRSB_STATE_INIT) + goto ret_success; + + if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) { + if (bgrsb_set_ldo(dev, BGRSB_DISABLE_WHEEL_EVENTS) != 0) + goto ret_err; + } + + if (bgrsb_set_ldo(dev, BGRSB_HW_TURN_OFF) == 0) { + dev->bgrsb_current_state = BGRSB_STATE_INIT; + pr_debug("RSB Init\n"); + goto ret_success; + } + +ret_err: + pr_err("RSB failed to suspend\n"); + mutex_unlock(&dev->rsb_state_mutex); + return -EINVAL; + +ret_success: + mutex_unlock(&dev->rsb_state_mutex); + return 0; +} + +static const struct of_device_id bg_rsb_of_match[] = { + { .compatible = "qcom,bg-rsb", }, + { } +}; + +static const struct dev_pm_ops pm_rsb = { + .resume = bg_rsb_resume, + .suspend = bg_rsb_suspend, +}; + +static struct platform_driver bg_rsb_driver = { + .driver = { + .name = "bg-rsb", + .of_match_table = bg_rsb_of_match, + .pm = &pm_rsb, + }, + .probe = bg_rsb_probe, + .remove = bg_rsb_remove, +}; module_platform_driver(bg_rsb_driver); +MODULE_DESCRIPTION("SoC BG RSB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index bcb51a249e54ee7d1a9d0a3d39724375948194a1..c207738e0d2330bb1c2f1ff1eaccae0a8801df8a 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -45,7 +45,6 @@ #define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 3000 #define ADSP_DOWN_EVENT_TO_BG_TIMEOUT 3000 -#define SLEEP_FOR_SPI_BUS 2000 enum { SSR_DOMAIN_BG, @@ -135,9 +134,9 @@ static void bgcom_load_twm_bg_work(struct work_struct *work) } else { dev->bg_twm_wear_load = true; dev->pil_h = subsystem_get_with_fwname("bg-wear", - "bg-twm-wear"); + "bg-twm"); if (!dev->pil_h) - pr_err("failed to load bg-twm-wear\n"); + pr_err("failed to load bg-twm\n"); } } @@ -401,8 +400,6 @@ static long bg_com_ioctl(struct file *filp, break; case SET_SPI_BUSY: ret = bgcom_set_spi_state(BGCOM_SPI_BUSY); - /* Add sleep for SPI Bus to release*/ - msleep(SLEEP_FOR_SPI_BUS); break; case BG_SOFT_RESET: ret = bg_soft_reset(); @@ -619,10 +616,8 @@ static int ssr_bg_cb(struct notifier_block *this, send_uevent(&bge); break; case SUBSYS_AFTER_SHUTDOWN: - /* Add sleep for SPI Bus to release*/ - msleep(SLEEP_FOR_SPI_BUS); if (dev->pending_bg_twm_wear_load) { - /* Load bg-twm-wear */ + /* Load bg-twm */ dev->pending_bg_twm_wear_load = false; queue_work(dev->bgdaemon_wq, &dev->bgdaemon_load_twm_bg_work); diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index e7993251a4d8a507b9e8cb37b05ced34efe3b7dc..f3ec8a421a184405911a73e0a200b8c68b987e16 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "bgcom.h" #include "bgrsb.h" #include "bgcom_interface.h" @@ -147,7 +148,7 @@ static void send_input_events(struct work_struct *work) list_for_each_safe(pos, temp, &pr_lst_hd) { node = list_entry(pos, struct event_list, list); evnt = node->evnt; -// bgrsb_send_input(evnt); + bgrsb_send_input(evnt); kfree(evnt); spin_lock(&lst_setup_lock); list_del(&node->list); @@ -160,6 +161,10 @@ int bgcom_set_spi_state(enum bgcom_spi_state state) { struct bg_spi_priv *bg_spi = container_of(bg_com_drv, struct bg_spi_priv, lhandle); + struct device spi_dev = bg_spi->spi->master->dev; + ktime_t time_start, delta; + s64 time_elapsed; + if (state < 0 || state > 1) return -EINVAL; @@ -167,6 +172,15 @@ int bgcom_set_spi_state(enum bgcom_spi_state state) return 0; mutex_lock(&bg_spi->xfer_mutex); + if (state == BGCOM_SPI_BUSY) { + time_start = ktime_get(); + while (!pm_runtime_status_suspended(spi_dev.parent)) { + delta = ktime_sub(ktime_get(), time_start); + time_elapsed = ktime_to_ms(delta); + BUG_ON(time_elapsed > 5 * MSEC_PER_SEC); + msleep(100); + } + } spi_state = state; mutex_unlock(&bg_spi->xfer_mutex); return 0; @@ -263,7 +277,9 @@ static int bgcom_transfer(void *handle, uint8_t *tx_buf, tx_xfer->rx_buf = rx_buf; tx_xfer->len = txn_len; + pm_runtime_get_sync(bg_spi->spi->controller->dev.parent); ret = spi_sync(spi, &bg_spi->msg1); + pm_runtime_put_sync_suspend(bg_spi->spi->controller->dev.parent); mutex_unlock(&bg_spi->xfer_mutex); if (ret) diff --git a/drivers/soc/qcom/bgrsb.h b/drivers/soc/qcom/bgrsb.h index 93a58b34bd28a673d223fb665bc1babde1142047..a6918732a76fbad6d0ac7f7d6475678c666c1a5b 100644 --- a/drivers/soc/qcom/bgrsb.h +++ b/drivers/soc/qcom/bgrsb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,24 +13,74 @@ #ifndef BGRSB_H #define BGRSB_H - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bgrsb_rpmsg.h" struct event { uint8_t sub_id; int16_t evnt_data; uint32_t evnt_tm; }; +#define BGRSB_GLINK_INTENT_SIZE 0x04 +#define BGRSB_MSG_SIZE 0x08 +#define TIMEOUT_MS 2000 +#define BGRSB_LDO15_VTG_MIN_UV 3000000 +#define BGRSB_LDO15_VTG_MAX_UV 3000000 +#define BGRSB_LDO11_VTG_MIN_UV 1800000 +#define BGRSB_LDO11_VTG_MAX_UV 1800000 + +#define BGRSB_BGWEAR_SUBSYS "bg-wear" + +#define BGRSB_POWER_DISABLE 0 +#define BGRSB_POWER_ENABLE 1 +#define BGRSB_POWER_CALIBRATION 2 +#define BGRSB_BTTN_CONFIGURE 5 +#define BGRSB_IN_TWM 8 +#define BGRSB_OUT_TWM 9 -struct bg_glink_chnl { - char *chnl_name; - char *chnl_edge; - char *chnl_trnsprt; + +struct bgrsb_regulator { + struct regulator *regldo11; + struct regulator *regldo15; }; -/** - * bgrsb_send_input() - send the recived input to input framework - * @evnt: pointer to the event structure - */ -int bgrsb_send_input(struct event *evnt); +enum ldo_task { + BGRSB_HW_TURN_ON, + BGRSB_ENABLE_WHEEL_EVENTS, + BGRSB_HW_TURN_OFF, + BGRSB_DISABLE_WHEEL_EVENTS, + BGRSB_NO_ACTION +}; + +enum bgrsb_state { + BGRSB_STATE_UNKNOWN, + BGRSB_STATE_INIT, + BGRSB_STATE_LDO11_ENABLED, + BGRSB_STATE_RSB_CONFIGURED, + BGRSB_STATE_RSB_ENABLED +}; + +struct bgrsb_msg { + uint32_t cmd_id; + uint32_t data; +}; +void bgrsb_send_input(struct event *evnt); +void bgrsb_notify_glink_channel_state(bool state); #endif /* BGCOM_H */ diff --git a/drivers/soc/qcom/bgrsb_rpmsg.c b/drivers/soc/qcom/bgrsb_rpmsg.c new file mode 100644 index 0000000000000000000000000000000000000000..1e57facdbe9b6db7470dd009eeb26e2a1ca078e0 --- /dev/null +++ b/drivers/soc/qcom/bgrsb_rpmsg.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include "bgrsb_rpmsg.h" + +static struct bgrsb_rpmsg_dev *pdev; + +int bgrsb_rpmsg_tx_msg(void *msg, size_t len) +{ + int ret; + + if (pdev == NULL || !pdev->chnl_state) + pr_err("pmsg_device is null, channel is closed\n"); + + pdev->message = msg; + pdev->message_length = len; + if (pdev->message) { + ret = rpmsg_send(pdev->channel, + pdev->message, pdev->message_length); + if (ret) + pr_err("rpmsg_send failed: %d\n", ret); + + } + return ret; +} +EXPORT_SYMBOL(bgrsb_rpmsg_tx_msg); + +static int bgrsb_rpmsg_probe(struct rpmsg_device *rpdev) +{ + int ret; + void *msg; + + pdev = devm_kzalloc(&rpdev->dev, sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->channel = rpdev->ept; + pdev->dev = &rpdev->dev; + if (pdev->channel == NULL) + return -ENOMEM; + + pdev->chnl_state = true; + dev_set_drvdata(&rpdev->dev, pdev); + + /* send a callback to bg-rsb driver*/ + bgrsb_notify_glink_channel_state(true); + if (pdev->message == NULL) + ret = bgrsb_rpmsg_tx_msg(msg, 0); + return 0; +} + +static void bgrsb_rpmsg_remove(struct rpmsg_device *rpdev) +{ + pdev->chnl_state = false; + pdev->message == NULL; + dev_dbg(&rpdev->dev, "rpmsg client driver is removed\n"); + bgrsb_notify_glink_channel_state(false); + dev_set_drvdata(&rpdev->dev, NULL); +} + +static int bgrsb_rpmsg_cb(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 src) +{ + struct bgrsb_rpmsg_dev *dev = + dev_get_drvdata(&rpdev->dev); + + if (!dev) + return -ENODEV; + + return 0; +} + +static const struct rpmsg_device_id rpmsg_driver_bgrsb_id_table[] = { + { "RSB_CTRL" }, + {}, +}; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_bgrsb_id_table); + +static const struct of_device_id rpmsg_driver_bgrsb_of_match[] = { + { .compatible = "qcom,bgrsb-rpmsg" }, + {}, +}; + +static struct rpmsg_driver rpmsg_bgrsb_client = { + .id_table = rpmsg_driver_bgrsb_id_table, + .probe = bgrsb_rpmsg_probe, + .callback = bgrsb_rpmsg_cb, + .remove = bgrsb_rpmsg_remove, + .drv = { + .name = "qcom,bg_rsb_rpmsg", + .of_match_table = rpmsg_driver_bgrsb_of_match, + }, +}; +module_rpmsg_driver(rpmsg_bgrsb_client); + +MODULE_DESCRIPTION("Interface Driver for BG-RSB and RPMSG"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts b/drivers/soc/qcom/bgrsb_rpmsg.h similarity index 56% rename from arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts rename to drivers/soc/qcom/bgrsb_rpmsg.h index ef7a24aeb2bf265cb1c8dea13f0b549d346e57ae..7ed8e35b8cec06a722c0e72f9463fb7f5932f029 100644 --- a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts +++ b/drivers/soc/qcom/bgrsb_rpmsg.h @@ -8,23 +8,29 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + * */ +#ifndef BGRSBRPMSG_H +#define BGRSBRPMSG_H -/dts-v1/; -/plugin/; - -#include - -#include "qcm6125-iot-idp.dtsi" -#include "qcm6125-iot-usbc-idp.dtsi" +#include +#include "bgrsb.h" -/ { - model = "USBC Audio IDP"; - compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; - qcom,msm-id = <467 0x10000>; - qcom,board-id = <34 2>; +struct bgrsb_rpmsg_dev { + struct rpmsg_endpoint *channel; + struct device *dev; + bool chnl_state; + void *message; + size_t message_length; }; -&dsi_td4330_truly_cmd_display { - qcom,dsi-display-active; -}; +#if IS_ENABLED(CONFIG_MSM_BGRSB_RPMSG) +int bgrsb_rpmsg_tx_msg(void *msg, size_t len); +#else +static inline int bgrsb_rpmsg_tx_msg(void *msg, size_t len) +{ + return -EIO; +} +#endif + +#endif diff --git a/drivers/soc/qcom/crypto-qti-common.c b/drivers/soc/qcom/crypto-qti-common.c new file mode 100644 index 0000000000000000000000000000000000000000..cd2eaef78a10a8203e0facb31c019ee966ce814b --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-common.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include "crypto-qti-ice-regs.h" +#include "crypto-qti-platform.h" + +static int ice_check_fuse_setting(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + uint32_t major, minor; + + major = (ice_entry->ice_hw_version & ICE_CORE_MAJOR_REV_MASK) >> + ICE_CORE_MAJOR_REV; + minor = (ice_entry->ice_hw_version & ICE_CORE_MINOR_REV_MASK) >> + ICE_CORE_MINOR_REV; + + /* Check fuse setting is not supported on ICE 3.2 onwards */ + if ((major == 0x03) && (minor >= 0x02)) + return 0; + regval = ice_readl(ice_entry, ICE_REGS_FUSE_SETTING); + regval &= (ICE_FUSE_SETTING_MASK | + ICE_FORCE_HW_KEY0_SETTING_MASK | + ICE_FORCE_HW_KEY1_SETTING_MASK); + + if (regval) { + pr_err("%s: error: ICE_ERROR_HW_DISABLE_FUSE_BLOWN\n", + __func__); + return -EPERM; + } + return 0; +} + +static int ice_check_version(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t version, major, minor, step; + + version = ice_readl(ice_entry, ICE_REGS_VERSION); + major = (version & ICE_CORE_MAJOR_REV_MASK) >> ICE_CORE_MAJOR_REV; + minor = (version & ICE_CORE_MINOR_REV_MASK) >> ICE_CORE_MINOR_REV; + step = (version & ICE_CORE_STEP_REV_MASK) >> ICE_CORE_STEP_REV; + + if (major < ICE_CORE_CURRENT_MAJOR_VERSION) { + pr_err("%s: Unknown ICE device at %lu, rev %d.%d.%d\n", + __func__, (unsigned long)ice_entry->icemmio_base, + major, minor, step); + return -ENODEV; + } + + ice_entry->ice_hw_version = version; + + return 0; +} + +int crypto_qti_init_crypto(struct device *dev, void __iomem *mmio_base, + void **priv_data) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = devm_kzalloc(dev, + sizeof(struct crypto_vops_qti_entry), + GFP_KERNEL); + if (!ice_entry) + return -ENOMEM; + + ice_entry->icemmio_base = mmio_base; + ice_entry->flags = 0; + + err = ice_check_version(ice_entry); + if (err) { + pr_err("%s: check version failed, err %d\n", __func__, err); + return err; + } + + err = ice_check_fuse_setting(ice_entry); + if (err) + return err; + + *priv_data = (void *)ice_entry; + + return err; +} + +static void ice_low_power_and_optimization_enable( + struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + + regval = ice_readl(ice_entry, ICE_REGS_ADVANCED_CONTROL); + /* Enable low power mode sequence + * [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0, + * Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING + */ + regval |= 0x7000; + /* Optimization enable sequence + */ + regval |= 0xD807100; + ice_writel(ice_entry, regval, ICE_REGS_ADVANCED_CONTROL); + /* + * Memory barrier - to ensure write completion before next transaction + */ + wmb(); +} + +static int ice_wait_bist_status(struct crypto_vops_qti_entry *ice_entry) +{ + int count; + uint32_t regval; + + for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) { + regval = ice_readl(ice_entry, ICE_REGS_BIST_STATUS); + if (!(regval & ICE_BIST_STATUS_MASK)) + break; + udelay(50); + } + + if (regval) { + pr_err("%s: wait bist status failed, reg %d\n", + __func__, regval); + return -ETIMEDOUT; + } + + return 0; +} + +static void ice_enable_intr(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + + regval = ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK); + regval &= ~ICE_REGS_NON_SEC_IRQ_MASK; + ice_writel(ice_entry, regval, ICE_REGS_NON_SEC_IRQ_MASK); + /* + * Memory barrier - to ensure write completion before next transaction + */ + wmb(); +} + +static void ice_disable_intr(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + + regval = ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK); + regval |= ICE_REGS_NON_SEC_IRQ_MASK; + ice_writel(ice_entry, regval, ICE_REGS_NON_SEC_IRQ_MASK); + /* + * Memory barrier - to ensure write completion before next transaction + */ + wmb(); +} + +int crypto_qti_enable(void *priv_data) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + ice_low_power_and_optimization_enable(ice_entry); + err = ice_wait_bist_status(ice_entry); + if (err) + return err; + ice_enable_intr(ice_entry); + + return err; +} + +void crypto_qti_disable(void *priv_data) +{ + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return; + } + + crypto_qti_disable_platform(ice_entry); + ice_disable_intr(ice_entry); +} + +int crypto_qti_resume(void *priv_data) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + err = ice_wait_bist_status(ice_entry); + + return err; +} + +static void ice_dump_test_bus(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval = 0x1; + uint32_t val; + uint8_t bus_selector; + uint8_t stream_selector; + + pr_err("ICE TEST BUS DUMP:\n"); + + for (bus_selector = 0; bus_selector <= 0xF; bus_selector++) { + regval = 0x1; /* enable test bus */ + regval |= bus_selector << 28; + if (bus_selector == 0xD) + continue; + ice_writel(ice_entry, regval, ICE_REGS_TEST_BUS_CONTROL); + /* + * make sure test bus selector is written before reading + * the test bus register + */ + wmb(); + val = ice_readl(ice_entry, ICE_REGS_TEST_BUS_REG); + pr_err("ICE_TEST_BUS_CONTROL: 0x%08x | ICE_TEST_BUS_REG: 0x%08x\n", + regval, val); + } + + pr_err("ICE TEST BUS DUMP (ICE_STREAM1_DATAPATH_TEST_BUS):\n"); + for (stream_selector = 0; stream_selector <= 0xF; stream_selector++) { + regval = 0xD0000001; /* enable stream test bus */ + regval |= stream_selector << 16; + ice_writel(ice_entry, regval, ICE_REGS_TEST_BUS_CONTROL); + /* + * make sure test bus selector is written before reading + * the test bus register + */ + wmb(); + val = ice_readl(ice_entry, ICE_REGS_TEST_BUS_REG); + pr_err("ICE_TEST_BUS_CONTROL: 0x%08x | ICE_TEST_BUS_REG: 0x%08x\n", + regval, val); + } +} + + +int crypto_qti_debug(void *priv_data) +{ + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + pr_err("%s: ICE Control: 0x%08x | ICE Reset: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_CONTROL), + ice_readl(ice_entry, ICE_REGS_RESET)); + + pr_err("%s: ICE Version: 0x%08x | ICE FUSE: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_VERSION), + ice_readl(ice_entry, ICE_REGS_FUSE_SETTING)); + + pr_err("%s: ICE Param1: 0x%08x | ICE Param2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_PARAMETERS_1), + ice_readl(ice_entry, ICE_REGS_PARAMETERS_2)); + + pr_err("%s: ICE Param3: 0x%08x | ICE Param4: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_PARAMETERS_3), + ice_readl(ice_entry, ICE_REGS_PARAMETERS_4)); + + pr_err("%s: ICE Param5: 0x%08x | ICE IRQ STTS: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_PARAMETERS_5), + ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_STTS)); + + pr_err("%s: ICE IRQ MASK: 0x%08x | ICE IRQ CLR: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK), + ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_CLR)); + + pr_err("%s: ICE INVALID CCFG ERR STTS: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_INVALID_CCFG_ERR_STTS)); + + pr_err("%s: ICE BIST Sts: 0x%08x | ICE Bypass Sts: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_BIST_STATUS), + ice_readl(ice_entry, ICE_REGS_BYPASS_STATUS)); + + pr_err("%s: ICE ADV CTRL: 0x%08x | ICE ENDIAN SWAP: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_ADVANCED_CONTROL), + ice_readl(ice_entry, ICE_REGS_ENDIAN_SWAP)); + + pr_err("%s: ICE_STM1_ERR_SYND1: 0x%08x | ICE_STM1_ERR_SYND2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_ERROR_SYNDROME1), + ice_readl(ice_entry, ICE_REGS_STREAM1_ERROR_SYNDROME2)); + + pr_err("%s: ICE_STM2_ERR_SYND1: 0x%08x | ICE_STM2_ERR_SYND2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_ERROR_SYNDROME1), + ice_readl(ice_entry, ICE_REGS_STREAM2_ERROR_SYNDROME2)); + + pr_err("%s: ICE_STM1_COUNTER1: 0x%08x | ICE_STM1_COUNTER2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS1), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS2)); + + pr_err("%s: ICE_STM1_COUNTER3: 0x%08x | ICE_STM1_COUNTER4: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS3), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS4)); + + pr_err("%s: ICE_STM2_COUNTER1: 0x%08x | ICE_STM2_COUNTER2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS1), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS2)); + + pr_err("%s: ICE_STM2_COUNTER3: 0x%08x | ICE_STM2_COUNTER4: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS3), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS4)); + + pr_err("%s: ICE_STM1_CTR5_MSB: 0x%08x | ICE_STM1_CTR5_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS5_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS5_LSB)); + + pr_err("%s: ICE_STM1_CTR6_MSB: 0x%08x | ICE_STM1_CTR6_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS6_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS6_LSB)); + + pr_err("%s: ICE_STM1_CTR7_MSB: 0x%08x | ICE_STM1_CTR7_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS7_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS7_LSB)); + + pr_err("%s: ICE_STM1_CTR8_MSB: 0x%08x | ICE_STM1_CTR8_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS8_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS8_LSB)); + + pr_err("%s: ICE_STM1_CTR9_MSB: 0x%08x | ICE_STM1_CTR9_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS9_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS9_LSB)); + + pr_err("%s: ICE_STM2_CTR5_MSB: 0x%08x | ICE_STM2_CTR5_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS5_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS5_LSB)); + + pr_err("%s: ICE_STM2_CTR6_MSB: 0x%08x | ICE_STM2_CTR6_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS6_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS6_LSB)); + + pr_err("%s: ICE_STM2_CTR7_MSB: 0x%08x | ICE_STM2_CTR7_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS7_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS7_LSB)); + + pr_err("%s: ICE_STM2_CTR8_MSB: 0x%08x | ICE_STM2_CTR8_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS8_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS8_LSB)); + + pr_err("%s: ICE_STM2_CTR9_MSB: 0x%08x | ICE_STM2_CTR9_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS9_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS9_LSB)); + + ice_dump_test_bus(ice_entry); + + return 0; +} + +int crypto_qti_keyslot_program(void *priv_data, + const struct blk_crypto_key *key, + unsigned int slot, + u8 data_unit_mask, int capid) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + err = crypto_qti_program_key(ice_entry, key, slot, + data_unit_mask, capid); + if (err) { + pr_err("%s: program key failed with error %d\n", __func__, err); + err = crypto_qti_invalidate_key(ice_entry, slot); + if (err) { + pr_err("%s: invalidate key failed with error %d\n", + __func__, err); + return err; + } + } + + return err; +} + +int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + err = crypto_qti_invalidate_key(ice_entry, slot); + if (err) { + pr_err("%s: invalidate key failed with error %d\n", + __func__, err); + return err; + } + + return err; +} + +int crypto_qti_derive_raw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size) +{ + int err = 0; + + if (wrapped_key_size <= RAW_SECRET_SIZE) { + pr_err("%s: Invalid wrapped_key_size: %u\n", + __func__, wrapped_key_size); + err = -EINVAL; + return err; + } + if (secret_size != RAW_SECRET_SIZE) { + pr_err("%s: Invalid secret size: %u\n", __func__, secret_size); + err = -EINVAL; + return err; + } + + memcpy(secret, wrapped_key, secret_size); + + return err; +} diff --git a/drivers/soc/qcom/crypto-qti-ice-regs.h b/drivers/soc/qcom/crypto-qti-ice-regs.h new file mode 100644 index 0000000000000000000000000000000000000000..d9e4cf2ad75fb6a7ba2c4ee86642940837b13f61 --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-ice-regs.h @@ -0,0 +1,163 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ +#define _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ + +#include + +/* Register bits for ICE version */ +#define ICE_CORE_CURRENT_MAJOR_VERSION 0x03 + +#define ICE_CORE_STEP_REV_MASK 0xFFFF +#define ICE_CORE_STEP_REV 0 /* bit 15-0 */ +#define ICE_CORE_MAJOR_REV_MASK 0xFF000000 +#define ICE_CORE_MAJOR_REV 24 /* bit 31-24 */ +#define ICE_CORE_MINOR_REV_MASK 0xFF0000 +#define ICE_CORE_MINOR_REV 16 /* bit 23-16 */ + +#define ICE_BIST_STATUS_MASK (0xF0000000) /* bits 28-31 */ + +#define ICE_FUSE_SETTING_MASK 0x1 +#define ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 +#define ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 + +/* QTI ICE Registers from SWI */ +#define ICE_REGS_CONTROL 0x0000 +#define ICE_REGS_RESET 0x0004 +#define ICE_REGS_VERSION 0x0008 +#define ICE_REGS_FUSE_SETTING 0x0010 +#define ICE_REGS_PARAMETERS_1 0x0014 +#define ICE_REGS_PARAMETERS_2 0x0018 +#define ICE_REGS_PARAMETERS_3 0x001C +#define ICE_REGS_PARAMETERS_4 0x0020 +#define ICE_REGS_PARAMETERS_5 0x0024 + + +/* QTI ICE v3.X only */ +#define ICE_GENERAL_ERR_STTS 0x0040 +#define ICE_INVALID_CCFG_ERR_STTS 0x0030 +#define ICE_GENERAL_ERR_MASK 0x0044 + + +/* QTI ICE v2.X only */ +#define ICE_REGS_NON_SEC_IRQ_STTS 0x0040 +#define ICE_REGS_NON_SEC_IRQ_MASK 0x0044 + + +#define ICE_REGS_NON_SEC_IRQ_CLR 0x0048 +#define ICE_REGS_STREAM1_ERROR_SYNDROME1 0x0050 +#define ICE_REGS_STREAM1_ERROR_SYNDROME2 0x0054 +#define ICE_REGS_STREAM2_ERROR_SYNDROME1 0x0058 +#define ICE_REGS_STREAM2_ERROR_SYNDROME2 0x005C +#define ICE_REGS_STREAM1_BIST_ERROR_VEC 0x0060 +#define ICE_REGS_STREAM2_BIST_ERROR_VEC 0x0064 +#define ICE_REGS_STREAM1_BIST_FINISH_VEC 0x0068 +#define ICE_REGS_STREAM2_BIST_FINISH_VEC 0x006C +#define ICE_REGS_BIST_STATUS 0x0070 +#define ICE_REGS_BYPASS_STATUS 0x0074 +#define ICE_REGS_ADVANCED_CONTROL 0x1000 +#define ICE_REGS_ENDIAN_SWAP 0x1004 +#define ICE_REGS_TEST_BUS_CONTROL 0x1010 +#define ICE_REGS_TEST_BUS_REG 0x1014 +#define ICE_REGS_STREAM1_COUNTERS1 0x1100 +#define ICE_REGS_STREAM1_COUNTERS2 0x1104 +#define ICE_REGS_STREAM1_COUNTERS3 0x1108 +#define ICE_REGS_STREAM1_COUNTERS4 0x110C +#define ICE_REGS_STREAM1_COUNTERS5_MSB 0x1110 +#define ICE_REGS_STREAM1_COUNTERS5_LSB 0x1114 +#define ICE_REGS_STREAM1_COUNTERS6_MSB 0x1118 +#define ICE_REGS_STREAM1_COUNTERS6_LSB 0x111C +#define ICE_REGS_STREAM1_COUNTERS7_MSB 0x1120 +#define ICE_REGS_STREAM1_COUNTERS7_LSB 0x1124 +#define ICE_REGS_STREAM1_COUNTERS8_MSB 0x1128 +#define ICE_REGS_STREAM1_COUNTERS8_LSB 0x112C +#define ICE_REGS_STREAM1_COUNTERS9_MSB 0x1130 +#define ICE_REGS_STREAM1_COUNTERS9_LSB 0x1134 +#define ICE_REGS_STREAM2_COUNTERS1 0x1200 +#define ICE_REGS_STREAM2_COUNTERS2 0x1204 +#define ICE_REGS_STREAM2_COUNTERS3 0x1208 +#define ICE_REGS_STREAM2_COUNTERS4 0x120C +#define ICE_REGS_STREAM2_COUNTERS5_MSB 0x1210 +#define ICE_REGS_STREAM2_COUNTERS5_LSB 0x1214 +#define ICE_REGS_STREAM2_COUNTERS6_MSB 0x1218 +#define ICE_REGS_STREAM2_COUNTERS6_LSB 0x121C +#define ICE_REGS_STREAM2_COUNTERS7_MSB 0x1220 +#define ICE_REGS_STREAM2_COUNTERS7_LSB 0x1224 +#define ICE_REGS_STREAM2_COUNTERS8_MSB 0x1228 +#define ICE_REGS_STREAM2_COUNTERS8_LSB 0x122C +#define ICE_REGS_STREAM2_COUNTERS9_MSB 0x1230 +#define ICE_REGS_STREAM2_COUNTERS9_LSB 0x1234 + +#define ICE_STREAM1_PREMATURE_LBA_CHANGE (1L << 0) +#define ICE_STREAM2_PREMATURE_LBA_CHANGE (1L << 1) +#define ICE_STREAM1_NOT_EXPECTED_LBO (1L << 2) +#define ICE_STREAM2_NOT_EXPECTED_LBO (1L << 3) +#define ICE_STREAM1_NOT_EXPECTED_DUN (1L << 4) +#define ICE_STREAM2_NOT_EXPECTED_DUN (1L << 5) +#define ICE_STREAM1_NOT_EXPECTED_DUS (1L << 6) +#define ICE_STREAM2_NOT_EXPECTED_DUS (1L << 7) +#define ICE_STREAM1_NOT_EXPECTED_DBO (1L << 8) +#define ICE_STREAM2_NOT_EXPECTED_DBO (1L << 9) +#define ICE_STREAM1_NOT_EXPECTED_ENC_SEL (1L << 10) +#define ICE_STREAM2_NOT_EXPECTED_ENC_SEL (1L << 11) +#define ICE_STREAM1_NOT_EXPECTED_CONF_IDX (1L << 12) +#define ICE_STREAM2_NOT_EXPECTED_CONF_IDX (1L << 13) +#define ICE_STREAM1_NOT_EXPECTED_NEW_TRNS (1L << 14) +#define ICE_STREAM2_NOT_EXPECTED_NEW_TRNS (1L << 15) + +#define ICE_NON_SEC_IRQ_MASK \ + (ICE_STREAM1_PREMATURE_LBA_CHANGE |\ + ICE_STREAM2_PREMATURE_LBA_CHANGE |\ + ICE_STREAM1_NOT_EXPECTED_LBO |\ + ICE_STREAM2_NOT_EXPECTED_LBO |\ + ICE_STREAM1_NOT_EXPECTED_DUN |\ + ICE_STREAM2_NOT_EXPECTED_DUN |\ + ICE_STREAM2_NOT_EXPECTED_DUS |\ + ICE_STREAM1_NOT_EXPECTED_DBO |\ + ICE_STREAM2_NOT_EXPECTED_DBO |\ + ICE_STREAM1_NOT_EXPECTED_ENC_SEL |\ + ICE_STREAM2_NOT_EXPECTED_ENC_SEL |\ + ICE_STREAM1_NOT_EXPECTED_CONF_IDX |\ + ICE_STREAM1_NOT_EXPECTED_NEW_TRNS |\ + ICE_STREAM2_NOT_EXPECTED_NEW_TRNS) + +/* QTI ICE registers from secure side */ +#define ICE_TEST_BUS_REG_SECURE_INTR (1L << 28) +#define ICE_TEST_BUS_REG_NON_SECURE_INTR (1L << 2) + +#define ICE_LUT_KEYS_CRYPTOCFG_R_16 0x4040 +#define ICE_LUT_KEYS_CRYPTOCFG_R_17 0x4044 +#define ICE_LUT_KEYS_CRYPTOCFG_OFFSET 0x80 + + +#define ICE_LUT_KEYS_ICE_SEC_IRQ_STTS 0x6200 +#define ICE_LUT_KEYS_ICE_SEC_IRQ_MASK 0x6204 +#define ICE_LUT_KEYS_ICE_SEC_IRQ_CLR 0x6208 + +#define ICE_STREAM1_PARTIALLY_SET_KEY_USED (1L << 0) +#define ICE_STREAM2_PARTIALLY_SET_KEY_USED (1L << 1) +#define ICE_QTIC_DBG_OPEN_EVENT (1L << 30) +#define ICE_KEYS_RAM_RESET_COMPLETED (1L << 31) + +#define ICE_SEC_IRQ_MASK \ + (ICE_STREAM1_PARTIALLY_SET_KEY_USED |\ + ICE_STREAM2_PARTIALLY_SET_KEY_USED |\ + ICE_QTIC_DBG_OPEN_EVENT | \ + ICE_KEYS_RAM_RESET_COMPLETED) + +#define ice_writel(ice_entry, val, reg) \ + writel_relaxed((val), (ice_entry)->icemmio_base + (reg)) +#define ice_readl(ice_entry, reg) \ + readl_relaxed((ice_entry)->icemmio_base + (reg)) + +#endif /* _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/drivers/soc/qcom/crypto-qti-platform.h b/drivers/soc/qcom/crypto-qti-platform.h new file mode 100644 index 0000000000000000000000000000000000000000..a37e34895ee7361b1c5aac94ca5f5e7bdc6b6c9e --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-platform.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CRYPTO_QTI_PLATFORM_H +#define _CRYPTO_QTI_PLATFORM_H + +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_QTI_CRYPTO_TZ) +int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, + const struct blk_crypto_key *key, unsigned int slot, + unsigned int data_unit_mask, int capid); +int crypto_qti_invalidate_key(struct crypto_vops_qti_entry *ice_entry, + unsigned int slot); +#else +static inline int crypto_qti_program_key( + struct crypto_vops_qti_entry *ice_entry, + const struct blk_crypto_key *key, + unsigned int slot, unsigned int data_unit_mask, + int capid) +{ + return 0; +} +static inline int crypto_qti_invalidate_key( + struct crypto_vops_qti_entry *ice_entry, unsigned int slot) +{ + return 0; +} +#endif /* CONFIG_QTI_CRYPTO_TZ */ + +static inline void crypto_qti_disable_platform( + struct crypto_vops_qti_entry *ice_entry) +{} + +#endif /* _CRYPTO_QTI_PLATFORM_H */ diff --git a/drivers/soc/qcom/crypto-qti-tz.c b/drivers/soc/qcom/crypto-qti-tz.c new file mode 100644 index 0000000000000000000000000000000000000000..0ebdd1a1c9f82c23d7c3673b9024961aa566f87c --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-tz.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include "crypto-qti-platform.h" +#include "crypto-qti-tz.h" + +unsigned int storage_type = SDCC_CE; + +#define ICE_BUFFER_SIZE 128 + +static uint8_t ice_buffer[ICE_BUFFER_SIZE]; + +int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, + const struct blk_crypto_key *key, + unsigned int slot, unsigned int data_unit_mask, + int capid) +{ + int err = 0; + uint32_t smc_id = 0; + char *tzbuf = NULL; + struct scm_desc desc = {0}; + int i; + union { + u8 bytes[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE]; + u32 words[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE / sizeof(u32)]; + } key_new; + + tzbuf = ice_buffer; + + memcpy(key_new.bytes, key->raw, key->size); + if (!key->is_hw_wrapped) { + for (i = 0; i < ARRAY_SIZE(key_new.words); i++) + __cpu_to_be32s(&key_new.words[i]); + } + + memcpy(tzbuf, key_new.bytes, key->size); + dmac_flush_range(tzbuf, tzbuf + key->size); + + smc_id = TZ_ES_CONFIG_SET_ICE_KEY_ID; + desc.arginfo = TZ_ES_CONFIG_SET_ICE_KEY_PARAM_ID; + desc.args[0] = slot; + desc.args[1] = virt_to_phys(tzbuf); + desc.args[2] = ICE_BUFFER_SIZE; + desc.args[3] = ICE_CIPHER_MODE_XTS_256; + desc.args[4] = data_unit_mask; + + + err = scm_call2_noretry(smc_id, &desc); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + + return err; +} + +int crypto_qti_invalidate_key( + struct crypto_vops_qti_entry *ice_entry, unsigned int slot) +{ + int err = 0; + uint32_t smc_id = 0; + struct scm_desc desc = {0}; + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = slot; + + err = scm_call2_noretry(smc_id, &desc); + if (err) + pr_err("%s:SCM call Error: 0x%x\n", __func__, err); + return err; +} + +static int crypto_qti_storage_type(unsigned int *s_type) +{ + char boot[20] = {'\0'}; + char *match = (char *)strnstr(saved_command_line, + "androidboot.bootdevice=", + strlen(saved_command_line)); + if (match) { + memcpy(boot, (match + strlen("androidboot.bootdevice=")), + sizeof(boot) - 1); + if (strnstr(boot, "ufs", strlen(boot))) + *s_type = UFS_CE; + + return 0; + } + return -EINVAL; +} + +static int __init crypto_qti_init(void) +{ + return crypto_qti_storage_type(&storage_type); +} + +module_init(crypto_qti_init); diff --git a/drivers/soc/qcom/crypto-qti-tz.h b/drivers/soc/qcom/crypto-qti-tz.h new file mode 100644 index 0000000000000000000000000000000000000000..bcb946096072e451cef60b21274a733fab2fb5cc --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-tz.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#ifndef _CRYPTO_QTI_TZ_H +#define _CRYPTO_QTI_TZ_H + +#define TZ_ES_INVALIDATE_ICE_KEY 0x3 +#define TZ_ES_CONFIG_SET_ICE_KEY 0x4 +#define TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE 0x5 +#define TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE 0x6 + +#define TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, \ + TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE) + +#define TZ_ES_CONFIG_SET_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, \ + TZ_ES_CONFIG_SET_ICE_KEY) + +#define TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ + TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE) + +#define TZ_ES_INVALIDATE_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ + TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY) + +#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_1( \ + TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_CONFIG_SET_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_5( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_2( \ + TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_6( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_VAL) + +enum { + ICE_CIPHER_MODE_XTS_128 = 0, + ICE_CIPHER_MODE_CBC_128 = 1, + ICE_CIPHER_MODE_XTS_256 = 3, + ICE_CIPHER_MODE_CBC_256 = 4 +}; + +#define UFS_CE 10 +#define SDCC_CE 20 +#define UFS_CARD_CE 30 + +#endif /* _CRYPTO_QTI_TZ_H */ diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index ef4470ea9445762425b672254da9bba311ee6d7a..8ca4db08fd5b0dd0618d39ed96e633be5e04eac2 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -989,7 +989,8 @@ static u32 dfc_adjust_grant(struct rmnet_bearer_map *bearer, static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, u8 ack_req, u32 ancillary, struct dfc_flow_status_info_type_v01 *fc_info, - bool is_query) + bool is_query, + int index) { struct rmnet_bearer_map *itm = NULL; int rc = 0; @@ -1010,9 +1011,16 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, if (itm->rat_switch) return 0; - /* If TX is OFF but we received grant, ignore it */ - if (itm->tx_off && fc_info->num_bytes > 0) - return 0; + /* If TX is OFF but we received grant from the same modem, + * ignore it. If the grant is from a different modem, + * assume TX had become ON. + */ + if (itm->tx_off && fc_info->num_bytes > 0) { + if (itm->tx_status_index == index) + return 0; + itm->tx_off = false; + itm->tx_status_index = index; + } /* Adjuste grant for query */ if (dfc_qmap && is_query) { @@ -1120,7 +1128,7 @@ void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, else dfc_update_fc_map( dev, qos, ack_req, ancillary, flow_status, - is_query); + is_query, dfc->index); spin_unlock_bh(&qos->qos_lock); } @@ -1131,7 +1139,8 @@ void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, static void dfc_update_tx_link_status(struct net_device *dev, struct qos_info *qos, u8 tx_status, - struct dfc_bearer_info_type_v01 *binfo) + struct dfc_bearer_info_type_v01 *binfo, + int index) { struct rmnet_bearer_map *itm = NULL; @@ -1139,6 +1148,8 @@ static void dfc_update_tx_link_status(struct net_device *dev, if (!itm) return; + itm->tx_status_index = index; + /* If no change in tx status, ignore */ if (itm->tx_off == !tx_status) return; @@ -1190,7 +1201,7 @@ void dfc_handle_tx_link_status_ind(struct dfc_qmi_data *dfc, spin_lock_bh(&qos->qos_lock); dfc_update_tx_link_status( - dev, qos, ind->tx_status, bearer_info); + dev, qos, ind->tx_status, bearer_info, dfc->index); spin_unlock_bh(&qos->qos_lock); } diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c index 0ba48c247c8daf119e71c4617ae7044c06e30304..354032e6472f408d987c092cfff9121077ff58f6 100644 --- a/drivers/soc/qcom/hab/hab_mimex.c +++ b/drivers/soc/qcom/hab/hab_mimex.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -249,7 +249,8 @@ int hab_mem_export(struct uhab_context *ctx, int page_count; int compressed = 0; - if (!ctx || !param || !param->buffer) + if (!ctx || !param || !param->buffer || !param->sizebytes + || ((param->sizebytes % PAGE_SIZE) != 0)) return -EINVAL; vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c index a90460a1295ee83bb4049ff232334657b6ffdf7e..8caccdd22c7db63644f0498363e62ab39f848dc8 100644 --- a/drivers/soc/qcom/hab/hab_open.c +++ b/drivers/soc/qcom/hab/hab_open.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -240,6 +240,8 @@ int hab_open_receive_cancel(struct physical_channel *pchan, request->xdata.vchan_id = data.vchan_id; request->xdata.sub_id = data.sub_id; request->xdata.open_id = data.open_id; + request->xdata.ver_fe = data.ver_fe; + request->xdata.ver_be = data.ver_be; do_gettimeofday(&tv); node->age = tv.tv_sec + HAB_OPEN_REQ_EXPIRE_TIME_S + diff --git a/drivers/soc/qcom/hgsl/hgsl.c b/drivers/soc/qcom/hgsl/hgsl.c index 80f9b7436ca5365d33efcd848e4ca809199f5082..f459774e3911955b01589d4ffae1b9c2dce05507 100644 --- a/drivers/soc/qcom/hgsl/hgsl.c +++ b/drivers/soc/qcom/hgsl/hgsl.c @@ -31,7 +31,9 @@ #define HGSL_DEVICE_NAME "hgsl" #define HGSL_DEV_NUM 1 -#define MAX_DB_QUEUE 4 + +/* Support upto 3 GVMs: 3 DBQs(Low/Medium/High priority) per GVM */ +#define MAX_DB_QUEUE 9 #define IORESOURCE_HWINF "hgsl_reg_hwinf" #define IORESOURCE_GMUCX "hgsl_reg_gmucx" diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index ab6792932e2e090a17c05de3038d9fea7214a2bb..fc7d91dcf5373e0d9c961c4a8fff123b9591fbf9 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -945,7 +945,9 @@ static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt) if (ret) return ret; - place_marker("M - Modem Image Start Loading"); + if (!strcmp(desc->name, "modem")) + place_marker("M - Modem Image Start Loading"); + pil_info(desc, "loading from %pa to %pa\n", &priv->region_start, &priv->region_end); @@ -1405,7 +1407,10 @@ int pil_boot(struct pil_desc *desc) goto err_auth_and_reset; } pil_log("reset_done", desc); - place_marker("M - Modem out of reset"); + + if (!strcmp(desc->name, "modem")) + place_marker("M - Modem out of reset"); + pil_info(desc, "Brought out of reset\n"); desc->modem_ssr = false; err_auth_and_reset: diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index d28c5c99aaeef2cd83dbcc3620467e30f310c961..c87eed4f361d5d1f092a03676e6b682fcf33b5fb 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -51,6 +51,7 @@ struct rmnet_bearer_map { bool tcp_bidir; bool rat_switch; bool tx_off; + int tx_status_index; u32 ack_txid; u32 mq_idx; u32 ack_mq_idx; diff --git a/drivers/soc/qcom/rename_block_device.c b/drivers/soc/qcom/rename_block_device.c new file mode 100644 index 0000000000000000000000000000000000000000..c2dd284b0ac3cd196ec57722fd7f32c0498a11bc --- /dev/null +++ b/drivers/soc/qcom/rename_block_device.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#define PATH_SIZE 32 + +static int rename_blk_dev_init(void) +{ + dev_t dev; + int index = 0, partno; + struct gendisk *disk; + struct device_node *node; + char dev_path[PATH_SIZE]; + const char *actual_name, *modified_name; + + node = of_find_compatible_node(NULL, NULL, "qcom,blkdev-rename"); + if (!node) { + pr_err("qcom,blkdev-rename is missing\n"); + goto out; + } + while (!of_property_read_string_index(node, "actual-dev", index, + &actual_name)) { + memset(dev_path, '\0', PATH_SIZE); + snprintf(dev_path, PATH_SIZE, "/dev/%s", actual_name); + dev = name_to_dev_t(dev_path); + if (!dev) { + pr_err("No device path : %s\n", dev_path); + return -EINVAL; + } + disk = get_gendisk(dev, &partno); + if (!disk) { + pr_err("No device with dev path : %s\n", dev_path); + return -ENXIO; + } + if (!of_property_read_string_index(node, "rename-dev", index, + &modified_name)) { + device_rename(disk_to_dev(disk), modified_name); + } else { + pr_err("rename-dev for actual-dev = %s is missing", + actual_name); + return -ENXIO; + } + index++; + } +out: + return 0; +} + +late_initcall(rename_blk_dev_init); +MODULE_DESCRIPTION("Rename block devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/sdx_ext_ipc.c b/drivers/soc/qcom/sdx_ext_ipc.c index 9e4ee937b03f177c4853e275ea1146fdebb590a1..a4d0c35f935328e2beb01306501a9bd5789c0280 100644 --- a/drivers/soc/qcom/sdx_ext_ipc.c +++ b/drivers/soc/qcom/sdx_ext_ipc.c @@ -47,7 +47,7 @@ static const char * const gpio_map[] = { }; struct gpio_cntrl { - unsigned int gpios[NUM_GPIOS]; + int gpios[NUM_GPIOS]; int status_irq; int wakeup_irq; int policy; @@ -264,7 +264,7 @@ static int setup_ipc(struct gpio_cntrl *mdm) irq = gpio_to_irq(mdm->gpios[WAKEUP_IN]); if (irq < 0) { - dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); + dev_err(mdm->dev, "bad WAKEUP_IN IRQ resource\n"); return irq; } mdm->wakeup_irq = irq; @@ -347,16 +347,15 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) if (mdm->gpios[WAKEUP_IN] >= 0) { ret = devm_request_threaded_irq(mdm->dev, mdm->wakeup_irq, - NULL, sdx_ext_ipc_wakeup_irq, + sdx_ext_ipc_wakeup_irq, NULL, IRQF_TRIGGER_FALLING, "sdx_ext_ipc_wakeup", mdm); if (ret < 0) { dev_err(mdm->dev, "%s: WAKEUP_IN IRQ#%d request failed,\n", - __func__, mdm->status_irq); + __func__, mdm->wakeup_irq); goto irq_fail; } - disable_irq(mdm->wakeup_irq); } if (mdm->gpios[WAKEUP_OUT] >= 0) { diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 0cdd98ca48f33302e71ae3b8563c12960b4fc567..72117972b7e54eb2f1f9a2f14016d384abdfb9d3 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -92,7 +92,7 @@ #define SMEM_GLOBAL_HOST 0xfffe /* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 11 +#define SMEM_HOST_COUNT 13 /** * struct smem_proc_comm - proc_comm communication struct (legacy) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 03a4c2214fe6f76782f88cc9a40167de202a9538..9e749e55993776450cb7d63ac29fbb24caa4a3c4 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -451,9 +451,11 @@ static struct msm_soc_info cpu_of_id[] = { [416] = {MSM_CPU_SDM429W, "SDM429W"}, [437] = {MSM_CPU_SDA429W, "SDA429W"}, - /* QCM6125 IDs*/ - [467] = {MSM_CPU_QCM6125, "QCM6125"}, - [468] = {MSM_CPU_QCS6125, "QCS6125"}, + /* TRINKET-IOT IDs*/ + [467] = {MSM_CPU_TRINKET_IOT, "TRINKET-IOT"}, + + /* TRINKETP-IOT IDs*/ + [468] = {MSM_CPU_TRINKETP_IOT, "TRINKETP-IOT"}, /* Uninitialized IDs are not known to run Linux. * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are @@ -1467,13 +1469,13 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 437; strlcpy(dummy_socinfo.build_id, "sda429w - ", sizeof(dummy_socinfo.build_id)); - } else if (early_machine_is_qcm6125()) { + } else if (early_machine_is_trinket_iot()) { dummy_socinfo.id = 467; - strlcpy(dummy_socinfo.build_id, "qcm6125 - ", + strlcpy(dummy_socinfo.build_id, "trinket-iot - ", sizeof(dummy_socinfo.build_id)); - } else if (early_machine_is_qcs6125()) { + } else if (early_machine_is_trinketp_iot()) { dummy_socinfo.id = 468; - strlcpy(dummy_socinfo.build_id, "qcm6125 - ", + strlcpy(dummy_socinfo.build_id, "trinketp-iot - ", sizeof(dummy_socinfo.build_id)); } else strlcat(dummy_socinfo.build_id, "Dummy socinfo", diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index 6cc4f35ff614e80887c93f7f561efdd89b987e29..e4eaa8b8e77e2af3ea22b022db4bee743bdde016 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -197,7 +197,7 @@ static int panic_wdog_handler(struct notifier_block *this, { struct msm_watchdog_data *wdog_dd = container_of(this, struct msm_watchdog_data, panic_blk); - if (panic_timeout == 0) { + if (panic_timeout == 0 || crash_kexec_post_notifiers) { __raw_writel(0, wdog_dd->base + WDT0_EN); /* Make sure watchdog is enabled before notifying the caller */ mb(); diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index 2ec29350f6f87bebd315f00e497099ae393bff44..b939c02b36ecd87d5f1e2c344c301605ff62ae46 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -1573,6 +1573,7 @@ static int wcnss_ctrl_probe(struct rpmsg_device *rpdev) static void wcnss_ctrl_remove(struct rpmsg_device *rpdev) { + penv->smd_channel_ready = 0; of_platform_depopulate(&rpdev->dev); } @@ -2378,6 +2379,8 @@ static void wcnss_process_smd_msg(void *buf, int len) if (nvresp->status != WAIT_FOR_CBC_IND) penv->is_cbc_done = 1; + penv->smd_channel_ready = 1; + if (penv->ops) penv->ops->driver_state(penv->ops->priv_data, WCNSS_SMD_OPEN); diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 5b18f6ffa45c798a9c8d138a4f0fb647551b4932..cd61c883c19f52a8b2e9d4d68a634d3f5fb14510 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -134,7 +134,7 @@ void __init tegra_init_apbmisc(void) apbmisc.flags = IORESOURCE_MEM; /* strapping options */ - if (tegra_get_chip_id() == TEGRA124) { + if (of_machine_is_compatible("nvidia,tegra124")) { straps.start = 0x7000e864; straps.end = 0x7000e867; } else { diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 897a74354419719772c15ae9da74f452e0a39092..c19f65386614522b17ed434d070c119da0ad5509 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -342,9 +342,15 @@ static int setup_fifo_params(struct spi_device *spi_slv, if (mode & SPI_CPOL) cpol |= CPOL; - if (!spi->slave) { - if (mode & SPI_CPHA) - cpha |= CPHA; + if (mode & SPI_CPHA) + cpha |= CPHA; + + /* SPI slave supports only mode 1, log unsuppoted mode and exit */ + if (spi->slave && !(cpol == 0 && cpha == 1)) { + GENI_SE_DBG(mas->ipc, false, mas->dev, + "%s: Unsupported SPI Slave mode cpol %d cpha %d\n", + __func__, cpol, cpha); + return -EINVAL; } if (spi_slv->mode & SPI_CS_HIGH) @@ -1064,10 +1070,11 @@ static int spi_geni_unprepare_transfer_hardware(struct spi_master *spi) return 0; } -static void setup_fifo_xfer(struct spi_transfer *xfer, +static int setup_fifo_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas, u16 mode, struct spi_master *spi) { + int ret = 0; u32 m_cmd = 0; u32 m_param = 0; u32 spi_tx_cfg = geni_read_reg(mas->base, SE_SPI_TRANS_CFG); @@ -1080,7 +1087,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, /* Speed and bits per word can be overridden per transfer */ if (xfer->speed_hz != mas->cur_speed_hz) { - int ret = 0; u32 clk_sel = 0; u32 m_clk_cfg = 0; int idx = 0; @@ -1090,7 +1096,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, if (ret) { dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret); - return; + return ret; } mas->cur_speed_hz = xfer->speed_hz; clk_sel |= (idx & CLK_SEL_MSK); @@ -1171,13 +1177,14 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd, xfer->cs_change, mas->cur_xfer_mode); if ((m_cmd & SPI_RX_ONLY) && (mas->cur_xfer_mode == SE_DMA)) { - int ret = 0; - ret = geni_se_rx_dma_prep(mas->wrapper_dev, mas->base, xfer->rx_buf, xfer->len, &xfer->rx_dma); - if (ret) + if (ret) { GENI_SE_ERR(mas->ipc, true, mas->dev, "Failed to setup Rx dma %d\n", ret); + xfer->rx_dma = 0; + return ret; + } } if (m_cmd & SPI_TX_ONLY) { if (mas->cur_xfer_mode == FIFO_MODE) { @@ -1189,14 +1196,18 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, ret = geni_se_tx_dma_prep(mas->wrapper_dev, mas->base, (void *)xfer->tx_buf, xfer->len, &xfer->tx_dma); - if (ret) + if (ret) { GENI_SE_ERR(mas->ipc, true, mas->dev, "Failed to setup tx dma %d\n", ret); + xfer->tx_dma = 0; + return ret; + } } } /* Ensure all writes are done before the WM interrupt */ mb(); + return ret; } static void handle_fifo_timeout(struct spi_master *spi, @@ -1231,7 +1242,7 @@ static void handle_fifo_timeout(struct spi_master *spi, } dma_unprep: if (mas->cur_xfer_mode == SE_DMA) { - if (xfer->tx_buf) { + if (xfer->tx_buf && xfer->tx_dma) { reinit_completion(&mas->xfer_done); writel_relaxed(1, mas->base + SE_DMA_TX_FSM_RST); @@ -1243,7 +1254,7 @@ static void handle_fifo_timeout(struct spi_master *spi, geni_se_tx_dma_unprep(mas->wrapper_dev, xfer->tx_dma, xfer->len); } - if (xfer->rx_buf) { + if (xfer->rx_buf && xfer->rx_dma) { reinit_completion(&mas->xfer_done); writel_relaxed(1, mas->base + SE_DMA_RX_FSM_RST); @@ -1274,21 +1285,28 @@ static int spi_geni_transfer_one(struct spi_master *spi, return -EINVAL; } - mutex_lock(&mas->spi_ssr.ssr_lock); - if (mas->spi_ssr.is_ssr_down || !mas->spi_ssr.xfer_prepared) { - mutex_unlock(&mas->spi_ssr.ssr_lock); - return -EINVAL; - } - /* Check for zero length transfer */ if (xfer->len < 1) { dev_err(mas->dev, "Zero length transfer\n"); return -EINVAL; } + mutex_lock(&mas->spi_ssr.ssr_lock); + if (mas->spi_ssr.is_ssr_down || !mas->spi_ssr.xfer_prepared) { + mutex_unlock(&mas->spi_ssr.ssr_lock); + return -EINVAL; + } + if (mas->cur_xfer_mode != GSI_DMA) { reinit_completion(&mas->xfer_done); - setup_fifo_xfer(xfer, mas, slv->mode, spi); + ret = setup_fifo_xfer(xfer, mas, slv->mode, spi); + if (ret) { + GENI_SE_ERR(mas->ipc, true, mas->dev, + "setup_fifo_xfer failed: %d\n", ret); + mas->cur_xfer = NULL; + goto err_fifo_geni_transfer_one; + } + if (spi->slave) spi->slave_state = true; mutex_unlock(&mas->spi_ssr.ssr_lock); @@ -1327,7 +1345,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, reinit_completion(&mas->tx_cb); reinit_completion(&mas->rx_cb); - setup_gsi_xfer(xfer, mas, slv, spi); + ret = setup_gsi_xfer(xfer, mas, slv, spi); + if (ret) { + GENI_SE_ERR(mas->ipc, true, mas->dev, + "setup_gsi_xfer failed: %d\n", ret); + mas->cur_xfer = NULL; + goto err_gsi_geni_transfer_one; + } if ((mas->num_xfers >= NUM_SPI_XFER) || (list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))) { diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index b2245cdce230b32c3be06922255bda2f2f0c1b63..5160e16d3a9852ffa7dd462ed66fb8c537bdcd63 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -76,6 +76,10 @@ MODULE_ALIAS("platform:pxa2xx-spi"); #define LPSS_CAPS_CS_EN_SHIFT 9 #define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT) +#define LPSS_PRIV_CLOCK_GATE 0x38 +#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3 +#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3 + struct lpss_config { /* LPSS offset from drv_data->ioaddr */ unsigned offset; @@ -92,6 +96,8 @@ struct lpss_config { unsigned cs_sel_shift; unsigned cs_sel_mask; unsigned cs_num; + /* Quirks */ + unsigned cs_clk_stays_gated : 1; }; /* Keep these sorted with enum pxa_ssp_type */ @@ -162,6 +168,7 @@ static const struct lpss_config lpss_platforms[] = { .tx_threshold_hi = 56, .cs_sel_shift = 8, .cs_sel_mask = 3 << 8, + .cs_clk_stays_gated = true, }, }; @@ -385,6 +392,22 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) else value |= LPSS_CS_CONTROL_CS_HIGH; __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); + if (config->cs_clk_stays_gated) { + u32 clkgate; + + /* + * Changing CS alone when dynamic clock gating is on won't + * actually flip CS at that time. This ruins SPI transfers + * that specify delays, or have no data. Toggle the clock mode + * to force on briefly to poke the CS pin to move. + */ + clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE); + value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) | + LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON; + + __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value); + __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate); + } } static void cs_assert(struct driver_data *drv_data) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 974a8ce58b68bc31e38d717ff16564aec398232e..cb74fd1af2053015796fcd0c7e6055701e063e78 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1190,6 +1190,11 @@ static int spi_qup_suspend(struct device *device) struct spi_qup *controller = spi_master_get_devdata(master); int ret; + if (pm_runtime_suspended(device)) { + ret = spi_qup_pm_resume_runtime(device); + if (ret) + return ret; + } ret = spi_master_suspend(master); if (ret) return ret; @@ -1198,10 +1203,8 @@ static int spi_qup_suspend(struct device *device) if (ret) return ret; - if (!pm_runtime_suspended(device)) { - clk_disable_unprepare(controller->cclk); - clk_disable_unprepare(controller->iclk); - } + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); return 0; } diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 18aeaceee2862017f4cd4bb13a5e3c6bd36f6ea7..d26c0eda2d9ea5fd3bb72d280b488a5cced4f557 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -415,9 +415,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry); - /* Dummy generic FIFO entry */ - zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0); - /* Manually start the generic FIFO command */ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index bc0679ec4d20aa81b7b2dc08b0f907504ee8a3b5..6f4b2fd05e12b89b15c26145d97618f6d0ccca6e 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1133,7 +1133,8 @@ struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, heap->type == ION_HEAP_TYPE_CARVEOUT || heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA || heap->type == - (enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE) { + (enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE || + heap->type == (enum ion_heap_type)ION_HEAP_TYPE_DMA) { type_valid = true; } else { pr_warn("%s: heap type not supported, type:%d\n", diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 723d49bbc5bb12a48251fccb24d7b984a2e42573..af1ea09141aba6660b409c7ba57000c67603c27e 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -409,11 +409,13 @@ static int ion_system_heap_allocate(struct ion_heap *heap, buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE; if (vmid > 0) - ion_hyp_unassign_sg(table, &vmid, 1, true, false); + if (ion_hyp_unassign_sg(table, &vmid, 1, true, false)) + goto err_free_table_sync; for_each_sg(table->sgl, sg, table->nents, i) free_buffer_page(sys_heap, buffer, sg_page(sg), get_order(sg->length)); +err_free_table_sync: if (nents_sync) sg_free_table(&table_sync); err_free_sg: diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index e19e395b0e440622dda2f5acfee98573922d25f1..9f1ec427c168c94bf2a18f1a13fdba86988db4b2 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2603,8 +2603,10 @@ static int comedi_open(struct inode *inode, struct file *file) } cfp = kzalloc(sizeof(*cfp), GFP_KERNEL); - if (!cfp) + if (!cfp) { + comedi_dev_put(dev); return -ENOMEM; + } cfp->dev = dev; diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index ce557197119454f41bf2005f4731edda3d59cdb4..9b773c2e140b29e56c1db89cf959566e695e4b8a 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -101,6 +101,7 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, int ret; for (i = 0; i < insn->n; i++) { + /* FIXME: lo bit 0 chooses voltage output or current output */ lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; hi = (data[i] & 0xff0) >> 4; @@ -114,6 +115,8 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, if (ret) return ret; + outb(hi, dev->iobase + DT2815_DATA); + devpriv->ao_readback[chan] = data[i]; } return i; diff --git a/drivers/staging/greybus/audio_manager.c b/drivers/staging/greybus/audio_manager.c index aa6508b44fab27f805bcd629c8815a9d0b8bf413..ed7c32542cb3cbd0e38c022e336cfee3b03bac4b 100644 --- a/drivers/staging/greybus/audio_manager.c +++ b/drivers/staging/greybus/audio_manager.c @@ -90,8 +90,8 @@ void gb_audio_manager_remove_all(void) list_for_each_entry_safe(module, next, &modules_list, list) { list_del(&module->list); - kobject_put(&module->kobj); ida_simple_remove(&module_id, module->id); + kobject_put(&module->kobj); } is_empty = list_empty(&modules_list); diff --git a/drivers/staging/greybus/tools/loopback_test.c b/drivers/staging/greybus/tools/loopback_test.c index fbe589fca840845ec8ec21fa81c065e9eab4926e..b6aa70b94f335de9830edae7165fae696f1f684e 100644 --- a/drivers/staging/greybus/tools/loopback_test.c +++ b/drivers/staging/greybus/tools/loopback_test.c @@ -20,6 +20,7 @@ #include #define MAX_NUM_DEVICES 10 +#define MAX_SYSFS_PREFIX 0x80 #define MAX_SYSFS_PATH 0x200 #define CSV_MAX_LINE 0x1000 #define SYSFS_MAX_INT 0x20 @@ -68,7 +69,7 @@ struct loopback_results { }; struct loopback_device { - char name[MAX_SYSFS_PATH]; + char name[MAX_STR_LEN]; char sysfs_entry[MAX_SYSFS_PATH]; char debugfs_entry[MAX_SYSFS_PATH]; struct loopback_results results; @@ -94,8 +95,8 @@ struct loopback_test { int stop_all; int poll_count; char test_name[MAX_STR_LEN]; - char sysfs_prefix[MAX_SYSFS_PATH]; - char debugfs_prefix[MAX_SYSFS_PATH]; + char sysfs_prefix[MAX_SYSFS_PREFIX]; + char debugfs_prefix[MAX_SYSFS_PREFIX]; struct timespec poll_timeout; struct loopback_device devices[MAX_NUM_DEVICES]; struct loopback_results aggregate_results; @@ -644,7 +645,7 @@ int find_loopback_devices(struct loopback_test *t) static int open_poll_files(struct loopback_test *t) { struct loopback_device *dev; - char buf[MAX_STR_LEN]; + char buf[MAX_SYSFS_PATH + MAX_STR_LEN]; char dummy; int fds_idx = 0; int i; @@ -914,10 +915,10 @@ int main(int argc, char *argv[]) t.iteration_max = atoi(optarg); break; case 'S': - snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", optarg); + snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg); break; case 'D': - snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", optarg); + snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg); break; case 'm': t.mask = atol(optarg); @@ -968,10 +969,10 @@ int main(int argc, char *argv[]) } if (!strcmp(t.sysfs_prefix, "")) - snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", sysfs_prefix); + snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", sysfs_prefix); if (!strcmp(t.debugfs_prefix, "")) - snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", debugfs_prefix); + snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", debugfs_prefix); ret = find_loopback_devices(&t); if (ret) diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 446310775e9021bcc7e9f72cb94545e0b9c1b012..184fc05a0f8b7bfab0d8405a25f1242f3b01d8e5 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -2051,7 +2051,7 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) struct ieee_param *param; uint ret = 0; - if (p->length < sizeof(struct ieee_param) || !p->pointer) { + if (!p->pointer || p->length != sizeof(struct ieee_param)) { ret = -EINVAL; goto out; } @@ -2856,7 +2856,7 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) goto out; } - if (!p->pointer) { + if (!p->pointer || p->length != sizeof(struct ieee_param)) { ret = -EINVAL; goto out; } diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 5364533585685e46af5513c3499aa5e1aa19488b..30615b8fb657a2dd0230b4419dc680edf74b9c75 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -40,12 +40,14 @@ static const struct usb_device_id rtw_usb_id_tbl[] = { /****** 8188EUS ********/ {USB_DEVICE(0x056e, 0x4008)}, /* Elecom WDC-150SU2M */ {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ + {USB_DEVICE(0x0B05, 0x18F0)}, /* ASUS USB-N10 Nano B1 */ {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ {USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */ + {USB_DEVICE(0x2C4E, 0x0102)}, /* MERCUSYS MW150US v2 */ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ {} /* Terminating entry */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index d0b317077511ce23d1939617dd575204bce90d84..f92f9073c50769e7e83dbc0b2746a27c23b34b9b 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -486,14 +486,13 @@ int rtl8723bs_xmit_thread(void *context) s32 ret; struct adapter *padapter; struct xmit_priv *pxmitpriv; - u8 thread_name[20] = "RTWHALXT"; - + u8 thread_name[20]; ret = _SUCCESS; padapter = context; pxmitpriv = &padapter->xmitpriv; - rtw_sprintf(thread_name, 20, "%s-"ADPT_FMT, thread_name, ADPT_ARG(padapter)); + rtw_sprintf(thread_name, 20, "RTWHALXT-" ADPT_FMT, ADPT_ARG(padapter)); thread_enter(thread_name); DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 1b61da61690b680f2514cff7d7bd0d363745cf55..d51f6c452972365e904384a8626ab74d7bdf4ee0 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -3495,7 +3495,7 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) /* down(&ieee->wx_sem); */ - if (p->length < sizeof(struct ieee_param) || !p->pointer) { + if (!p->pointer || p->length != sizeof(struct ieee_param)) { ret = -EINVAL; goto out; } @@ -4340,7 +4340,7 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) /* if (p->length < sizeof(struct ieee_param) || !p->pointer) { */ - if (!p->pointer) { + if (!p->pointer || p->length != sizeof(*param)) { ret = -EINVAL; goto out; } diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index 56f7be6af1f695a873c9acfe6619d3ec8dafd496..a27f5e9a1ae183f6621035a59662074b8faf7bfc 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -567,7 +567,7 @@ static u_long get_word(struct vc_data *vc) return 0; } else if (tmpx < vc->vc_cols - 2 && (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) && - get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) { + get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) { tmp_pos += 2; tmpx++; } else diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index 655f0002f8808a6d4527dd23f35987d8c014bda2..7b73fa2f883404b4b05e2db08af246e4bf31918b 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -140,7 +140,7 @@ int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb, vnt_rf_rssi_to_dbm(priv, *rssi, &rx_dbm); - priv->bb_pre_ed_rssi = (u8)rx_dbm + 1; + priv->bb_pre_ed_rssi = (u8)-rx_dbm + 1; priv->current_rssi = priv->bb_pre_ed_rssi; frame = skb_data + 8; diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c index c521729c4192cb500198a3252001d363211f026b..d5d89e83630936d519065921c015e6fdc780bea2 100644 --- a/drivers/staging/vt6656/int.c +++ b/drivers/staging/vt6656/int.c @@ -153,7 +153,8 @@ void vnt_int_process_data(struct vnt_private *priv) priv->wake_up_count = priv->hw->conf.listen_interval; - --priv->wake_up_count; + if (priv->wake_up_count) + --priv->wake_up_count; /* Turn on wake up to listen next beacon */ if (priv->wake_up_count == 1) diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c index cc18cb141bff18e8f80437361506d857eb0b8acc..5ecc1a97cb44a0ae21be567c98a7d5d1845a57ec 100644 --- a/drivers/staging/vt6656/key.c +++ b/drivers/staging/vt6656/key.c @@ -91,9 +91,6 @@ static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr, case VNT_KEY_PAIRWISE: key_mode |= mode; key_inx = 4; - /* Don't save entry for pairwise key for station mode */ - if (priv->op_mode == NL80211_IFTYPE_STATION) - clear_bit(entry, &priv->key_entry_inuse); break; default: return -EINVAL; @@ -117,7 +114,6 @@ static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr, int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct ieee80211_key_conf *key) { - struct ieee80211_bss_conf *conf = &vif->bss_conf; struct vnt_private *priv = hw->priv; u8 *mac_addr = NULL; u8 key_dec_mode = 0; @@ -159,16 +155,12 @@ int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; } - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) vnt_set_keymode(hw, mac_addr, key, VNT_KEY_PAIRWISE, key_dec_mode, true); - } else { - vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY, + else + vnt_set_keymode(hw, mac_addr, key, VNT_KEY_GROUP_ADDRESS, key_dec_mode, true); - vnt_set_keymode(hw, (u8 *)conf->bssid, key, - VNT_KEY_GROUP_ADDRESS, key_dec_mode, true); - } - return 0; } diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index e8ccd800c94fde6a504eec428291f7ab6f61cf4c..9adab851580cab21792c99fbf3a47c1e02ea8b8d 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -594,8 +594,6 @@ static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) priv->op_mode = vif->type; - vnt_set_bss_mode(priv); - /* LED blink on TX */ vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_INTER); @@ -682,7 +680,6 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, priv->basic_rates = conf->basic_rates; vnt_update_top_rates(priv); - vnt_set_bss_mode(priv); dev_dbg(&priv->usb->dev, "basic rates %x\n", conf->basic_rates); } @@ -711,11 +708,14 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, priv->short_slot_time = false; vnt_set_short_slot_time(priv); - vnt_update_ifs(priv); vnt_set_vga_gain_offset(priv, priv->bb_vga[0]); vnt_update_pre_ed_threshold(priv, false); } + if (changed & (BSS_CHANGED_BASIC_RATES | BSS_CHANGED_ERP_PREAMBLE | + BSS_CHANGED_ERP_SLOT)) + vnt_set_bss_mode(priv); + if (changed & BSS_CHANGED_TXPOWER) vnt_rf_setpower(priv, priv->current_rate, conf->chandef.chan->hw_value); @@ -739,12 +739,15 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - vnt_adjust_tsf(priv, conf->beacon_rate->hw_value, - conf->sync_tsf, priv->current_tsf); - vnt_mac_set_beacon_interval(priv, conf->beacon_int); vnt_reset_next_tbtt(priv, conf->beacon_int); + + vnt_adjust_tsf(priv, conf->beacon_rate->hw_value, + conf->sync_tsf, priv->current_tsf); + + vnt_update_next_tbtt(priv, + conf->sync_tsf, conf->beacon_int); } else { vnt_clear_current_tsf(priv); @@ -779,15 +782,11 @@ static void vnt_configure(struct ieee80211_hw *hw, { struct vnt_private *priv = hw->priv; u8 rx_mode = 0; - int rc; *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC; - rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR, - MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode); - - if (!rc) - rx_mode = RCR_MULTICAST | RCR_BROADCAST; + vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR, + MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode); dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode); @@ -828,8 +827,12 @@ static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; break; case DISABLE_KEY: - if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) + if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) { clear_bit(key->hw_key_idx, &priv->key_entry_inuse); + + vnt_mac_disable_keyentry(priv, key->hw_key_idx); + } + default: break; } diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index 2a22e448a2b3b49779446e8417ebaadcbf259874..fb1a76c4c9271fda2453a798fe57502a92aed210 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -3495,6 +3495,8 @@ static void hfa384x_int_rxmonitor(struct wlandevice *wlandev, WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)) { pr_debug("overlen frm: len=%zd\n", skblen - sizeof(struct p80211_caphdr)); + + return; } skb = dev_alloc_skb(skblen); diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c index b5ba176004c1f88aa1e0cfc5f127bc3fa06586b8..d8d86761b790ae07744525e279c09084a2e85b3a 100644 --- a/drivers/staging/wlan-ng/prism2usb.c +++ b/drivers/staging/wlan-ng/prism2usb.c @@ -180,6 +180,7 @@ static void prism2sta_disconnect_usb(struct usb_interface *interface) cancel_work_sync(&hw->link_bh); cancel_work_sync(&hw->commsqual_bh); + cancel_work_sync(&hw->usb_work); /* Now we complete any outstanding commands * and tell everyone who is waiting for their diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 37d64acea5e1ea166c6f78c8ce24fd33cf0495d5..ee49b227dc12b6ca04b4831427c61c2d19bdb2c5 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1158,9 +1158,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length, conn->cid); - if (target_get_sess_cmd(&cmd->se_cmd, true) < 0) - return iscsit_add_reject_cmd(cmd, - ISCSI_REASON_WAITING_FOR_LOGOUT, buf); + target_get_sess_cmd(&cmd->se_cmd, true); cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, scsilun_to_int(&hdr->lun)); @@ -2006,9 +2004,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, conn->sess->se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, cmd->sense_buffer + 2); - if (target_get_sess_cmd(&cmd->se_cmd, true) < 0) - return iscsit_add_reject_cmd(cmd, - ISCSI_REASON_WAITING_FOR_LOGOUT, buf); + target_get_sess_cmd(&cmd->se_cmd, true); /* * TASK_REASSIGN for ERL=2 / connection stays inside of @@ -4155,6 +4151,9 @@ int iscsit_close_connection( iscsit_stop_nopin_response_timer(conn); iscsit_stop_nopin_timer(conn); + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); + /* * During Connection recovery drop unacknowledged out of order * commands for this connection, and prepare the other commands @@ -4237,11 +4236,6 @@ int iscsit_close_connection( * must wait until they have completed. */ iscsit_check_conn_usage_count(conn); - target_sess_cmd_list_set_waiting(sess->se_sess); - target_wait_for_sess_cmds(sess->se_sess); - - if (conn->conn_transport->iscsit_wait_conn) - conn->conn_transport->iscsit_wait_conn(conn); ahash_request_free(conn->conn_tx_hash); if (conn->conn_rx_hash) { @@ -4320,30 +4314,37 @@ int iscsit_close_connection( if (!atomic_read(&sess->session_reinstatement) && atomic_read(&sess->session_fall_back_to_erl0)) { spin_unlock_bh(&sess->conn_lock); + complete_all(&sess->session_wait_comp); iscsit_close_session(sess); return 0; } else if (atomic_read(&sess->session_logout)) { pr_debug("Moving to TARG_SESS_STATE_FREE.\n"); sess->session_state = TARG_SESS_STATE_FREE; - spin_unlock_bh(&sess->conn_lock); - if (atomic_read(&sess->sleep_on_sess_wait_comp)) - complete(&sess->session_wait_comp); + if (atomic_read(&sess->session_close)) { + spin_unlock_bh(&sess->conn_lock); + complete_all(&sess->session_wait_comp); + iscsit_close_session(sess); + } else { + spin_unlock_bh(&sess->conn_lock); + } return 0; } else { pr_debug("Moving to TARG_SESS_STATE_FAILED.\n"); sess->session_state = TARG_SESS_STATE_FAILED; - if (!atomic_read(&sess->session_continuation)) { - spin_unlock_bh(&sess->conn_lock); + if (!atomic_read(&sess->session_continuation)) iscsit_start_time2retain_handler(sess); - } else - spin_unlock_bh(&sess->conn_lock); - if (atomic_read(&sess->sleep_on_sess_wait_comp)) - complete(&sess->session_wait_comp); + if (atomic_read(&sess->session_close)) { + spin_unlock_bh(&sess->conn_lock); + complete_all(&sess->session_wait_comp); + iscsit_close_session(sess); + } else { + spin_unlock_bh(&sess->conn_lock); + } return 0; } @@ -4452,9 +4453,9 @@ static void iscsit_logout_post_handler_closesession( complete(&conn->conn_logout_comp); iscsit_dec_conn_usage_count(conn); + atomic_set(&sess->session_close, 1); iscsit_stop_session(sess, sleep, sleep); iscsit_dec_session_usage_count(sess); - iscsit_close_session(sess); } static void iscsit_logout_post_handler_samecid( @@ -4589,49 +4590,6 @@ void iscsit_fail_session(struct iscsi_session *sess) sess->session_state = TARG_SESS_STATE_FAILED; } -int iscsit_free_session(struct iscsi_session *sess) -{ - u16 conn_count = atomic_read(&sess->nconn); - struct iscsi_conn *conn, *conn_tmp = NULL; - int is_last; - - spin_lock_bh(&sess->conn_lock); - atomic_set(&sess->sleep_on_sess_wait_comp, 1); - - list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list, - conn_list) { - if (conn_count == 0) - break; - - if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) { - is_last = 1; - } else { - iscsit_inc_conn_usage_count(conn_tmp); - is_last = 0; - } - iscsit_inc_conn_usage_count(conn); - - spin_unlock_bh(&sess->conn_lock); - iscsit_cause_connection_reinstatement(conn, 1); - spin_lock_bh(&sess->conn_lock); - - iscsit_dec_conn_usage_count(conn); - if (is_last == 0) - iscsit_dec_conn_usage_count(conn_tmp); - - conn_count--; - } - - if (atomic_read(&sess->nconn)) { - spin_unlock_bh(&sess->conn_lock); - wait_for_completion(&sess->session_wait_comp); - } else - spin_unlock_bh(&sess->conn_lock); - - iscsit_close_session(sess); - return 0; -} - void iscsit_stop_session( struct iscsi_session *sess, int session_sleep, @@ -4642,8 +4600,6 @@ void iscsit_stop_session( int is_last; spin_lock_bh(&sess->conn_lock); - if (session_sleep) - atomic_set(&sess->sleep_on_sess_wait_comp, 1); if (connection_sleep) { list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list, @@ -4701,12 +4657,15 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) spin_lock(&sess->conn_lock); if (atomic_read(&sess->session_fall_back_to_erl0) || atomic_read(&sess->session_logout) || + atomic_read(&sess->session_close) || (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { spin_unlock(&sess->conn_lock); continue; } + iscsit_inc_session_usage_count(sess); atomic_set(&sess->session_reinstatement, 1); atomic_set(&sess->session_fall_back_to_erl0, 1); + atomic_set(&sess->session_close, 1); spin_unlock(&sess->conn_lock); list_move_tail(&se_sess->sess_list, &free_list); @@ -4716,7 +4675,9 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) { sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - iscsit_free_session(sess); + list_del_init(&se_sess->sess_list); + iscsit_stop_session(sess, 1, 1); + iscsit_dec_session_usage_count(sess); session_count++; } diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index 42de1843aa40d06f9967693ab5dbf20852e84629..f0d2cbf594c92ea2adee3e98febe8b4b52310149 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -43,7 +43,6 @@ extern int iscsi_target_rx_thread(void *); extern int iscsit_close_connection(struct iscsi_conn *); extern int iscsit_close_session(struct iscsi_session *); extern void iscsit_fail_session(struct iscsi_session *); -extern int iscsit_free_session(struct iscsi_session *); extern void iscsit_stop_session(struct iscsi_session *, int, int); extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0ebc4818e132ade606a77e8e46b46e183e111ddd..4191e4a8a9ed64e3ac37aff1a9a659a6125c2666 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1503,20 +1503,23 @@ static void lio_tpg_close_session(struct se_session *se_sess) spin_lock(&sess->conn_lock); if (atomic_read(&sess->session_fall_back_to_erl0) || atomic_read(&sess->session_logout) || + atomic_read(&sess->session_close) || (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { spin_unlock(&sess->conn_lock); spin_unlock_bh(&se_tpg->session_lock); return; } + iscsit_inc_session_usage_count(sess); atomic_set(&sess->session_reinstatement, 1); atomic_set(&sess->session_fall_back_to_erl0, 1); + atomic_set(&sess->session_close, 1); spin_unlock(&sess->conn_lock); iscsit_stop_time2retain_timer(sess); spin_unlock_bh(&se_tpg->session_lock); iscsit_stop_session(sess, 1, 1); - iscsit_close_session(sess); + iscsit_dec_session_usage_count(sess); } static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg) diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 27893d90c4efa992aadc7122b6c3ff00a478ed1f..55df6f99e66917ed74f9f05bc22be6ac81904d76 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -199,6 +199,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) spin_lock(&sess_p->conn_lock); if (atomic_read(&sess_p->session_fall_back_to_erl0) || atomic_read(&sess_p->session_logout) || + atomic_read(&sess_p->session_close) || (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { spin_unlock(&sess_p->conn_lock); continue; @@ -209,6 +210,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) (sess_p->sess_ops->SessionType == sessiontype))) { atomic_set(&sess_p->session_reinstatement, 1); atomic_set(&sess_p->session_fall_back_to_erl0, 1); + atomic_set(&sess_p->session_close, 1); spin_unlock(&sess_p->conn_lock); iscsit_inc_session_usage_count(sess_p); iscsit_stop_time2retain_timer(sess_p); @@ -233,7 +235,6 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) if (sess->session_state == TARG_SESS_STATE_FAILED) { spin_unlock_bh(&sess->conn_lock); iscsit_dec_session_usage_count(sess); - iscsit_close_session(sess); return 0; } spin_unlock_bh(&sess->conn_lock); @@ -241,7 +242,6 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) iscsit_stop_session(sess, 1, 1); iscsit_dec_session_usage_count(sess); - iscsit_close_session(sess); return 0; } @@ -534,6 +534,7 @@ static int iscsi_login_non_zero_tsih_s2( sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr; if (atomic_read(&sess_p->session_fall_back_to_erl0) || atomic_read(&sess_p->session_logout) || + atomic_read(&sess_p->session_close) || (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) continue; if (!memcmp(sess_p->isid, pdu->isid, 6) && diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 95aa47ac4dcd2b923a996e709611d0fd52469718..f8621fe6737671341067d112650b2d75f5b0b850 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -76,7 +76,7 @@ static int fc_get_pr_transport_id( * encoded TransportID. */ ptr = &se_nacl->initiatorname[0]; - for (i = 0; i < 24; ) { + for (i = 0; i < 23; ) { if (!strncmp(&ptr[i], ":", 1)) { i++; continue; diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 60429011292a2c4c2fa4104a90414ae948f956a7..2a9e023f542919df1b84d0c1a53ecacf8d1c4300 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -447,7 +447,7 @@ iblock_execute_zero_out(struct block_device *bdev, struct se_cmd *cmd) target_to_linux_sector(dev, cmd->t_task_lba), target_to_linux_sector(dev, sbc_get_write_same_sectors(cmd)), - GFP_KERNEL, false); + GFP_KERNEL, BLKDEV_ZERO_NOUNMAP); if (ret) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/drivers/thermal/qcom/qmi_cooling.c b/drivers/thermal/qcom/qmi_cooling.c index 2309f029c859d0e8a848735e5faeee68b1688152..a9e0d73784ff034befecd590618d1ae06df8c293 100644 --- a/drivers/thermal/qcom/qmi_cooling.c +++ b/drivers/thermal/qcom/qmi_cooling.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -133,6 +133,10 @@ static struct qmi_dev_info device_clients[] = { .dev_name = "mmw_skin3", .type = QMI_CDEV_MAX_LIMIT_TYPE, }, + { + .dev_name = "modem_v2x", + .type = QMI_CDEV_MAX_LIMIT_TYPE, + }, { .dev_name = "cdsp_sw", .type = QMI_CDEV_MAX_LIMIT_TYPE, diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c index 46bfd0d5c2d282f8a1726bb453323b5ab7fc13a2..e27c9712ca1d9fce7f00b7e4565c26ff54b3708f 100644 --- a/drivers/thermal/qcom/qti_virtual_sensor.c +++ b/drivers/thermal/qcom/qti_virtual_sensor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -181,6 +181,17 @@ static const struct virtual_sensor_data qti_virtual_sensors[] = { "gpuss-3-usr"}, .logic = VIRT_MAXIMUM, }, + { + .virt_zone_name = "hexa-cpu-max-step", + .num_sensors = 6, + .sensor_names = {"apc1-cpu0-usr", + "apc1-cpu1-usr", + "apc1-cpu2-usr", + "apc1-cpu3-usr", + "cpuss0-usr", + "cpuss1-usr"}, + .logic = VIRT_MAXIMUM, + }, }; int qti_virtual_sensor_register(struct device *dev) diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index 209ba04bcc8c449c1a9957ec2f06d5d6772c5e4c..76c11c3c081c6bb49e62909c98dcaff095ff1af1 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -69,7 +69,6 @@ #define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT 3 #define TSENS_INIT_ID 0x5 #define TSENS_RECOVERY_LOOP_COUNT 5 -#define TSENS_RE_INIT_MAX_COUNT 5 static void msm_tsens_convert_temp(int last_temp, int *temp) { @@ -186,6 +185,7 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) if (tmdev->tsens_reinit_wa) { struct scm_desc desc = { 0 }; + int scm_cnt = 0, reg_write_cnt = 0; if (atomic_read(&in_tsens_reinit)) { pr_err("%s: tsens re-init is in progress\n", @@ -199,45 +199,87 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) tmdev->ops->dbg(tmdev, 0, TSENS_DBG_LOG_BUS_ID_DATA, NULL); - if (tmdev->tsens_reinit_cnt >= - TSENS_RE_INIT_MAX_COUNT) { - pr_err( - "%s: TSENS not recovered after %d re-init\n", - __func__, tmdev->tsens_reinit_cnt); - BUG(); - } + while (1) { + /* + * Invoke scm call only if SW register write is + * reflecting in controller. If not, wait for + * 2 ms and then retry. + */ + if (reg_write_cnt >= 100) { + msleep(100); + pr_err( + "%s: Tsens write is failed. cnt:%d\n", + __func__, reg_write_cnt); + BUG(); + } + writel_relaxed(BIT(2), + TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + code = readl_relaxed( + TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + if (!(code & BIT(2))) { + udelay(2000); + TSENS_DBG(tmdev, "%s cnt:%d\n", + "Re-try TSENS write prior to scm", + reg_write_cnt++); + continue; + } + reg_write_cnt = 0; - /* Make an scm call to re-init TSENS */ - TSENS_DBG(tmdev, "%s", - "Calling TZ to re-init TSENS\n"); - ret = scm_call2(SCM_SIP_FNID(SCM_SVC_TSENS, + /* Make an scm call to re-init TSENS */ + TSENS_DBG(tmdev, "%s", + "Calling TZ to re-init TSENS\n"); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_TSENS, TSENS_INIT_ID), &desc); - TSENS_DBG(tmdev, "%s", - "return from scm call\n"); - if (ret) { - pr_err("%s: scm call failed %d\n", - __func__, ret); - BUG(); - } - tsens_ret = desc.ret[0]; - if (tsens_ret) { - pr_err("%s: scm call failed to init tsens %d\n", - __func__, tsens_ret); - BUG(); + TSENS_DBG(tmdev, "%s", + "return from scm call\n"); + if (ret) { + msleep(100); + pr_err("%s: scm call failed %d\n", + __func__, ret); + BUG(); + } + tsens_ret = desc.ret[0]; + if (tsens_ret) { + msleep(100); + pr_err("%s: scm call failed, ret:%d\n", + __func__, tsens_ret); + BUG(); + } + + scm_cnt++; + rc = 0; + list_for_each_entry(tmdev_itr, + &tsens_device_list, list) { + rc = __tsens2xxx_hw_init(tmdev_itr); + if (rc) { + pr_err( + "%s: TSENS hw_init error\n", + __func__); + break; + } + } + + if (!rc) + break; + + if (scm_cnt >= 100) { + msleep(100); + pr_err( + "%s: Tsens is not up after %d scm\n", + __func__, scm_cnt); + BUG(); + } + udelay(2000); + TSENS_DBG(tmdev, "%s cnt:%d\n", + "Re-try TSENS scm call", scm_cnt); } + tmdev->tsens_reinit_cnt++; atomic_set(&in_tsens_reinit, 0); /* Notify thermal fwk */ list_for_each_entry(tmdev_itr, &tsens_device_list, list) { - rc = __tsens2xxx_hw_init(tmdev_itr); - if (rc) { - pr_err( - "%s: Failed to re-initialize TSENS controller\n", - __func__); - BUG(); - } queue_work(tmdev_itr->tsens_reinit_work, &tmdev_itr->therm_fwk_notify); } @@ -252,7 +294,6 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) sensor_read: tmdev->trdy_fail_ctr = 0; - tmdev->tsens_reinit_cnt = 0; code = readl_relaxed_no_log(sensor_addr + (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET)); diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index fe2384b019ec95f531718502579bb0197158591e..9cfc65ca173db5d04fe015e68c2e64fde0810186 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -240,6 +240,12 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, return dma_port_flash_read(sw->dma_port, offset, val, bytes); } +static int tb_switch_nvm_no_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return -EPERM; +} + static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, size_t bytes) { @@ -285,6 +291,7 @@ static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id, config.read_only = true; } else { config.name = "nvm_non_active"; + config.reg_read = tb_switch_nvm_no_read; config.reg_write = tb_switch_nvm_write; config.root_only = true; } diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index a1c7125cb968fdcbe9f69a5c29b306adff000b66..5a348efb91adae6d065f7735e76967d3b9ba8cc1 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -139,6 +139,21 @@ static int find_console_handle(void) return 1; } +static unsigned int local_ev_byte_channel_send(unsigned int handle, + unsigned int *count, + const char *p) +{ + char buffer[EV_BYTE_CHANNEL_MAX_BYTES]; + unsigned int c = *count; + + if (c < sizeof(buffer)) { + memcpy(buffer, p, c); + memset(&buffer[c], 0, sizeof(buffer) - c); + p = buffer; + } + return ev_byte_channel_send(handle, count, p); +} + /*************************** EARLY CONSOLE DRIVER ***************************/ #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC @@ -157,7 +172,7 @@ static void byte_channel_spin_send(const char data) do { count = 1; - ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, + ret = local_ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, &count, &data); } while (ret == EV_EAGAIN); } @@ -224,7 +239,7 @@ static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s, while (count) { len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES); do { - ret = ev_byte_channel_send(handle, &len, s); + ret = local_ev_byte_channel_send(handle, &len, s); } while (ret == EV_EAGAIN); count -= len; s += len; @@ -404,7 +419,7 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc) CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE), EV_BYTE_CHANNEL_MAX_BYTES); - ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail); + ret = local_ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail); /* 'len' is valid only if the return code is 0 or EV_EAGAIN */ if (!ret || (ret == EV_EAGAIN)) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index a8d399188242efe428bb579f845b716396465d9f..fc0ef13f2616a241c285f2fbb0a142e309f8d39e 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -288,10 +288,6 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) vtermnos[index] = vtermno; cons_ops[index] = ops; - /* reserve all indices up to and including this index */ - if (last_hvc < index) - last_hvc = index; - /* check if we need to re-register the kernel console */ hvc_check_console(index); @@ -895,13 +891,22 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, cons_ops[i] == hp->ops) break; - /* no matching slot, just use a counter */ - if (i >= MAX_NR_HVC_CONSOLES) - i = ++last_hvc; + if (i >= MAX_NR_HVC_CONSOLES) { + + /* find 'empty' slot for console */ + for (i = 0; i < MAX_NR_HVC_CONSOLES && vtermnos[i] != -1; i++) { + } + + /* no matching slot, just use a counter */ + if (i == MAX_NR_HVC_CONSOLES) + i = ++last_hvc + MAX_NR_HVC_CONSOLES; + } hp->index = i; - cons_ops[i] = ops; - vtermnos[i] = vtermno; + if (i < MAX_NR_HVC_CONSOLES) { + cons_ops[i] = ops; + vtermnos[i] = vtermno; + } list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 32943afacffd1042c1519695fc8367333342abba..1081810b3e3fed77411958ee559eb2888791031d 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -645,18 +645,21 @@ init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) tty_port_init(&info->port); info->port.ops = &rocket_port_ops; info->flags &= ~ROCKET_MODE_MASK; - switch (pc104[board][line]) { - case 422: - info->flags |= ROCKET_MODE_RS422; - break; - case 485: - info->flags |= ROCKET_MODE_RS485; - break; - case 232: - default: + if (board < ARRAY_SIZE(pc104) && line < ARRAY_SIZE(pc104_1)) + switch (pc104[board][line]) { + case 422: + info->flags |= ROCKET_MODE_RS422; + break; + case 485: + info->flags |= ROCKET_MODE_RS485; + break; + case 232: + default: + info->flags |= ROCKET_MODE_RS232; + break; + } + else info->flags |= ROCKET_MODE_RS232; - break; - } info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index f513107b9ea0b6a309a03c13ccbaeb5d73332d94..e6c9ff65402aecec38a38dcd2fe975ad97845d27 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -452,16 +452,18 @@ static int platform_serdev_register_devices(struct serdev_controller *ctrl) return err; } + /** - * serdev_controller_add() - Add an serdev controller + * serdev_controller_add_platform() - Add an serdev controller * @ctrl: controller to be registered. + * @platform: whether to permit fallthrough to platform device probe * * Register a controller previously allocated via serdev_controller_alloc() with - * the serdev core. + * the serdev core. Optionally permit probing via a platform device fallback. */ -int serdev_controller_add(struct serdev_controller *ctrl) +int serdev_controller_add_platform(struct serdev_controller *ctrl, bool platform) { - int ret_of, ret_platform, ret; + int ret, ret_of, ret_platform = -ENODEV; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) @@ -471,8 +473,9 @@ int serdev_controller_add(struct serdev_controller *ctrl) if (ret) return ret; - ret_platform = platform_serdev_register_devices(ctrl); ret_of = of_serdev_register_devices(ctrl); + if (platform) + ret_platform = platform_serdev_register_devices(ctrl); if (ret_of && ret_platform) { dev_dbg(&ctrl->dev, "no devices registered: of:%d " "platform:%d\n", @@ -489,7 +492,7 @@ int serdev_controller_add(struct serdev_controller *ctrl) device_del(&ctrl->dev); return ret; }; -EXPORT_SYMBOL_GPL(serdev_controller_add); +EXPORT_SYMBOL_GPL(serdev_controller_add_platform); /* Remove a device associated with a controller */ static int serdev_remove_device(struct device *dev, void *data) diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index 69fc6d9ab490f90cea6b5e67b10e0b41f66d5726..0669e18ff8796b43810124cbbc85cd0ead8a3a54 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -15,9 +15,15 @@ #include #include #include +#include +#include #define SERPORT_ACTIVE 1 +static char *pdev_tty_port; +module_param(pdev_tty_port, charp, 0644); +MODULE_PARM_DESC(pdev_tty_port, "platform device tty port to claim"); + struct serport { struct tty_port *port; struct tty_struct *tty; @@ -238,9 +244,9 @@ struct device *serdev_tty_port_register(struct tty_port *port, struct device *parent, struct tty_driver *drv, int idx) { - const struct tty_port_client_operations *old_ops; struct serdev_controller *ctrl; struct serport *serport; + bool platform = false; int ret; if (!port || !drv || !parent) @@ -257,11 +263,27 @@ struct device *serdev_tty_port_register(struct tty_port *port, ctrl->ops = &ctrl_ops; - old_ops = port->client_ops; port->client_ops = &client_ops; port->client_data = ctrl; - ret = serdev_controller_add(ctrl); + /* There is not always a way to bind specific platform devices because + * they may be defined on platforms without DT or ACPI. When dealing + * with a platform devices, do not allow direct binding unless it is + * whitelisted by module parameter. If a platform device is otherwise + * described by DT or ACPI it will still be bound and this check will + * be ignored. + */ + if (parent->bus == &platform_bus_type) { + char tty_port_name[7]; + + sprintf(tty_port_name, "%s%d", drv->name, idx); + if (pdev_tty_port && + !strcmp(pdev_tty_port, tty_port_name)) { + platform = true; + } + } + + ret = serdev_controller_add_platform(ctrl, platform); if (ret) goto err_reset_data; @@ -270,7 +292,7 @@ struct device *serdev_tty_port_register(struct tty_port *port, err_reset_data: port->client_data = NULL; - port->client_ops = old_ops; + port->client_ops = &tty_port_default_client_ops; serdev_controller_put(ctrl); return ERR_PTR(ret); @@ -285,8 +307,8 @@ int serdev_tty_port_unregister(struct tty_port *port) return -ENODEV; serdev_controller_remove(ctrl); - port->client_ops = NULL; port->client_data = NULL; + port->client_ops = &tty_port_default_client_ops; serdev_controller_put(ctrl); return 0; diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 33a801353114c016ca7fe5fa0aebe507a3d2844b..0a89df390f248ec5209bb64b706d5ca82d72d826 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -256,7 +256,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.line = rc; port.port.irq = irq_of_parse_and_map(np, 0); - port.port.irqflags = IRQF_SHARED; port.port.iotype = UPIO_MEM; port.port.type = PORT_16550A; port.port.uartclk = clk; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index c698ebab6d3bd5fa12b87fbdd83575b306227fdd..5017a0f46b826574e90c30fb94535b8de6b18742 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -181,7 +181,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up) struct hlist_head *h; struct hlist_node *n; struct irq_info *i; - int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; + int ret; mutex_lock(&hash_mutex); @@ -216,9 +216,8 @@ static int serial_link_irq_chain(struct uart_8250_port *up) INIT_LIST_HEAD(&up->list); i->head = &up->list; spin_unlock_irq(&i->lock); - irq_flags |= up->port.irqflags; ret = request_irq(up->port.irq, serial8250_interrupt, - irq_flags, up->port.name, i); + up->port.irqflags, up->port.name, i); if (ret < 0) serial_do_unlink(i, up); } diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 411b4b03457bbbd7bac5c1f2ed542e81ebda47e8..899f36b59af798c085deb70daedf7e37ae1678cb 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -27,6 +27,14 @@ #include "8250.h" +#define PCI_DEVICE_ID_ACCES_COM_2S 0x1052 +#define PCI_DEVICE_ID_ACCES_COM_4S 0x105d +#define PCI_DEVICE_ID_ACCES_COM_8S 0x106c +#define PCI_DEVICE_ID_ACCES_COM232_8 0x10a8 +#define PCI_DEVICE_ID_ACCES_COM_2SM 0x10d2 +#define PCI_DEVICE_ID_ACCES_COM_4SM 0x10db +#define PCI_DEVICE_ID_ACCES_COM_8SM 0x10ea + #define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002 #define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004 #define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a @@ -562,6 +570,22 @@ static int __maybe_unused exar_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); +static const struct exar8250_board acces_com_2x = { + .num_ports = 2, + .setup = pci_xr17c154_setup, +}; + +static const struct exar8250_board acces_com_4x = { + .num_ports = 4, + .setup = pci_xr17c154_setup, +}; + +static const struct exar8250_board acces_com_8x = { + .num_ports = 8, + .setup = pci_xr17c154_setup, +}; + + static const struct exar8250_board pbn_fastcom335_2 = { .num_ports = 2, .setup = pci_fastcom335_setup, @@ -632,6 +656,15 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { } static const struct pci_device_id exar_pci_tbl[] = { + EXAR_DEVICE(ACCESSIO, ACCES_COM_2S, acces_com_2x), + EXAR_DEVICE(ACCESSIO, ACCES_COM_4S, acces_com_4x), + EXAR_DEVICE(ACCESSIO, ACCES_COM_8S, acces_com_8x), + EXAR_DEVICE(ACCESSIO, ACCES_COM232_8, acces_com_8x), + EXAR_DEVICE(ACCESSIO, ACCES_COM_2SM, acces_com_2x), + EXAR_DEVICE(ACCESSIO, ACCES_COM_4SM, acces_com_4x), + EXAR_DEVICE(ACCESSIO, ACCES_COM_8SM, acces_com_8x), + + CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect), diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a73d2bc4b6852c9a1b2523a0ad27524fc7984fde..90a93c001e169bc350d909df458c31522883e168 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2258,6 +2258,10 @@ int serial8250_do_startup(struct uart_port *port) } } + /* Check if we need to have shared IRQs */ + if (port->irq && (up->port.flags & UPF_SHARE_IRQ)) + up->port.irqflags |= IRQF_SHARED; + if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { unsigned char iir1; /* diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index ed545a61413c045df92a11c0cbc188e03cdb2926..ac56a5131a9ccee0ed2aa07c82aac2ed2509936e 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -289,6 +289,10 @@ static void ar933x_uart_set_termios(struct uart_port *port, ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, AR933X_UART_CS_HOST_INT_EN); + /* enable RX and TX ready overide */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE); + /* reenable the UART */ ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, @@ -421,6 +425,10 @@ static int ar933x_uart_startup(struct uart_port *port) ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, AR933X_UART_CS_HOST_INT_EN); + /* enable RX and TX ready overide */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE); + /* Enable RX interrupts */ up->ier = AR933X_UART_INT_RX_VALID; ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 367ce812743e22d6fedd538c14a17d147b6e8448..a00227d312d3f74afed6ed3953044f983224eb31 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -498,7 +498,8 @@ static void atmel_stop_tx(struct uart_port *port) atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); if (atmel_uart_is_half_duplex(port)) - atmel_start_rx(port); + if (!atomic_read(&atmel_port->tasklet_shutdown)) + atmel_start_rx(port); } diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a81a5be0cf7a2a6740806b13d449d5c86630e0c4..630065b551f5f1ea57ddc687c62147fec54d9894 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -80,7 +80,7 @@ #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ #define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */ #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ -#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_RXDMAEN (1<<8) /* Recv ready DMA enable */ #define UCR1_IREN (1<<7) /* Infrared interface enable */ #define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ @@ -352,6 +352,30 @@ static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) *ucr2 |= UCR2_CTSC; } +/* + * interrupts disabled on entry + */ +static void imx_start_rx(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned int ucr1, ucr2; + + ucr1 = readl(port->membase + UCR1); + ucr2 = readl(port->membase + UCR2); + + ucr2 |= UCR2_RXEN; + + if (sport->dma_is_enabled) { + ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + } else { + ucr1 |= UCR1_RRDYEN; + } + + /* Write UCR2 first as it includes RXEN */ + writel(ucr2, port->membase + UCR2); + writel(ucr1, port->membase + UCR1); +} + /* * interrupts disabled on entry */ @@ -378,9 +402,10 @@ static void imx_stop_tx(struct uart_port *port) imx_port_rts_active(sport, &temp); else imx_port_rts_inactive(sport, &temp); - temp |= UCR2_RXEN; writel(temp, port->membase + UCR2); + imx_start_rx(port); + temp = readl(port->membase + UCR4); temp &= ~UCR4_TCEN; writel(temp, port->membase + UCR4); @@ -393,7 +418,7 @@ static void imx_stop_tx(struct uart_port *port) static void imx_stop_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; + unsigned long ucr1, ucr2; if (sport->dma_is_enabled && sport->dma_is_rxing) { if (sport->port.suspended) { @@ -404,12 +429,18 @@ static void imx_stop_rx(struct uart_port *port) } } - temp = readl(sport->port.membase + UCR2); - writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); + ucr1 = readl(sport->port.membase + UCR1); + ucr2 = readl(sport->port.membase + UCR2); - /* disable the `Receiver Ready Interrrupt` */ - temp = readl(sport->port.membase + UCR1); - writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1); + if (sport->dma_is_enabled) { + ucr1 &= ~(UCR1_RXDMAEN | UCR1_ATDMAEN); + } else { + ucr1 &= ~UCR1_RRDYEN; + } + writel(ucr1, port->membase + UCR1); + + ucr2 &= ~UCR2_RXEN; + writel(ucr2, port->membase + UCR2); } /* @@ -526,7 +557,7 @@ static void imx_dma_tx(struct imx_port *sport) sport->tx_bytes = uart_circ_chars_pending(xmit); - if (xmit->tail < xmit->head) { + if (xmit->tail < xmit->head || xmit->head == 0) { sport->dma_tx_nents = 1; sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); } else { @@ -581,10 +612,11 @@ static void imx_start_tx(struct uart_port *port) imx_port_rts_active(sport, &temp); else imx_port_rts_inactive(sport, &temp); - if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) - temp &= ~UCR2_RXEN; writel(temp, port->membase + UCR2); + if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) + imx_stop_rx(port); + /* enable transmitter and shifter empty irq */ temp = readl(port->membase + UCR4); temp |= UCR4_TCEN; @@ -811,14 +843,42 @@ static void imx_mctrl_check(struct imx_port *sport) static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int sts; - unsigned int sts2; + unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; - sts = readl(sport->port.membase + USR1); - sts2 = readl(sport->port.membase + USR2); + usr1 = readl(sport->port.membase + USR1); + usr2 = readl(sport->port.membase + USR2); + ucr1 = readl(sport->port.membase + UCR1); + ucr2 = readl(sport->port.membase + UCR2); + ucr3 = readl(sport->port.membase + UCR3); + ucr4 = readl(sport->port.membase + UCR4); - if (sts & (USR1_RRDY | USR1_AGTIM)) { + /* + * Even if a condition is true that can trigger an irq only handle it if + * the respective irq source is enabled. This prevents some undesired + * actions, for example if a character that sits in the RX FIFO and that + * should be fetched via DMA is tried to be fetched using PIO. Or the + * receiver is currently off and so reading from URXD0 results in an + * exception. So just mask the (raw) status bits for disabled irqs. + */ + if ((ucr1 & UCR1_RRDYEN) == 0) + usr1 &= ~USR1_RRDY; + if ((ucr2 & UCR2_ATEN) == 0) + usr1 &= ~USR1_AGTIM; + if ((ucr1 & UCR1_TXMPTYEN) == 0) + usr1 &= ~USR1_TRDY; + if ((ucr4 & UCR4_TCEN) == 0) + usr2 &= ~USR2_TXDC; + if ((ucr3 & UCR3_DTRDEN) == 0) + usr1 &= ~USR1_DTRD; + if ((ucr1 & UCR1_RTSDEN) == 0) + usr1 &= ~USR1_RTSD; + if ((ucr3 & UCR3_AWAKEN) == 0) + usr1 &= ~USR1_AWAKE; + if ((ucr4 & UCR4_OREN) == 0) + usr2 &= ~USR2_ORE; + + if (usr1 & (USR1_RRDY | USR1_AGTIM)) { if (sport->dma_is_enabled) imx_dma_rxint(sport); else @@ -826,18 +886,15 @@ static irqreturn_t imx_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - if ((sts & USR1_TRDY && - readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || - (sts2 & USR2_TXDC && - readl(sport->port.membase + UCR4) & UCR4_TCEN)) { + if ((usr1 & USR1_TRDY) || (usr2 & USR2_TXDC)) { imx_txint(irq, dev_id); ret = IRQ_HANDLED; } - if (sts & USR1_DTRD) { + if (usr1 & USR1_DTRD) { unsigned long flags; - if (sts & USR1_DTRD) + if (usr1 & USR1_DTRD) writel(USR1_DTRD, sport->port.membase + USR1); spin_lock_irqsave(&sport->port.lock, flags); @@ -847,17 +904,17 @@ static irqreturn_t imx_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - if (sts & USR1_RTSD) { + if (usr1 & USR1_RTSD) { imx_rtsint(irq, dev_id); ret = IRQ_HANDLED; } - if (sts & USR1_AWAKE) { + if (usr1 & USR1_AWAKE) { writel(USR1_AWAKE, sport->port.membase + USR1); ret = IRQ_HANDLED; } - if (sts2 & USR2_ORE) { + if (usr2 & USR2_ORE) { sport->port.icount.overrun++; writel(USR2_ORE, sport->port.membase + USR2); ret = IRQ_HANDLED; @@ -1206,7 +1263,7 @@ static void imx_enable_dma(struct imx_port *sport) /* set UCR1 */ temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; + temp |= UCR1_RXDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR2); @@ -1224,7 +1281,7 @@ static void imx_disable_dma(struct imx_port *sport) /* clear UCR1 */ temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN); + temp &= ~(UCR1_RXDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN); writel(temp, sport->port.membase + UCR1); /* clear UCR2 */ @@ -1289,11 +1346,9 @@ static int imx_startup(struct uart_port *port) writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1); writel(USR2_ORE, sport->port.membase + USR2); - if (sport->dma_is_inited && !sport->dma_is_enabled) - imx_enable_dma(sport); - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN | UCR1_UARTEN; + temp &= ~UCR1_RRDYEN; + temp |= UCR1_UARTEN; if (sport->have_rtscts) temp |= UCR1_RTSDEN; @@ -1332,14 +1387,13 @@ static int imx_startup(struct uart_port *port) */ imx_enable_ms(&sport->port); - /* - * Start RX DMA immediately instead of waiting for RX FIFO interrupts. - * In our iMX53 the average delay for the first reception dropped from - * approximately 35000 microseconds to 1000 microseconds. - */ - if (sport->dma_is_enabled) { - imx_disable_rx_int(sport); + if (sport->dma_is_inited) { + imx_enable_dma(sport); start_rx_dma(sport); + } else { + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); } spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1386,7 +1440,8 @@ static void imx_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | + UCR1_RXDMAEN | UCR1_ATDMAEN); writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1659,7 +1714,7 @@ static int imx_poll_init(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - unsigned long temp; + unsigned long ucr1, ucr2; int retval; retval = clk_prepare_enable(sport->clk_ipg); @@ -1673,16 +1728,29 @@ static int imx_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); - temp = readl(sport->port.membase + UCR1); + /* + * Be careful about the order of enabling bits here. First enable the + * receiver (UARTEN + RXEN) and only then the corresponding irqs. + * This prevents that a character that already sits in the RX fifo is + * triggering an irq but the try to fetch it from there results in an + * exception because UARTEN or RXEN is still off. + */ + ucr1 = readl(port->membase + UCR1); + ucr2 = readl(port->membase + UCR2); + if (is_imx1_uart(sport)) - temp |= IMX1_UCR1_UARTCLKEN; - temp |= UCR1_UARTEN | UCR1_RRDYEN; - temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN); - writel(temp, sport->port.membase + UCR1); + ucr1 |= IMX1_UCR1_UARTCLKEN; - temp = readl(sport->port.membase + UCR2); - temp |= UCR2_RXEN; - writel(temp, sport->port.membase + UCR2); + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN | UCR1_RRDYEN); + + ucr2 |= UCR2_RXEN; + + writel(ucr1, sport->port.membase + UCR1); + writel(ucr2, sport->port.membase + UCR2); + + /* now enable irqs */ + writel(ucr1 | UCR1_RRDYEN, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1742,11 +1810,8 @@ static int imx_rs485_config(struct uart_port *port, /* Make sure Rx is enabled in case Tx is active with Rx disabled */ if (!(rs485conf->flags & SER_RS485_ENABLED) || - rs485conf->flags & SER_RS485_RX_DURING_TX) { - temp = readl(sport->port.membase + UCR2); - temp |= UCR2_RXEN; - writel(temp, sport->port.membase + UCR2); - } + rs485conf->flags & SER_RS485_RX_DURING_TX) + imx_start_rx(port); port->rs485 = *rs485conf; diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index b0d04569847c2879ca82d8389d3eccfe3e0f61d0..d5858c08919b9014be28197b09ac8e690e536a15 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -125,6 +126,24 @@ #define IPC_LOG_TX_RX_PAGES (10) #define DATA_BYTES_PER_LINE (32) +#define M_IRQ_BITS (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN |\ + M_CMD_CANCEL_EN | M_CMD_ABORT_EN) +#define S_IRQ_BITS (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN |\ + S_CMD_CANCEL_EN | S_CMD_ABORT_EN) +#define DMA_TX_IRQ_BITS (TX_RESET_DONE | TX_DMA_DONE) +#define DMA_RX_IRQ_BITS (RX_EOT | RX_RESET_DONE | UART_DMA_RX_ERRS |\ + UART_DMA_RX_PARITY_ERR | UART_DMA_RX_BREAK |\ + RX_DMA_DONE) + +/* Required for polling for 100 msecs */ +#define POLL_WAIT_TIMEOUT_MSEC 100 + +/* + * Number of iterrations required while polling + * where each iterration has a delay of 100 usecs + */ +#define POLL_ITERATIONS 1000 + #define IPC_LOG_MSG(ctx, x...) do { \ if (ctx) \ ipc_log_string(ctx, x); \ @@ -148,7 +167,7 @@ struct msm_geni_serial_ver_info { struct msm_geni_serial_port { struct uart_port uport; - char name[20]; + const char *name; unsigned int tx_fifo_depth; unsigned int tx_fifo_width; unsigned int rx_fifo_depth; @@ -188,6 +207,14 @@ struct msm_geni_serial_port { bool startup_in_progress; bool pm_auto_suspend_disable; struct msm_geni_serial_ssr uart_ssr; + bool is_console; + bool rumi_platform; + bool m_cmd_done; + bool s_cmd_done; + bool m_cmd; + bool s_cmd; + struct completion m_cmd_timeout; + struct completion s_cmd_timeout; }; static const struct uart_ops msm_geni_serial_pops; @@ -223,6 +250,170 @@ static void msm_geni_serial_ssr_up(struct device *dev); static struct msm_geni_serial_port msm_geni_console_port; static struct msm_geni_serial_port msm_geni_serial_ports[GENI_UART_NR_PORTS]; +static void msm_geni_serial_handle_isr(struct uart_port *uport, + unsigned long *flags, bool is_irq_masked); + +/* + * The below API is required to check if uport->lock (spinlock) + * is taken by the serial layer or not. If the lock is not taken + * then we can rely on the isr to be fired and if the lock is taken + * by the serial layer then we need to poll for the interrupts. + * + * Returns true(1) if spinlock is already taken by framework (serial layer) + * Return false(0) if spinlock is not taken by framework. + */ +static int msm_geni_serial_spinlocked(struct uart_port *uport) +{ + unsigned long flags; + bool locked; + + locked = spin_trylock_irqsave(&uport->lock, flags); + if (locked) + spin_unlock_irqrestore(&uport->lock, flags); + + return !locked; +} + +/* + * We are enabling the interrupts once the polling operations + * is completed. + */ +static void msm_geni_serial_enable_interrupts(struct uart_port *uport) +{ + unsigned int geni_m_irq_en, geni_s_irq_en; + unsigned int dma_m_irq_en, dma_s_irq_en; + struct msm_geni_serial_port *port = GET_DEV_PORT(uport); + + geni_m_irq_en = geni_read_reg_nolog(uport->membase, + SE_GENI_M_IRQ_EN); + geni_s_irq_en = geni_read_reg_nolog(uport->membase, + SE_GENI_S_IRQ_EN); + if (port->xfer_mode == SE_DMA) { + dma_m_irq_en = geni_read_reg_nolog(uport->membase, + SE_DMA_TX_IRQ_EN); + dma_s_irq_en = geni_read_reg_nolog(uport->membase, + SE_DMA_RX_IRQ_EN); + } + + geni_m_irq_en |= M_IRQ_BITS; + geni_s_irq_en |= S_IRQ_BITS; + if (port->xfer_mode == SE_DMA) { + if (((port->ver_info.hw_major_ver <= 1) && + (port->ver_info.hw_minor_ver <= 2))) + dma_m_irq_en |= DMA_TX_IRQ_BITS; + else + dma_m_irq_en |= DMA_TX_IRQ_BITS | TX_GENI_CANCEL_IRQ; + dma_s_irq_en |= (DMA_RX_IRQ_BITS | + RX_GENI_CANCEL_IRQ(port->ver_info)); + } + + geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN); + geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN); + if (port->xfer_mode == SE_DMA) { + geni_write_reg_nolog(dma_m_irq_en, uport->membase, + SE_DMA_TX_IRQ_EN); + geni_write_reg_nolog(dma_s_irq_en, uport->membase, + SE_DMA_RX_IRQ_EN); + } +} + +/* Try Disabling the interrupts in order to do polling in an atomic contexts. */ +static bool msm_serial_try_disable_interrupts(struct uart_port *uport) +{ + unsigned int geni_m_irq_en, geni_s_irq_en; + unsigned int dma_m_irq_en, dma_s_irq_en; + struct msm_geni_serial_port *port = GET_DEV_PORT(uport); + + /* + * We don't need to disable interrupts if spinlock is not taken + * by framework as we can rely on ISR. + */ + if (!msm_geni_serial_spinlocked(uport)) + return false; + + geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); + geni_s_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_EN); + if (port->xfer_mode == SE_DMA) { + dma_m_irq_en = geni_read_reg_nolog(uport->membase, + SE_DMA_TX_IRQ_EN); + dma_s_irq_en = geni_read_reg_nolog(uport->membase, + SE_DMA_RX_IRQ_EN); + } + + geni_m_irq_en &= ~M_IRQ_BITS; + geni_s_irq_en &= ~S_IRQ_BITS; + if (port->xfer_mode == SE_DMA) { + if (((port->ver_info.hw_major_ver <= 1) && + (port->ver_info.hw_minor_ver <= 2))) + dma_m_irq_en &= ~DMA_TX_IRQ_BITS; + else + dma_m_irq_en &= ~(DMA_TX_IRQ_BITS | + TX_GENI_CANCEL_IRQ); + dma_s_irq_en &= DMA_RX_IRQ_BITS | + RX_GENI_CANCEL_IRQ(port->ver_info); + } + + geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN); + geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN); + if (port->xfer_mode == SE_DMA) { + geni_write_reg_nolog(dma_m_irq_en, uport->membase, + SE_DMA_TX_IRQ_EN); + geni_write_reg_nolog(dma_s_irq_en, uport->membase, + SE_DMA_RX_IRQ_EN); + } + + return true; +} + +/* + * We need to poll for interrupt if we are in an atomic context + * as serial framework might be taking spinlocks and depend on the isr + * in a non-atomic context. This API decides wheather to poll for + * interrupt or depend on the isr based on in_atomic() call. + */ +static bool geni_wait_for_cmd_done(struct uart_port *uport, bool is_irq_masked) +{ + struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); + unsigned long timeout = POLL_ITERATIONS; + unsigned long flags = 0; + + /* + * We need to do polling if spinlock is taken + * by framework as we cannot rely on ISR. + */ + if (is_irq_masked) { + /* + * Polling is done for 1000 iterrations with + * 10 usecs interval which in total accumulates + * to 10 msecs + */ + if (msm_port->m_cmd) { + while (!msm_port->m_cmd_done && timeout > 0) { + msm_geni_serial_handle_isr(uport, &flags, true); + timeout--; + udelay(100); + } + } else if (msm_port->s_cmd) { + while (!msm_port->s_cmd_done && timeout > 0) { + msm_geni_serial_handle_isr(uport, &flags, true); + timeout--; + udelay(100); + } + } + } else { + /* Waiting for 10 milli second for interrupt to be fired */ + if (msm_port->m_cmd) + timeout = wait_for_completion_timeout + (&msm_port->m_cmd_timeout, + msecs_to_jiffies(POLL_WAIT_TIMEOUT_MSEC)); + else if (msm_port->s_cmd) + timeout = wait_for_completion_timeout + (&msm_port->s_cmd_timeout, + msecs_to_jiffies(POLL_WAIT_TIMEOUT_MSEC)); + } + + return timeout ? 0 : 1; +} static void msm_geni_serial_config_port(struct uart_port *uport, int cfg_flags) { @@ -476,7 +667,8 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) mctrl |= TIOCM_CTS; - + IPC_LOG_MSG(port->ipc_log_misc, "%s: geni_ios:0x%x, mctrl:0x%x\n", + __func__, geni_ios, mctrl); return mctrl; } @@ -572,7 +764,6 @@ static int msm_geni_serial_power_on(struct uart_port *uport) } else { pm_runtime_get_noresume(uport->dev); pm_runtime_set_active(uport->dev); - enable_irq(uport->irq); } pm_runtime_enable(uport->dev); if (lock) @@ -663,64 +854,32 @@ static void msm_geni_serial_setup_tx(struct uart_port *uport, mb(); } -static void msm_geni_serial_poll_cancel_tx(struct uart_port *uport) +static void msm_geni_serial_poll_tx_done(struct uart_port *uport) { int done = 0; - unsigned int irq_clear = M_CMD_DONE_EN; + unsigned int irq_clear = 0; done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { - geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase, - SE_GENI_M_CMD_CTRL_REG); - irq_clear |= M_CMD_ABORT_EN; - msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_ABORT_EN, true); - } - geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_M_IRQ_CLEAR); -} - -static void msm_geni_serial_abort_rx(struct uart_port *uport) -{ - unsigned int irq_clear = S_CMD_DONE_EN; - struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - - geni_abort_s_cmd(uport->membase); - /* Ensure this goes through before polling. */ - mb(); - irq_clear |= S_CMD_ABORT_EN; - msm_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, - S_GENI_CMD_ABORT, false); - geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_S_IRQ_CLEAR); - /* FORCE_DEFAULT makes RFR default high, hence set manually Low */ - msm_geni_serial_set_manual_flow(true, port); - geni_write_reg(FORCE_DEFAULT, uport->membase, GENI_FORCE_DEFAULT_REG); -} - -static void msm_geni_serial_complete_rx_eot(struct uart_port *uport) -{ - int poll_done = 0, tries = 0; - struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - - if (port->uart_ssr.is_ssr_down) { - IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n", - __func__); - return; + /* + * Failure IPC logs are not added as this API is + * used by early console and it doesn't have log handle. + */ + geni_write_reg(M_GENI_CMD_CANCEL, uport->membase, + SE_GENI_M_CMD_CTRL_REG); + done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, + M_CMD_CANCEL_EN, true); + if (!done) { + geni_write_reg_nolog(M_GENI_CMD_ABORT, uport->membase, + SE_GENI_M_CMD_CTRL_REG); + msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, + M_CMD_ABORT_EN, true); + } } - do { - poll_done = msm_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT, - RX_EOT, true); - tries++; - } while (!poll_done && tries < 5); - - if (!poll_done) - IPC_LOG_MSG(port->ipc_log_misc, - "%s: RX_EOT, GENI:0x%x, DMA_DEBUG:0x%x\n", __func__, - geni_read_reg_nolog(uport->membase, SE_GENI_STATUS), - geni_read_reg_nolog(uport->membase, SE_DMA_DEBUG_REG0)); - else - geni_write_reg_nolog(RX_EOT, uport->membase, SE_DMA_RX_IRQ_CLR); + irq_clear = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_STATUS); + geni_write_reg_nolog(irq_clear, uport->membase, SE_GENI_M_IRQ_CLEAR); } #ifdef CONFIG_CONSOLE_POLL @@ -776,7 +935,9 @@ static void msm_geni_serial_poll_put_char(struct uart_port *uport, * Ensure FIFO write goes through before polling for status but. */ mb(); - msm_geni_serial_poll_cancel_tx(uport); + msm_serial_try_disable_interrupts(uport); + msm_geni_serial_poll_tx_done(uport); + msm_geni_serial_enable_interrupts(uport); } #endif @@ -836,7 +997,9 @@ __msm_geni_serial_console_write(struct uart_port *uport, const char *s, mb(); i += chars_to_write; } - msm_geni_serial_poll_cancel_tx(uport); + msm_serial_try_disable_interrupts(uport); + msm_geni_serial_poll_tx_done(uport); + msm_geni_serial_enable_interrupts(uport); } static void msm_geni_serial_console_write(struct console *co, const char *s, @@ -847,6 +1010,8 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, bool locked = true; unsigned long flags; unsigned int geni_status; + bool timeout; + bool is_irq_masked; int irq_en; WARN_ON(co->index < 0 || co->index >= GENI_UART_NR_PORTS); @@ -864,24 +1029,45 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ - if (!locked) { + if ((geni_status & M_GENI_CMD_ACTIVE) && !locked) { + port->m_cmd_done = false; + port->m_cmd = true; + reinit_completion(&port->m_cmd_timeout); + is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); - if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_CANCEL_EN, true)) { + + /* + * Console should be in polling mode. Hence directly pass true + * as argument for wait_for_cmd_done here to handle cancel tx + * in polling mode. + */ + timeout = geni_wait_for_cmd_done(uport, true); + if (timeout) { + IPC_LOG_MSG(port->console_log, + "%s: tx_cancel failed 0x%x\n", + __func__, geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS)); + + reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); - msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_ABORT_EN, true); - geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase, - SE_GENI_M_IRQ_CLEAR); + timeout = geni_wait_for_cmd_done(uport, true); + if (timeout) + IPC_LOG_MSG(port->console_log, + "%s: tx abort failed 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS)); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + + msm_geni_serial_enable_interrupts(uport); + port->m_cmd = false; } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->cur_tx_remaining) { /* It seems we can interrupt existing transfers unless all data * has been sent, in which case we need to look for done first. */ - msm_geni_serial_poll_cancel_tx(uport); + msm_serial_try_disable_interrupts(uport); + msm_geni_serial_poll_tx_done(uport); + msm_geni_serial_enable_interrupts(uport); /* Enable WATERMARK interrupt for every new console write op */ if (uart_circ_chars_pending(&uport->state->xmit)) { @@ -936,18 +1122,6 @@ static int handle_rx_console(struct uart_port *uport, tty_insert_flip_char(tport, rx_char[c], flag); } } - if (!drop_rx) { - /* - * Driver acquiring port->lock in isr function and calling - * tty_flip_buffer_push() which in turn will wait for - * another lock from framework __queue_work function. - * release the port lock before calling tty_flip_buffer_push() - * to avoid deadlock scenarios. - */ - spin_unlock(&uport->lock); - tty_flip_buffer_push(tport); - spin_lock(&uport->lock); - } return 0; } #else @@ -967,8 +1141,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); struct circ_buf *xmit = &uport->state->xmit; unsigned int xmit_size; - u32 geni_status; - bool done = 0; + unsigned int dma_dbg; + bool timeout, is_irq_masked; int ret = 0; if (msm_port->uart_ssr.is_ssr_down) { @@ -996,35 +1170,74 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) msm_port->xmit_size = xmit_size; } else { IPC_LOG_MSG(msm_port->ipc_log_misc, - "%s: TX DMA map Fail %d\n", __func__, ret); - geni_write_reg_nolog(0, uport->membase, - SE_UART_TX_TRANS_LEN); + "%s: TX DMA map Fail %d\n", __func__, ret); + + geni_write_reg_nolog(0, uport->membase, SE_UART_TX_TRANS_LEN); + msm_port->m_cmd_done = false; + msm_port->m_cmd = true; + reinit_completion(&msm_port->m_cmd_timeout); + + /* + * Try disabling the interrupts before giving the + * cancel command as this might be in an atomic context. + */ + is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); - if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_CANCEL_EN, true)) { - geni_status = geni_read_reg_nolog(uport->membase, - SE_GENI_STATUS); + + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) { + IPC_LOG_MSG(msm_port->console_log, + "%s: tx_cancel fail 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); + IPC_LOG_MSG(msm_port->ipc_log_misc, - "%s: TX Cancel Fail 0x%x\n", - __func__, geni_status); + "%s: tx_cancel failed 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); + + msm_port->m_cmd_done = false; + reinit_completion(&msm_port->m_cmd_timeout); + /* Give abort command as cancel command failed */ geni_abort_m_cmd(uport->membase); - done = msm_geni_serial_poll_bit(uport, - SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - if (!done) { - geni_status = - geni_read_reg_nolog(uport->membase, - SE_GENI_STATUS); + + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) { + IPC_LOG_MSG(msm_port->console_log, + "%s: tx abort failed 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS)); IPC_LOG_MSG(msm_port->ipc_log_misc, - "%s: TX Abort fail 0x%x\n", - __func__, geni_status); + "%s: tx abort failed 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS)); + } + } + + if (msm_port->xfer_mode == SE_DMA) { + dma_dbg = geni_read_reg(uport->membase, + SE_DMA_DEBUG_REG0); + if (dma_dbg & DMA_TX_ACTIVE) { + msm_port->m_cmd_done = false; + reinit_completion(&msm_port->m_cmd_timeout); + geni_write_reg_nolog(1, uport->membase, + SE_DMA_TX_FSM_RST); + + timeout = geni_wait_for_cmd_done(uport, + is_irq_masked); + if (timeout) + IPC_LOG_MSG(msm_port->ipc_log_misc, + "%s: tx fsm reset failed\n", __func__); + } + + if (msm_port->tx_dma) { + geni_se_tx_dma_unprep(msm_port->wrapper_dev, + msm_port->tx_dma, msm_port->xmit_size); + msm_port->tx_dma = (dma_addr_t)NULL; } - geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase, - SE_GENI_M_IRQ_CLEAR); } - geni_write_reg_nolog(M_CMD_CANCEL_EN, uport->membase, - SE_GENI_M_IRQ_CLEAR); - msm_port->tx_dma = (dma_addr_t)NULL; msm_port->xmit_size = 0; + /* Enable the interrupts once the cancel operation is done. */ + msm_geni_serial_enable_interrupts(uport); + msm_port->m_cmd = false; } return ret; } @@ -1094,38 +1307,12 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) msm_geni_serial_power_off(uport); } -static void msm_geni_serial_tx_fsm_rst(struct uart_port *uport) -{ - unsigned int tx_irq_en; - int done = 0; - int tries = 0; - struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - - if (port->uart_ssr.is_ssr_down) { - IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n", - __func__); - return; - } - - tx_irq_en = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_EN); - geni_write_reg_nolog(0, uport->membase, SE_DMA_TX_IRQ_EN_SET); - geni_write_reg_nolog(1, uport->membase, SE_DMA_TX_FSM_RST); - do { - done = msm_geni_serial_poll_bit(uport, SE_DMA_TX_IRQ_STAT, - TX_RESET_DONE, true); - tries++; - } while (!done && tries < 5); - geni_write_reg_nolog(TX_DMA_DONE | TX_RESET_DONE, uport->membase, - SE_DMA_TX_IRQ_CLR); - geni_write_reg_nolog(tx_irq_en, uport->membase, SE_DMA_TX_IRQ_EN_SET); -} - static void stop_tx_sequencer(struct uart_port *uport) { - unsigned int geni_m_irq_en; unsigned int geni_status; + bool timeout, is_irq_masked; + unsigned int dma_dbg; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - bool done = 0; if (port->uart_ssr.is_ssr_down) { IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n", @@ -1133,24 +1320,7 @@ static void stop_tx_sequencer(struct uart_port *uport) return; } - geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); - geni_m_irq_en &= ~M_CMD_DONE_EN; - if (port->xfer_mode == FIFO_MODE) { - geni_m_irq_en &= ~M_TX_FIFO_WATERMARK_EN; - geni_write_reg_nolog(0, uport->membase, - SE_GENI_TX_WATERMARK_REG); - } else if (port->xfer_mode == SE_DMA) { - if (port->tx_dma) { - msm_geni_serial_tx_fsm_rst(uport); - geni_se_tx_dma_unprep(port->wrapper_dev, port->tx_dma, - port->xmit_size); - port->tx_dma = (dma_addr_t)NULL; - } - } - port->xmit_size = 0; - geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN); - geni_status = geni_read_reg_nolog(uport->membase, - SE_GENI_STATUS); + geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop tx is called multiple times. */ if (!(geni_status & M_GENI_CMD_ACTIVE)) return; @@ -1158,28 +1328,64 @@ static void stop_tx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->ipc_log_misc, "%s: Start GENI: 0x%x\n", __func__, geni_status); + port->m_cmd_done = false; + port->m_cmd = true; + reinit_completion(&port->m_cmd_timeout); + /* + * Try to mask the interrupts before giving the + * cancel command as this might be in an atomic context + * from framework driver. + */ + is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_m_cmd(uport->membase); - if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_CANCEL_EN, true)) { - geni_status = geni_read_reg_nolog(uport->membase, - SE_GENI_STATUS); - IPC_LOG_MSG(port->ipc_log_misc, - "%s: TX Cancel Fail 0x%x\n", __func__, geni_status); + + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) { + IPC_LOG_MSG(port->console_log, "%s: tx_cancel failed 0x%x\n", + __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); + IPC_LOG_MSG(port->ipc_log_misc, "%s: tx_cancel failed 0x%x\n", + __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); + + port->m_cmd_done = false; + reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); - done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_CMD_ABORT_EN, true); - if (!done) { - geni_status = geni_read_reg_nolog(uport->membase, - SE_GENI_STATUS); + + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) { + IPC_LOG_MSG(port->console_log, + "%s: tx abort failed 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); IPC_LOG_MSG(port->ipc_log_misc, - "%s TX Abort fail 0x%x\n", - __func__, geni_status); + "%s: tx abort failed 0x%x\n", __func__, + geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); } - geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase, - SE_GENI_M_IRQ_CLEAR); } - geni_write_reg_nolog(M_CMD_CANCEL_EN, uport->membase, - SE_GENI_M_IRQ_CLEAR); + + if (port->xfer_mode == SE_DMA) { + dma_dbg = geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0); + if (dma_dbg & DMA_TX_ACTIVE) { + port->m_cmd_done = false; + reinit_completion(&port->m_cmd_timeout); + geni_write_reg_nolog(1, uport->membase, + SE_DMA_TX_FSM_RST); + + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) + IPC_LOG_MSG(port->ipc_log_misc, + "%s: tx fsm reset failed\n", __func__); + } + + if (port->tx_dma) { + geni_se_tx_dma_unprep(port->wrapper_dev, + port->tx_dma, port->xmit_size); + port->tx_dma = (dma_addr_t)NULL; + } + } + /* unmask the interrupts once the cancel operation is done. */ + msm_geni_serial_enable_interrupts(uport); + port->m_cmd = false; + port->xmit_size = 0; + /* * If we end up having to cancel an on-going Tx for non-console usecase * then it means there was some unsent data in the Tx FIFO, consequently @@ -1211,8 +1417,6 @@ static void msm_geni_serial_stop_tx(struct uart_port *uport) static void start_rx_sequencer(struct uart_port *uport) { - unsigned int geni_s_irq_en; - unsigned int geni_m_irq_en; unsigned int geni_status; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); u32 geni_se_param = UART_PARAM_RFR_OPEN; @@ -1241,29 +1445,14 @@ static void start_rx_sequencer(struct uart_port *uport) } /* Start RX with the RFR_OPEN to keep RFR in always ready state */ + msm_geni_serial_enable_interrupts(uport); geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); - if (port->xfer_mode == FIFO_MODE) { - geni_s_irq_en = geni_read_reg_nolog(uport->membase, - SE_GENI_S_IRQ_EN); - geni_m_irq_en = geni_read_reg_nolog(uport->membase, - SE_GENI_M_IRQ_EN); - - geni_s_irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; - geni_m_irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; - - geni_write_reg_nolog(geni_s_irq_en, uport->membase, - SE_GENI_S_IRQ_EN); - geni_write_reg_nolog(geni_m_irq_en, uport->membase, - SE_GENI_M_IRQ_EN); - } else if (port->xfer_mode == SE_DMA) { + if (port->xfer_mode == SE_DMA) geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &port->rx_dma); - } - /* - * Ensure the writes to the secondary sequencer and interrupt enables - * go through. - */ + + /* Ensure that the above writes go through */ mb(); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__, @@ -1283,33 +1472,6 @@ static void msm_geni_serial_start_rx(struct uart_port *uport) start_rx_sequencer(&port->uport); } - -static void msm_geni_serial_rx_fsm_rst(struct uart_port *uport) -{ - unsigned int rx_irq_en; - int done = 0; - int tries = 0; - struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - - if (port->uart_ssr.is_ssr_down) { - IPC_LOG_MSG(port->ipc_log_misc, "%s: SSR Down event set\n", - __func__); - return; - } - - rx_irq_en = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_EN); - geni_write_reg_nolog(0, uport->membase, SE_DMA_RX_IRQ_EN_SET); - geni_write_reg_nolog(1, uport->membase, SE_DMA_RX_FSM_RST); - do { - done = msm_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT, - RX_RESET_DONE, true); - tries++; - } while (!done && tries < 5); - geni_write_reg_nolog(RX_DMA_DONE | RX_RESET_DONE, uport->membase, - SE_DMA_RX_IRQ_CLR); - geni_write_reg_nolog(rx_irq_en, uport->membase, SE_DMA_RX_IRQ_EN_SET); -} - static void msm_geni_serial_set_manual_flow(bool enable, struct msm_geni_serial_port *port) { @@ -1350,12 +1512,10 @@ static void msm_geni_serial_set_manual_flow(bool enable, static void stop_rx_sequencer(struct uart_port *uport) { - unsigned int geni_s_irq_en; - unsigned int geni_m_irq_en; unsigned int geni_status; + bool timeout, is_irq_masked; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - u32 irq_clear = S_CMD_CANCEL_EN; - bool done; + unsigned long flags = 0; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); if (port->uart_ssr.is_ssr_down) { @@ -1364,57 +1524,91 @@ static void stop_rx_sequencer(struct uart_port *uport) return; } - if (port->xfer_mode == FIFO_MODE) { - geni_s_irq_en = geni_read_reg_nolog(uport->membase, - SE_GENI_S_IRQ_EN); - geni_m_irq_en = geni_read_reg_nolog(uport->membase, - SE_GENI_M_IRQ_EN); - geni_s_irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); - geni_m_irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); - - geni_write_reg_nolog(geni_s_irq_en, uport->membase, - SE_GENI_S_IRQ_EN); - geni_write_reg_nolog(geni_m_irq_en, uport->membase, - SE_GENI_M_IRQ_EN); - } geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop rx is called multiple times. */ - if (!(geni_status & S_GENI_CMD_ACTIVE)) - goto exit_rx_seq; + if (!(geni_status & S_GENI_CMD_ACTIVE)) { + IPC_LOG_MSG(port->ipc_log_misc, + "%s: RX is Inactive, geni_sts: 0x%x\n", + __func__, geni_status); + return; + } + + port->s_cmd_done = false; + port->s_cmd = true; + reinit_completion(&port->s_cmd_timeout); IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n", __func__, geni_status); + /* + * Try disabling the interrupts before giving the + * cancel command as this might be in an atomic context. + */ + is_irq_masked = msm_serial_try_disable_interrupts(uport); geni_cancel_s_cmd(uport->membase); + /* * Ensure that the cancel goes through before polling for the * cancel control bit. */ mb(); - if (!uart_console(uport)) - msm_geni_serial_complete_rx_eot(uport); + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) { + bool is_rx_active; - done = msm_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, - S_GENI_CMD_CANCEL, false); - if (done) { - geni_write_reg_nolog(irq_clear, uport->membase, - SE_GENI_S_IRQ_CLEAR); - goto exit_rx_seq; - } else { - IPC_LOG_MSG(port->ipc_log_misc, "%s Cancel fail 0x%x\n", - __func__, geni_status); - } + geni_status = geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS); + /* + * Possible that stop_rx is called from system resume context + * for console usecase. In early resume, irq remains disabled + * in the system. call msm_geni_serial_isr to clear + * the interrupts. + */ + is_rx_active = geni_status & S_GENI_CMD_ACTIVE; + IPC_LOG_MSG(port->ipc_log_misc, + "%s cancel failed is_rx_active: %d 0x%x\n", + __func__, is_rx_active, geni_status); + IPC_LOG_MSG(port->console_log, + "%s cancel failed is_rx_active:%d 0x%x\n", + __func__, is_rx_active, geni_status); + if (uart_console(uport) && !is_rx_active) { + msm_geni_serial_handle_isr(uport, &flags, true); + goto exit_rx_seq; + } + port->s_cmd_done = false; + reinit_completion(&port->s_cmd_timeout); + geni_abort_s_cmd(uport->membase); + /* Ensure this goes through before polling. */ + mb(); - geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - if ((geni_status & S_GENI_CMD_ACTIVE)) { - IPC_LOG_MSG(port->ipc_log_misc, "%s:Abort Rx, GENI:0x%x\n", - __func__, geni_status); - msm_geni_serial_abort_rx(uport); + timeout = geni_wait_for_cmd_done(uport, is_irq_masked); + if (timeout) { + geni_status = geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS); + IPC_LOG_MSG(port->ipc_log_misc, + "%s abort fail 0x%x\n", __func__, geni_status); + IPC_LOG_MSG(port->console_log, + "%s abort fail 0x%x\n", __func__, geni_status); + } + + if (port->xfer_mode == SE_DMA) { + port->s_cmd_done = false; + reinit_completion(&port->s_cmd_timeout); + geni_write_reg_nolog(1, uport->membase, + SE_DMA_RX_FSM_RST); + + timeout = geni_wait_for_cmd_done(uport, + is_irq_masked); + if (timeout) + IPC_LOG_MSG(port->ipc_log_misc, + "%s: rx fsm reset failed\n", __func__); + } } -exit_rx_seq: - if (port->xfer_mode == SE_DMA && port->rx_dma) - msm_geni_serial_rx_fsm_rst(uport); + /* Enable the interrupts once the cancel operation is done. */ + msm_geni_serial_enable_interrupts(uport); + port->s_cmd = false; +exit_rx_seq: geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: End 0x%x\n", __func__, geni_status); @@ -1486,8 +1680,8 @@ static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) RX_LAST_BYTE_VALID_SHFT); rx_last = rx_fifo_status & RX_LAST; if (rx_fifo_wc) - port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid, - rx_last, drop_rx); + ret = port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid, + rx_last, drop_rx); return ret; } @@ -1658,8 +1852,6 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) dump_ipc(msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0, rx_bytes); exit_handle_dma_rx: - geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, - &msm_port->rx_dma); if (msm_port->uart_ssr.is_ssr_down) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n", __func__); @@ -1703,19 +1895,22 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport) return 0; } -static irqreturn_t msm_geni_serial_isr(int isr, void *dev) +static void msm_geni_serial_handle_isr(struct uart_port *uport, + unsigned long *flags, + bool is_irq_masked) { unsigned int m_irq_status; unsigned int s_irq_status; unsigned int dma; unsigned int dma_tx_status; unsigned int dma_rx_status; - struct uart_port *uport = dev; unsigned int m_irq_en; unsigned int geni_status; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); struct tty_port *tport = &uport->state->port; bool drop_rx = false; + bool s_cmd_done = false; + bool m_cmd_done = false; if (msm_port->uart_ssr.is_ssr_down) { m_irq_status = geni_read_reg_nolog(uport->membase, @@ -1738,21 +1933,15 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) SE_DMA_RX_IRQ_CLR); IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.SSR Down event set\n", __func__); - return IRQ_HANDLED; + return; } - spin_lock(&uport->lock); if (uart_console(uport) && uport->suspended) { IPC_LOG_MSG(msm_port->console_log, "%s. Console in suspend state\n", __func__); goto exit_geni_serial_isr; } - if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) { - dev_err(uport->dev, "%s.Device is suspended.\n", __func__); - IPC_LOG_MSG(msm_port->ipc_log_misc, - "%s.Device is suspended.\n", __func__); - goto exit_geni_serial_isr; - } + m_irq_status = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_STATUS); s_irq_status = geni_read_reg_nolog(uport->membase, @@ -1760,16 +1949,13 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) if (uart_console(uport)) IPC_LOG_MSG(msm_port->console_log, "%s. sirq 0x%x mirq:0x%x\n", __func__, s_irq_status, - m_irq_status); - m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); - dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN); - dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT); - dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); - geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); - - geni_write_reg_nolog(m_irq_status, uport->membase, SE_GENI_M_IRQ_CLEAR); - geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); + m_irq_status); + geni_write_reg_nolog(m_irq_status, uport->membase, + SE_GENI_M_IRQ_CLEAR); + geni_write_reg_nolog(s_irq_status, uport->membase, + SE_GENI_S_IRQ_CLEAR); + m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); if ((m_irq_status & M_ILLEGAL_CMD_EN)) { WARN_ON(1); goto exit_geni_serial_isr; @@ -1783,49 +1969,93 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) __func__, s_irq_status, uport->icount.buf_overrun); } + dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN); if (!dma) { + geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); + if ((m_irq_status & m_irq_en) & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) msm_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN, geni_status & M_GENI_CMD_ACTIVE); - if ((s_irq_status & S_GP_IRQ_0_EN) || - (s_irq_status & S_GP_IRQ_1_EN)) { + if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) + m_cmd_done = true; + + if (s_irq_status & (S_GP_IRQ_0_EN | S_GP_IRQ_1_EN)) { if (s_irq_status & S_GP_IRQ_0_EN) uport->icount.parity++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.sirq 0x%x parity:%d\n", __func__, s_irq_status, uport->icount.parity); drop_rx = true; - } else if ((s_irq_status & S_GP_IRQ_2_EN) || - (s_irq_status & S_GP_IRQ_3_EN)) { + } else if (s_irq_status & (S_GP_IRQ_2_EN | S_GP_IRQ_3_EN)) { uport->icount.brk++; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.sirq 0x%x break:%d\n", __func__, s_irq_status, uport->icount.brk); } + /* + * In case of stop_rx handling there is a chance + * for RX data can come in parallel. set drop_rx to + * avoid data push to framework from handle_rx_console() + * API for stop_rx case. + */ - if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) || - (s_irq_status & S_RX_FIFO_LAST_EN)) + if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) { + s_cmd_done = true; + drop_rx = true; + } + + if (s_irq_status & (S_RX_FIFO_WATERMARK_EN | + S_RX_FIFO_LAST_EN)) { msm_geni_serial_handle_rx(uport, drop_rx); + if (!drop_rx && !is_irq_masked) { + spin_unlock_irqrestore(&uport->lock, *flags); + tty_flip_buffer_push(tport); + spin_lock_irqsave(&uport->lock, *flags); + } else if (!drop_rx) { + tty_flip_buffer_push(tport); + } + } } else { + dma_tx_status = geni_read_reg_nolog(uport->membase, + SE_DMA_TX_IRQ_STAT); + dma_rx_status = geni_read_reg_nolog(uport->membase, + SE_DMA_RX_IRQ_STAT); + if (dma_tx_status) { + geni_write_reg_nolog(dma_tx_status, uport->membase, - SE_DMA_TX_IRQ_CLR); - if (dma_tx_status & TX_DMA_DONE) + SE_DMA_TX_IRQ_CLR); + + + if (((msm_port->ver_info.hw_major_ver <= 1) && + (msm_port->ver_info.hw_minor_ver <= 2)) && + (dma_tx_status & TX_RESET_DONE)) { + m_cmd_done = true; + } else if (dma_tx_status & (TX_RESET_DONE | + TX_GENI_CANCEL_IRQ)) { + m_cmd_done = true; + } + if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) + m_cmd_done = true; + + if ((dma_tx_status & TX_DMA_DONE) && !m_cmd_done) msm_geni_serial_handle_dma_tx(uport); } if (dma_rx_status) { geni_write_reg_nolog(dma_rx_status, uport->membase, - SE_DMA_RX_IRQ_CLR); + SE_DMA_RX_IRQ_CLR); + if (dma_rx_status & RX_RESET_DONE) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); goto exit_geni_serial_isr; } + if (dma_rx_status & UART_DMA_RX_ERRS) { if (dma_rx_status & UART_DMA_RX_PARITY_ERR) uport->icount.parity++; @@ -1841,13 +2071,55 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) __func__, dma_rx_status, uport->icount.brk); } - if (dma_rx_status & RX_DMA_DONE) - msm_geni_serial_handle_dma_rx(uport, drop_rx); + + if (dma_rx_status & RX_EOT || + dma_rx_status & RX_DMA_DONE) { + msm_geni_serial_handle_dma_rx(uport, + drop_rx); + if (!(dma_rx_status & + RX_GENI_CANCEL_IRQ(msm_port->ver_info))) { + geni_se_rx_dma_start(uport->membase, + DMA_RX_BUF_SIZE, &msm_port->rx_dma); + } + } + + if (dma_rx_status & RX_SBE) { + IPC_LOG_MSG(msm_port->ipc_log_misc, + "%s.Rx Errors. 0x%x\n", + __func__, dma_rx_status); + WARN_ON(1); + } + + if (dma_rx_status & (RX_EOT | + RX_GENI_CANCEL_IRQ(msm_port->ver_info) | + RX_DMA_DONE)) + s_cmd_done = true; + + if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) + s_cmd_done = true; } } exit_geni_serial_isr: - spin_unlock(&uport->lock); + if (m_cmd_done) { + msm_port->m_cmd_done = true; + complete(&msm_port->m_cmd_timeout); + } + + if (s_cmd_done) { + msm_port->s_cmd_done = true; + complete(&msm_port->s_cmd_timeout); + } +} + +static irqreturn_t msm_geni_serial_isr(int isr, void *dev) +{ + struct uart_port *uport = dev; + unsigned long flags; + + spin_lock_irqsave(&uport->lock, flags); + msm_geni_serial_handle_isr(uport, &flags, false); + spin_unlock_irqrestore(&uport->lock, flags); return IRQ_HANDLED; } @@ -1928,22 +2200,18 @@ static void set_rfr_wm(struct msm_geni_serial_port *port) static void msm_geni_serial_shutdown(struct uart_port *uport) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); - unsigned long flags; int ret; IPC_LOG_MSG(msm_port->ipc_log_misc, "%s:\n", __func__); - if (!uart_console(uport)) { + if (uart_console(uport)) { + console_stop(uport->cons); + disable_irq(uport->irq); + } else { msm_geni_serial_power_on(uport); wait_for_transfers_inflight(uport); + msm_geni_serial_stop_tx(uport); } - disable_irq(uport->irq); - free_irq(uport->irq, uport); - spin_lock_irqsave(&uport->lock, flags); - msm_geni_serial_stop_tx(uport); - msm_geni_serial_stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); - if (!uart_console(uport)) { if (msm_port->ioctl_count) { int i; @@ -2008,6 +2276,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) msm_port->rx_buf = geni_se_iommu_alloc_buf(msm_port->wrapper_dev, &dma_address, DMA_RX_BUF_SIZE); + if (!msm_port->rx_buf) { devm_kfree(uport->dev, msm_port->rx_fifo); msm_port->rx_fifo = NULL; @@ -2021,7 +2290,9 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) * it else we could end up in data loss scenarios. */ msm_port->xfer_mode = FIFO_MODE; - msm_geni_serial_poll_cancel_tx(uport); + msm_serial_try_disable_interrupts(uport); + msm_geni_serial_poll_tx_done(uport); + msm_geni_serial_enable_interrupts(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0); @@ -2033,6 +2304,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_RX_PACKING_CFG1); } + ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr); if (ret) { dev_err(uport->dev, "%s: Fail\n", __func__); @@ -2067,8 +2339,6 @@ static int msm_geni_serial_startup(struct uart_port *uport) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); IPC_LOG_MSG(msm_port->ipc_log_misc, "%s:\n", __func__); - scnprintf(msm_port->name, sizeof(msm_port->name), "msm_serial_geni%d", - uport->line); msm_port->startup_in_progress = true; @@ -2097,13 +2367,16 @@ static int msm_geni_serial_startup(struct uart_port *uport) * before returning to the framework. */ mb(); - ret = request_irq(uport->irq, msm_geni_serial_isr, IRQF_TRIGGER_HIGH, - msm_port->name, uport); - if (unlikely(ret)) { - dev_err(uport->dev, "%s: Failed to get IRQ ret %d\n", - __func__, ret); - goto exit_startup; - } + + /* Console usecase requires irq to be in enable state after early + * console switch from probe to handle RX data. Hence enable IRQ + * from startup and disable it from shutdown APIs for console case. + * BT HSUART usecase, IRQ will be enabled from runtime resume() + * and disabled in runtime_suspend to avoid spurious interrupts + * after suspend. + */ + if (uart_console(uport)) + enable_irq(uport->irq); if (msm_port->wakeup_irq > 0) { ret = request_irq(msm_port->wakeup_irq, msm_geni_wakeup_isr, @@ -2215,8 +2488,15 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, unsigned long ser_clk_cfg = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned long clk_rate; - unsigned long flags; + unsigned long desired_rate; + int uart_sampling; + /* QUP_2.5.0 and older RUMI has sampling rate as 32 */ + if (port->rumi_platform && port->is_console) { + geni_write_reg_nolog(0x21, uport->membase, GENI_SER_M_CLK_CFG); + geni_write_reg_nolog(0x21, uport->membase, GENI_SER_S_CLK_CFG); + geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG); + } if (!uart_console(uport)) { int ret = msm_geni_serial_power_on(uport); @@ -2226,16 +2506,15 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, __func__, ret); return; } - disable_irq(uport->irq); msm_geni_serial_set_manual_flow(false, port); } - /* Take a spinlock else stop_rx causes a race with an ISR due to Cancel - * and FSM_RESET. This also has a potential race with the dma_map/unmap - * operations of ISR. - */ - spin_lock_irqsave(&uport->lock, flags); msm_geni_serial_stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); + /* baud rate */ + baud = uart_get_baud_rate(uport, termios, old, 300, 4000000); + port->cur_baud = baud; + uart_sampling = IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING) ? + UART_OVERSAMPLING / 2 : UART_OVERSAMPLING; + desired_rate = baud * uart_sampling; mutex_lock(&port->uart_ssr.ssr_lock); if (port->uart_ssr.is_ssr_down) { @@ -2345,10 +2624,9 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, IPC_LOG_MSG(port->ipc_log_misc, "BitsChar%d stop bit%d\n", bits_per_char, stop_bit_len); exit_set_termios: - if (!uart_console(uport)) { + if (!uart_console(uport)) msm_geni_serial_set_manual_flow(true, port); - enable_irq(uport->irq); - } + msm_geni_serial_start_rx(uport); if (!uart_console(uport)) msm_geni_serial_power_off(uport); @@ -2418,9 +2696,9 @@ static ssize_t msm_geni_serial_xfer_mode_store(struct device *dev, return size; msm_geni_serial_power_on(uport); - spin_lock_irqsave(&uport->lock, flags); msm_geni_serial_stop_tx(uport); msm_geni_serial_stop_rx(uport); + spin_lock_irqsave(&uport->lock, flags); port->xfer_mode = xfer_mode; geni_se_select_mode(uport->membase, port->xfer_mode); spin_unlock_irqrestore(&uport->lock, flags); @@ -2504,6 +2782,45 @@ msm_geni_serial_early_console_write(struct console *con, const char *s, __msm_geni_serial_console_write(&dev->port, s, n); } +static void msm_geni_serial_cancel_rx(struct uart_port *uport) +{ + int done = 0; + int i = 0; + unsigned int irq_status; + u32 rx_fifo_status; + u32 rx_fifo_wc; + + geni_cancel_s_cmd(uport->membase); + /* Ensure this goes through before polling. */ + mb(); + + done = msm_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS, + S_CMD_CANCEL_EN, true); + if (!done) { + geni_abort_s_cmd(uport->membase); + /* Ensure this goes through before polling. */ + mb(); + msm_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS, + S_CMD_ABORT_EN, false); + } else if (msm_geni_serial_poll_bit(uport, + SE_GENI_S_IRQ_STATUS, S_RX_FIFO_LAST_EN, true)) { + rx_fifo_status = geni_read_reg_nolog(uport->membase, + SE_GENI_RX_FIFO_STATUS); + rx_fifo_wc = rx_fifo_status & RX_FIFO_WC_MSK; + for (i = 0; i < rx_fifo_wc; i++) + geni_read_reg_nolog(uport->membase, + SE_GENI_RX_FIFOn); + } + + irq_status = geni_read_reg_nolog(uport->membase, + SE_GENI_S_IRQ_STATUS); + geni_write_reg_nolog(irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); + + if (!done) + geni_write_reg(FORCE_DEFAULT, uport->membase, + GENI_FORCE_DEFAULT_REG); +} + static int __init msm_geni_serial_earlycon_setup(struct earlycon_device *dev, const char *opt) @@ -2562,10 +2879,25 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, s_clk_cfg |= (clk_div << CLK_DIV_SHFT); /* - * Make an unconditional cancel on the main sequencer to reset - * it else we could end up in data loss scenarios. + * Here we need to poll for command done which indicates that + * the previous tx transfer is done. And if the command done interrupt + * is not getting set, then we need to cancel the command. + */ + msm_geni_serial_poll_tx_done(uport); + + /* + * Here cancel rx is done in polling mode as there is + * no isr support during early console time. */ - msm_geni_serial_poll_cancel_tx(uport); + msm_geni_serial_cancel_rx(uport); + + /* Only for earlyconsole */ + if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) { + geni_write_reg_nolog(0x21, uport->membase, GENI_SER_M_CLK_CFG); + geni_write_reg_nolog(0x21, uport->membase, GENI_SER_S_CLK_CFG); + geni_read_reg_nolog(uport->membase, GENI_SER_M_CLK_CFG); + } + se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), (DEF_FIFO_DEPTH_WORDS - 2)); @@ -2576,8 +2908,14 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, SE_UART_TX_TRANS_CFG); geni_write_reg_nolog(tx_parity_cfg, uport->membase, SE_UART_TX_PARITY_CFG); + geni_write_reg_nolog(rx_trans_cfg, uport->membase, + SE_UART_RX_TRANS_CFG); + geni_write_reg_nolog(rx_parity_cfg, uport->membase, + SE_UART_RX_PARITY_CFG); geni_write_reg_nolog(bits_per_char, uport->membase, SE_UART_TX_WORD_LEN); + geni_write_reg_nolog(bits_per_char, uport->membase, + SE_UART_RX_WORD_LEN); geni_write_reg_nolog(stop_bit, uport->membase, SE_UART_TX_STOP_BIT_LEN); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG); @@ -2809,6 +3147,8 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport) __func__, msm_port->ver_info.hw_major_ver, msm_port->ver_info.hw_minor_ver, msm_port->ver_info.hw_step_ver); + + msm_geni_serial_enable_interrupts(uport); exit_ver_info: se_geni_clks_off(&msm_port->serial_rsc); return ret; @@ -3011,6 +3351,9 @@ static int msm_geni_serial_probe(struct platform_device *pdev) dev_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS; uport->fifosize = ((dev_port->tx_fifo_depth * dev_port->tx_fifo_width) >> 3); + /* Complete signals to handle cancel cmd completion */ + init_completion(&dev_port->m_cmd_timeout); + init_completion(&dev_port->s_cmd_timeout); uport->irq = platform_get_irq(pdev, 0); if (uport->irq < 0) { @@ -3019,6 +3362,17 @@ static int msm_geni_serial_probe(struct platform_device *pdev) goto exit_geni_serial_probe; } + dev_port->name = devm_kasprintf(uport->dev, GFP_KERNEL, + "msm_serial_geni%d", uport->line); + irq_set_status_flags(uport->irq, IRQ_NOAUTOEN); + ret = devm_request_irq(uport->dev, uport->irq, msm_geni_serial_isr, + IRQF_TRIGGER_HIGH, dev_port->name, uport); + if (ret) { + dev_err(uport->dev, "%s: Failed to get IRQ ret %d\n", + __func__, ret); + goto exit_geni_serial_probe; + } + uport->private_data = (void *)drv; platform_set_drvdata(pdev, dev_port); /* @@ -3119,16 +3473,17 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) wait_for_transfers_inflight(&port->uport); /* - * Disable Interrupt * Manual RFR On. * Stop Rx. + * Disable Interrupt * Resources off */ - disable_irq(port->uport.irq); stop_rx_sequencer(&port->uport); geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS); if ((geni_status & M_GENI_CMD_ACTIVE)) stop_tx_sequencer(&port->uport); + + disable_irq(port->uport.irq); ret = se_geni_resources_off(&port->serial_rsc); if (ret) { dev_err(dev, "%s: Error ret %d\n", __func__, ret); @@ -3173,8 +3528,8 @@ static int msm_geni_serial_runtime_resume(struct device *dev) start_rx_sequencer(&port->uport); /* Ensure that the Rx is running before enabling interrupts */ mb(); - if (pm_runtime_enabled(dev)) - enable_irq(port->uport.irq); + /* Enable interrupt */ + enable_irq(port->uport.irq); IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); exit_runtime_resume: return ret; @@ -3186,7 +3541,7 @@ static int msm_geni_serial_sys_suspend_noirq(struct device *dev) struct msm_geni_serial_port *port = platform_get_drvdata(pdev); struct uart_port *uport = &port->uport; - if (uart_console(uport) || !pm_runtime_enabled(uport->dev)) { + if (uart_console(uport) || port->pm_auto_suspend_disable) { uart_suspend_port((struct uart_driver *)uport->private_data, uport); } else { @@ -3217,10 +3572,9 @@ static int msm_geni_serial_sys_resume_noirq(struct device *dev) if ((uart_console(uport) && console_suspend_enabled && uport->suspended) || - !pm_runtime_enabled(uport->dev)) { + port->pm_auto_suspend_disable) { uart_resume_port((struct uart_driver *)uport->private_data, uport); - disable_irq(uport->irq); } return 0; } diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 401c983ec5f3651bc442b315566fc4dfc63ed627..a10e4aa9e18eaffb59e1df06ec47a4ff7865b867 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -581,7 +581,7 @@ static int mvebu_uart_probe(struct platform_device *pdev) port->membase = devm_ioremap_resource(&pdev->dev, reg); if (IS_ERR(port->membase)) - return -PTR_ERR(port->membase); + return PTR_ERR(port->membase); data = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart_data), GFP_KERNEL); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 333de7d3fe8668566a76dd833dad7440fa9d5e44..06cf474072d6dfe73c9c3c0e0386a09cd184836e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -841,9 +841,16 @@ static void sci_receive_chars(struct uart_port *port) tty_insert_flip_char(tport, c, TTY_NORMAL); } else { for (i = 0; i < count; i++) { - char c = serial_port_in(port, SCxRDR); - - status = serial_port_in(port, SCxSR); + char c; + + if (port->type == PORT_SCIF || + port->type == PORT_HSCIF) { + status = serial_port_in(port, SCxSR); + c = serial_port_in(port, SCxRDR); + } else { + c = serial_port_in(port, SCxRDR); + status = serial_port_in(port, SCxSR); + } if (uart_handle_sysrq_char(port, c)) { count--; i--; continue; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 0dbfd02e3b196b0317c150739e138b92e9a8bd96..81657f09761cd764dfe8faa1d7552a54aac6a5bf 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -31,6 +31,7 @@ #include #include #include +#include #define CDNS_UART_TTY_NAME "ttyPS" #define CDNS_UART_NAME "xuartps" @@ -39,6 +40,7 @@ #define CDNS_UART_NR_PORTS 2 #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ #define CDNS_UART_REGISTER_SPACE 0x1000 +#define TX_TIMEOUT 500000 /* Rx Trigger level */ static int rx_trigger_level = 56; @@ -685,18 +687,21 @@ static void cdns_uart_set_termios(struct uart_port *port, unsigned int cval = 0; unsigned int baud, minbaud, maxbaud; unsigned long flags; - unsigned int ctrl_reg, mode_reg; - - spin_lock_irqsave(&port->lock, flags); + unsigned int ctrl_reg, mode_reg, val; + int err; /* Wait for the transmit FIFO to empty before making changes */ if (!(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_TX_DIS)) { - while (!(readl(port->membase + CDNS_UART_SR) & - CDNS_UART_SR_TXEMPTY)) { - cpu_relax(); + err = readl_poll_timeout(port->membase + CDNS_UART_SR, + val, (val & CDNS_UART_SR_TXEMPTY), + 1000, TX_TIMEOUT); + if (err) { + dev_err(port->dev, "timed out waiting for tx empty"); + return; } } + spin_lock_irqsave(&port->lock, flags); /* Disable the TX and RX to set baud rate */ ctrl_reg = readl(port->membase + CDNS_UART_CR); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 344e8c427c7e2c606e2df2d7bde4615bf512951c..9d68f89a2bf8dac451c452445c70f513ec7645c2 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1349,10 +1349,10 @@ static void throttle(struct tty_struct * tty) DBGINFO(("%s throttle\n", info->device_name)); if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (C_CRTSCTS(tty)) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->signals &= ~SerialSignal_RTS; - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } } @@ -1374,10 +1374,10 @@ static void unthrottle(struct tty_struct * tty) else send_xchar(tty, START_CHAR(tty)); } - if (C_CRTSCTS(tty)) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->signals |= SerialSignal_RTS; - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } } @@ -2575,8 +2575,8 @@ static void change_params(struct slgt_info *info) info->read_status_mask = IRQ_RXOVER; if (I_INPCK(info->port.tty)) info->read_status_mask |= MASK_PARITY | MASK_FRAMING; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask |= MASK_BREAK; + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) + info->read_status_mask |= MASK_BREAK; if (I_IGNPAR(info->port.tty)) info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING; if (I_IGNBRK(info->port.tty)) { @@ -3207,7 +3207,7 @@ static int tiocmset(struct tty_struct *tty, info->signals &= ~SerialSignal_DTR; spin_lock_irqsave(&info->lock,flags); - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); return 0; } @@ -3218,7 +3218,7 @@ static int carrier_raised(struct tty_port *port) struct slgt_info *info = container_of(port, struct slgt_info, port); spin_lock_irqsave(&info->lock,flags); - get_signals(info); + get_signals(info); spin_unlock_irqrestore(&info->lock,flags); return (info->signals & SerialSignal_DCD) ? 1 : 0; } @@ -3233,7 +3233,7 @@ static void dtr_rts(struct tty_port *port, int on) info->signals |= SerialSignal_RTS | SerialSignal_DTR; else info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 4fed9e7b281f0c5faad059783205b190be8b15d6..3c9e314406b4efe8c91d630b9dadbbef79abf378 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1467,10 +1467,10 @@ static void throttle(struct tty_struct * tty) if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (C_CRTSCTS(tty)) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } } @@ -1496,10 +1496,10 @@ static void unthrottle(struct tty_struct * tty) send_xchar(tty, START_CHAR(tty)); } - if (C_CRTSCTS(tty)) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } } @@ -2484,7 +2484,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) if (status & SerialSignal_CTS) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx start..."); - info->port.tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; tx_start(info); info->pending_bh |= BH_TRANSMIT; return; @@ -2493,7 +2493,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) if (!(status & SerialSignal_CTS)) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx stop..."); - info->port.tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; tx_stop(info); } } @@ -2820,8 +2820,8 @@ static void change_params(SLMP_INFO *info) info->read_status_mask2 = OVRN; if (I_INPCK(info->port.tty)) info->read_status_mask2 |= PE | FRME; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask1 |= BRKD; + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) + info->read_status_mask1 |= BRKD; if (I_IGNPAR(info->port.tty)) info->ignore_status_mask2 |= PE | FRME; if (I_IGNBRK(info->port.tty)) { @@ -3191,7 +3191,7 @@ static int tiocmget(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->lock,flags); - get_signals(info); + get_signals(info); spin_unlock_irqrestore(&info->lock,flags); result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS : 0) | @@ -3229,7 +3229,7 @@ static int tiocmset(struct tty_struct *tty, info->serial_signals &= ~SerialSignal_DTR; spin_lock_irqsave(&info->lock,flags); - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); return 0; @@ -3241,7 +3241,7 @@ static int carrier_raised(struct tty_port *port) unsigned long flags; spin_lock_irqsave(&info->lock,flags); - get_signals(info); + get_signals(info); spin_unlock_irqrestore(&info->lock,flags); return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; @@ -3257,7 +3257,7 @@ static void dtr_rts(struct tty_port *port, int on) info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; else info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); + set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 4e6a3713fae0dc68375afbfc9425ef1e6d9accba..ba64768f5764b3c50affce7d16286ca3918f3041 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -135,17 +135,10 @@ static struct sysrq_key_op sysrq_unraw_op = { static void sysrq_handle_crash(int key) { - char *killer = NULL; - - /* we need to release the RCU read lock here, - * otherwise we get an annoying - * 'BUG: sleeping function called from invalid context' - * complaint from the kernel before the panic. - */ + /* release the RCU read lock before crashing */ rcu_read_unlock(); - panic_on_oops = 1; /* force panic */ - wmb(); - *killer = 1; + + panic("sysrq triggered crash\n"); } static struct sysrq_key_op sysrq_crash_op = { .handler = sysrq_handle_crash, @@ -547,7 +540,6 @@ void __handle_sysrq(int key, bool check_mask) */ orig_log_level = console_loglevel; console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; - pr_info("SysRq : "); op_p = __sysrq_get_key_op(key); if (op_p) { @@ -556,14 +548,15 @@ void __handle_sysrq(int key, bool check_mask) * should not) and is the invoked operation enabled? */ if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { - pr_cont("%s\n", op_p->action_msg); + pr_info("%s\n", op_p->action_msg); console_loglevel = orig_log_level; op_p->handler(key); } else { - pr_cont("This sysrq operation is disabled.\n"); + pr_info("This sysrq operation is disabled.\n"); + console_loglevel = orig_log_level; } } else { - pr_cont("HELP : "); + pr_info("HELP : "); /* Only print the help msg once per handler */ for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { if (sysrq_key_table[i]) { diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index c93a33701d32acfd5fc36029702dc2139d985b96..dd12c3b86eb461427b700928aa285fcce7d13e66 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -51,10 +51,11 @@ static void tty_port_default_wakeup(struct tty_port *port) } } -static const struct tty_port_client_operations default_client_ops = { +const struct tty_port_client_operations tty_port_default_client_ops = { .receive_buf = tty_port_default_receive_buf, .write_wakeup = tty_port_default_wakeup, }; +EXPORT_SYMBOL_GPL(tty_port_default_client_ops); void tty_port_init(struct tty_port *port) { @@ -67,7 +68,7 @@ void tty_port_init(struct tty_port *port) spin_lock_init(&port->lock); port->close_delay = (50 * HZ) / 100; port->closing_wait = (3000 * HZ) / 100; - port->client_ops = &default_client_ops; + port->client_ops = &tty_port_default_client_ops; kref_init(&port->kref); } EXPORT_SYMBOL(tty_port_init); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 7a4c8022c02375828608e5fc7ac9e8b58e6dc80e..8687b17f6cf0245b83b8dd762312b6afadd11cf5 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,8 @@ #include #include +#include + /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') @@ -41,6 +44,7 @@ static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; static char *sel_buffer; +static DEFINE_MUTEX(sel_lock); /* clear_selection, highlight and highlight_pointer can be called from interrupt (via scrollback/front) */ @@ -79,6 +83,11 @@ void clear_selection(void) } } +bool vc_is_sel(struct vc_data *vc) +{ + return vc == sel_cons; +} + /* * User settable table: what characters are to be considered alphabetic? * 128 bits. Locked by the console lock. @@ -153,14 +162,14 @@ static int store_utf8(u16 c, char *p) * The entire selection process is managed under the console_lock. It's * a lot under the lock but its hardly a performance path */ -int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) +static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe, multiplier; u16 c; - int mode; + int mode, ret = 0; poke_blanked_console(); @@ -321,7 +330,21 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t } } sel_buffer_lth = bp - sel_buffer; - return 0; + + return ret; +} + +int set_selection(const struct tiocl_selection __user *v, struct tty_struct *tty) +{ + int ret; + + mutex_lock(&sel_lock); + console_lock(); + ret = __set_selection(v, tty); + console_unlock(); + mutex_unlock(&sel_lock); + + return ret; } /* Insert the contents of the selection buffer into the @@ -338,6 +361,7 @@ int paste_selection(struct tty_struct *tty) unsigned int count; struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); + int ret = 0; console_lock(); poke_blanked_console(); @@ -349,10 +373,17 @@ int paste_selection(struct tty_struct *tty) tty_buffer_lock_exclusive(&vc->port); add_wait_queue(&vc->paste_wait, &wait); + mutex_lock(&sel_lock); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + ret = -EINTR; + break; + } if (tty_throttled(tty)) { + mutex_unlock(&sel_lock); schedule(); + mutex_lock(&sel_lock); continue; } __set_current_state(TASK_RUNNING); @@ -361,10 +392,11 @@ int paste_selection(struct tty_struct *tty) count); pasted += count; } + mutex_unlock(&sel_lock); remove_wait_queue(&vc->paste_wait, &wait); __set_current_state(TASK_RUNNING); tty_buffer_unlock_exclusive(&vc->port); tty_ldisc_deref(ld); - return 0; + return ret; } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 06761fcedeff4595b19b75204c280ce947188f10..8a4e7879a7a6e73015264538c0bb1ac4066be99a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -584,8 +584,9 @@ static void hide_softcursor(struct vc_data *vc) static void hide_cursor(struct vc_data *vc) { - if (vc == sel_cons) + if (vc_is_sel(vc)) clear_selection(); + vc->vc_sw->con_cursor(vc, CM_ERASE); hide_softcursor(vc); } @@ -595,7 +596,7 @@ static void set_cursor(struct vc_data *vc) if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS) return; if (vc->vc_deccm) { - if (vc == sel_cons) + if (vc_is_sel(vc)) clear_selection(); add_softcursor(vc); if ((vc->vc_cursor_type & 0x0f) != 1) @@ -750,6 +751,17 @@ static void visual_init(struct vc_data *vc, int num, int init) vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; } +static void vc_port_destruct(struct tty_port *port) +{ + struct vc_data *vc = container_of(port, struct vc_data, port); + + kfree(vc); +} + +static const struct tty_port_operations vc_port_ops = { + .destruct = vc_port_destruct, +}; + int vc_allocate(unsigned int currcons) /* return 0 on success */ { struct vt_notifier_param param; @@ -775,6 +787,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ vc_cons[currcons].d = vc; tty_port_init(&vc->port); + vc->port.ops = &vc_port_ops; INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); @@ -867,13 +880,13 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) return 0; - if (new_screen_size > (4 << 20)) + if (new_screen_size > KMALLOC_MAX_SIZE) return -EINVAL; newscreen = kzalloc(new_screen_size, GFP_USER); if (!newscreen) return -ENOMEM; - if (vc == sel_cons) + if (vc_is_sel(vc)) clear_selection(); old_rows = vc->vc_rows; @@ -2688,9 +2701,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) switch (type) { case TIOCL_SETSEL: - console_lock(); ret = set_selection((struct tiocl_selection __user *)(p+1), tty); - console_unlock(); break; case TIOCL_PASTESEL: ret = paste_selection(tty); @@ -2896,6 +2907,7 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty) tty->driver_data = vc; vc->port.tty = tty; + tty_port_get(&vc->port); if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; @@ -2931,6 +2943,13 @@ static void con_shutdown(struct tty_struct *tty) console_unlock(); } +static void con_cleanup(struct tty_struct *tty) +{ + struct vc_data *vc = tty->driver_data; + + tty_port_put(&vc->port); +} + static int default_color = 7; /* white */ static int default_italic_color = 2; // green (ASCII) static int default_underline_color = 3; // cyan (ASCII) @@ -3055,7 +3074,8 @@ static const struct tty_operations con_ops = { .throttle = con_throttle, .unthrottle = con_unthrottle, .resize = vt_resize, - .shutdown = con_shutdown + .shutdown = con_shutdown, + .cleanup = con_cleanup, }; static struct cdev vc0_cdev; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 7b34b0ddbf0e0281ec8ca723fb6469b5ac43d30f..699ad55e3ec60f128d3d0cefaa5de204980e4a32 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -39,11 +39,32 @@ #include #include -char vt_dont_switch; -extern struct tty_driver *console_driver; +bool vt_dont_switch; -#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) +static inline bool vt_in_use(unsigned int i) +{ + const struct vc_data *vc = vc_cons[i].d; + + /* + * console_lock must be held to prevent the vc from being deallocated + * while we're checking whether it's in-use. + */ + WARN_CONSOLE_UNLOCKED(); + + return vc && kref_read(&vc->port.kref) > 1; +} + +static inline bool vt_busy(int i) +{ + if (vt_in_use(i)) + return true; + if (i == fg_console) + return true; + if (vc_is_sel(vc_cons[i].d)) + return true; + + return false; +} /* * Console (vt and kd) routines, as defined by USL SVR4 manual, and by @@ -289,16 +310,14 @@ static int vt_disallocate(unsigned int vc_num) int ret = 0; console_lock(); - if (VT_BUSY(vc_num)) + if (vt_busy(vc_num)) ret = -EBUSY; else if (vc_num) vc = vc_deallocate(vc_num); console_unlock(); - if (vc && vc_num >= MIN_NR_CONSOLES) { - tty_port_destroy(&vc->port); - kfree(vc); - } + if (vc && vc_num >= MIN_NR_CONSOLES) + tty_port_put(&vc->port); return ret; } @@ -311,17 +330,15 @@ static void vt_disallocate_all(void) console_lock(); for (i = 1; i < MAX_NR_CONSOLES; i++) - if (!VT_BUSY(i)) + if (!vt_busy(i)) vc[i] = vc_deallocate(i); else vc[i] = NULL; console_unlock(); for (i = 1; i < MAX_NR_CONSOLES; i++) { - if (vc[i] && i >= MIN_NR_CONSOLES) { - tty_port_destroy(&vc[i]->port); - kfree(vc[i]); - } + if (vc[i] && i >= MIN_NR_CONSOLES) + tty_port_put(&vc[i]->port); } } @@ -335,22 +352,13 @@ int vt_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - unsigned int console; + unsigned int console = vc->vc_num; unsigned char ucval; unsigned int uival; void __user *up = (void __user *)arg; int i, perm; int ret = 0; - console = vc->vc_num; - - - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } - - /* * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. @@ -641,15 +649,16 @@ int vt_ioctl(struct tty_struct *tty, struct vt_stat __user *vtstat = up; unsigned short state, mask; - /* Review: FIXME: Console lock ? */ if (put_user(fg_console + 1, &vtstat->v_active)) ret = -EFAULT; else { state = 1; /* /dev/tty0 is always open */ + console_lock(); /* required by vt_in_use() */ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) + if (vt_in_use(i)) state |= mask; + console_unlock(); ret = put_user(state, &vtstat->v_state); } break; @@ -659,10 +668,11 @@ int vt_ioctl(struct tty_struct *tty, * Returns the first available (non-opened) console. */ case VT_OPENQRY: - /* FIXME: locking ? - but then this is a stupid API */ + console_lock(); /* required by vt_in_use() */ for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (! VT_IS_IN_USE(i)) + if (!vt_in_use(i)) break; + console_unlock(); uival = i < MAX_NR_CONSOLES ? (i+1) : -1; goto setint; @@ -847,58 +857,49 @@ int vt_ioctl(struct tty_struct *tty, case VT_RESIZEX: { - struct vt_consize __user *vtconsize = up; - ushort ll,cc,vlin,clin,vcol,ccol; + struct vt_consize v; if (!perm) return -EPERM; - if (!access_ok(VERIFY_READ, vtconsize, - sizeof(struct vt_consize))) { - ret = -EFAULT; - break; - } + if (copy_from_user(&v, up, sizeof(struct vt_consize))) + return -EFAULT; /* FIXME: Should check the copies properly */ - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); - vlin = vlin ? vlin : vc->vc_scan_lines; - if (clin) { - if (ll) { - if (ll != vlin/clin) { - /* Parameters don't add up */ - ret = -EINVAL; - break; - } - } else - ll = vlin/clin; + if (!v.v_vlin) + v.v_vlin = vc->vc_scan_lines; + if (v.v_clin) { + int rows = v.v_vlin/v.v_clin; + if (v.v_rows != rows) { + if (v.v_rows) /* Parameters don't add up */ + return -EINVAL; + v.v_rows = rows; + } } - if (vcol && ccol) { - if (cc) { - if (cc != vcol/ccol) { - ret = -EINVAL; - break; - } - } else - cc = vcol/ccol; + if (v.v_vcol && v.v_ccol) { + int cols = v.v_vcol/v.v_ccol; + if (v.v_cols != cols) { + if (v.v_cols) + return -EINVAL; + v.v_cols = cols; + } } - if (clin > 32) { - ret = -EINVAL; - break; - } - + if (v.v_clin > 32) + return -EINVAL; + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *vcp; + if (!vc_cons[i].d) continue; console_lock(); - if (vlin) - vc_cons[i].d->vc_scan_lines = vlin; - if (clin) - vc_cons[i].d->vc_font.height = clin; - vc_cons[i].d->vc_resize_user = 1; - vc_resize(vc_cons[i].d, cc, ll); + vcp = vc_cons[i].d; + if (vcp) { + if (v.v_vlin) + vcp->vc_scan_lines = v.v_vlin; + if (v.v_clin) + vcp->vc_font.height = v.v_clin; + vcp->vc_resize_user = 1; + vc_resize(vcp, v.v_cols, v.v_rows); + } console_unlock(); } break; @@ -1020,12 +1021,12 @@ int vt_ioctl(struct tty_struct *tty, case VT_LOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; - vt_dont_switch = 1; + vt_dont_switch = true; break; case VT_UNLOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; - vt_dont_switch = 0; + vt_dont_switch = false; break; case VT_GETHIFONTMASK: ret = put_user(vc->vc_hi_font_mask, @@ -1189,18 +1190,10 @@ long vt_compat_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - unsigned int console; void __user *up = (void __user *)arg; int perm; int ret = 0; - console = vc->vc_num; - - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } - /* * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. @@ -1260,7 +1253,7 @@ long vt_compat_ioctl(struct tty_struct *tty, arg = (unsigned long)compat_ptr(arg); goto fallback; } -out: + return ret; fallback: diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index e1134a4d97f3fd0005e30dc29e9acf9da77e0e46..a00b4aee6c799cd12b8273db0101990c6437033a 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -135,11 +135,13 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) if (irq_on) { if (test_and_clear_bit(0, &priv->flags)) enable_irq(dev_info->irq); + spin_unlock_irqrestore(&priv->lock, flags); } else { - if (!test_and_set_bit(0, &priv->flags)) + if (!test_and_set_bit(0, &priv->flags)) { + spin_unlock_irqrestore(&priv->lock, flags); disable_irq(dev_info->irq); + } } - spin_unlock_irqrestore(&priv->lock, flags); return 0; } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0453f0eb11781c29f6e4f88b05d51d840ba6ae72..38709bee4c202f5216a2fd22b248a34e75f96a19 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -424,9 +424,12 @@ static void acm_ctrl_irq(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval && retval != -EPERM) + if (retval && retval != -EPERM && retval != -ENODEV) dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", __func__, retval); + else + dev_vdbg(&acm->control->dev, + "control resubmission terminated %d\n", retval); } static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) @@ -442,6 +445,8 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) dev_err(&acm->data->dev, "urb %d failed submission with %d\n", index, res); + } else { + dev_vdbg(&acm->data->dev, "intended failure %d\n", res); } set_bit(index, &acm->read_urbs_free); return res; @@ -484,6 +489,7 @@ static void acm_read_bulk_callback(struct urb *urb) int status = urb->status; bool stopped = false; bool stalled = false; + bool cooldown = false; dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", rb->index, urb->actual_length, status); @@ -510,6 +516,14 @@ static void acm_read_bulk_callback(struct urb *urb) __func__, status); stopped = true; break; + case -EOVERFLOW: + case -EPROTO: + dev_dbg(&acm->data->dev, + "%s - cooling babbling device\n", __func__); + usb_mark_last_busy(acm->dev); + set_bit(rb->index, &acm->urbs_in_error_delay); + cooldown = true; + break; default: dev_dbg(&acm->data->dev, "%s - nonzero urb status received: %d\n", @@ -531,9 +545,11 @@ static void acm_read_bulk_callback(struct urb *urb) */ smp_mb__after_atomic(); - if (stopped || stalled) { + if (stopped || stalled || cooldown) { if (stalled) schedule_work(&acm->work); + else if (cooldown) + schedule_delayed_work(&acm->dwork, HZ / 2); return; } @@ -575,14 +591,20 @@ static void acm_softint(struct work_struct *work) struct acm *acm = container_of(work, struct acm, work); if (test_bit(EVENT_RX_STALL, &acm->flags)) { - if (!(usb_autopm_get_interface(acm->data))) { + smp_mb(); /* against acm_suspend() */ + if (!acm->susp_count) { for (i = 0; i < acm->rx_buflimit; i++) usb_kill_urb(acm->read_urbs[i]); usb_clear_halt(acm->dev, acm->in); acm_submit_read_urbs(acm, GFP_KERNEL); - usb_autopm_put_interface(acm->data); + clear_bit(EVENT_RX_STALL, &acm->flags); } - clear_bit(EVENT_RX_STALL, &acm->flags); + } + + if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) { + for (i = 0; i < ACM_NR; i++) + if (test_and_clear_bit(i, &acm->urbs_in_error_delay)) + acm_submit_read_urb(acm, i, GFP_NOIO); } if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags)) @@ -926,10 +948,10 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) memset(&tmp, 0, sizeof(tmp)); tmp.xmit_fifo_size = acm->writesize; tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); - tmp.close_delay = acm->port.close_delay / 10; + tmp.close_delay = jiffies_to_msecs(acm->port.close_delay) / 10; tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - acm->port.closing_wait / 10; + jiffies_to_msecs(acm->port.closing_wait) / 10; if (copy_to_user(info, &tmp, sizeof(tmp))) return -EFAULT; @@ -942,20 +964,28 @@ static int set_serial_info(struct acm *acm, { struct serial_struct new_serial; unsigned int closing_wait, close_delay; + unsigned int old_closing_wait, old_close_delay; int retval = 0; if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) return -EFAULT; - close_delay = new_serial.close_delay * 10; + close_delay = msecs_to_jiffies(new_serial.close_delay * 10); closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + ASYNC_CLOSING_WAIT_NONE : + msecs_to_jiffies(new_serial.closing_wait * 10); + + /* we must redo the rounding here, so that the values match */ + old_close_delay = jiffies_to_msecs(acm->port.close_delay) / 10; + old_closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + jiffies_to_msecs(acm->port.closing_wait) / 10; mutex_lock(&acm->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if ((close_delay != acm->port.close_delay) || - (closing_wait != acm->port.closing_wait)) + if ((new_serial.close_delay != old_close_delay) || + (new_serial.closing_wait != old_closing_wait)) retval = -EPERM; else retval = -EOPNOTSUPP; @@ -1366,6 +1396,7 @@ static int acm_probe(struct usb_interface *intf, acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; INIT_WORK(&acm->work, acm_softint); + INIT_DELAYED_WORK(&acm->dwork, acm_softint); init_waitqueue_head(&acm->wioctl); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); @@ -1579,6 +1610,7 @@ static void acm_disconnect(struct usb_interface *intf) acm_kill_urbs(acm); cancel_work_sync(&acm->work); + cancel_delayed_work_sync(&acm->dwork); tty_unregister_device(acm_tty_driver, acm->minor); @@ -1621,6 +1653,8 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) acm_kill_urbs(acm); cancel_work_sync(&acm->work); + cancel_delayed_work_sync(&acm->dwork); + acm->urbs_in_error_delay = 0; return 0; } diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 515aad0847ee84b408e7fceb503081f5d97fc78b..30380d28a504b8715417f6f720103ea480ab562a 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -108,8 +108,11 @@ struct acm { unsigned long flags; # define EVENT_TTY_WAKEUP 0 # define EVENT_RX_STALL 1 +# define ACM_ERROR_DELAY 3 + unsigned long urbs_in_error_delay; /* these need to be restarted after a delay */ struct usb_cdc_line_coding line; /* bits, stop, parity */ - struct work_struct work; /* work queue entry for line discipline waking up */ + struct work_struct work; /* work queue entry for various purposes*/ + struct delayed_work dwork; /* for cool downs needed in error recovery */ unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ unsigned int ctrlout; /* output control lines (DTR, RTS) */ struct async_icount iocount; /* counters for control line changes */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7f2ff4fa7e4ef13b64c2988ec434671ad90b98cd..8e03def58017e12e9f2136b51d6d497f4d8ad386 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -37,7 +37,9 @@ #include "otg_whitelist.h" #define USB_VENDOR_GENESYS_LOGIC 0x05e3 +#define USB_VENDOR_SMSC 0x0424 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 +#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02 /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can @@ -968,13 +970,17 @@ int usb_remove_device(struct usb_device *udev) { struct usb_hub *hub; struct usb_interface *intf; + int ret; if (!udev->parent) /* Can't remove a root hub */ return -EINVAL; hub = usb_hub_to_struct_hub(udev->parent); intf = to_usb_interface(hub->intfdev); - usb_autopm_get_interface(intf); + ret = usb_autopm_get_interface(intf); + if (ret < 0) + return ret; + set_bit(udev->portnum, hub->removed_bits); hub_port_logical_disconnect(hub, udev->portnum); usb_autopm_put_interface(intf); @@ -1697,6 +1703,10 @@ static void hub_disconnect(struct usb_interface *intf) kfree(hub->buffer); pm_suspend_ignore_children(&intf->dev, false); + + if (hub->quirk_disable_autosuspend) + usb_autopm_put_interface(intf); + kref_put(&hub->kref, hub_release); } @@ -1827,6 +1837,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND) hub->quirk_check_port_auto_suspend = 1; + if (id->driver_info & HUB_QUIRK_DISABLE_AUTOSUSPEND) { + hub->quirk_disable_autosuspend = 1; + usb_autopm_get_interface_no_resume(intf); + } + if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) return 0; @@ -3010,6 +3025,15 @@ static int check_port_resume_type(struct usb_device *udev, if (portchange & USB_PORT_STAT_C_ENABLE) usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); + + /* + * Whatever made this reset-resume necessary may have + * turned on the port1 bit in hub->change_bits. But after + * a successful reset-resume we want the bit to be clear; + * if it was on it would indicate that something happened + * following the reset-resume. + */ + clear_bit(port1, hub->change_bits); } return status; @@ -5325,6 +5349,10 @@ static void hub_event(struct work_struct *work) } static const struct usb_device_id hub_id_table[] = { + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = USB_VENDOR_SMSC, + .bInterfaceClass = USB_CLASS_HUB, + .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND}, { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = USB_VENDOR_GENESYS_LOGIC, diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 34c1a7e22aae020a2f48bce219a342a89d835650..657bacfbe3a7e5c27b7691e11609b0dc2bac3e84 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,7 @@ struct usb_hub { unsigned quiescing:1; unsigned disconnected:1; unsigned in_reset:1; + unsigned quirk_disable_autosuspend:1; unsigned quirk_check_port_auto_suspend:1; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index e70578e1115614d229250f9bdbb154a5ab7dd565..00e80cfe614cefc4945c7947f4e37627891f29da 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -586,12 +586,13 @@ void usb_sg_cancel(struct usb_sg_request *io) int i, retval; spin_lock_irqsave(&io->lock, flags); - if (io->status) { + if (io->status || io->count == 0) { spin_unlock_irqrestore(&io->lock, flags); return; } /* shut everything down */ io->status = -ECONNRESET; + io->count++; /* Keep the request alive until we're done */ spin_unlock_irqrestore(&io->lock, flags); for (i = io->entries - 1; i >= 0; --i) { @@ -605,6 +606,12 @@ void usb_sg_cancel(struct usb_sg_request *io) dev_warn(&io->dev->dev, "%s, unlink --> %d\n", __func__, retval); } + + spin_lock_irqsave(&io->lock, flags); + io->count--; + if (!io->count) + complete(&io->complete); + spin_unlock_irqrestore(&io->lock, flags); } EXPORT_SYMBOL_GPL(usb_sg_cancel); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 460c855be0d020bd21d3cc024d0a33d705b0d59d..53c1f6e604b152923bf323317d270b05da6c20dd 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -179,7 +179,10 @@ static int usb_port_runtime_resume(struct device *dev) if (!port_dev->is_superspeed && peer) pm_runtime_get_sync(&peer->dev); - usb_autopm_get_interface(intf); + retval = usb_autopm_get_interface(intf); + if (retval < 0) + return retval; + retval = usb_hub_set_port_power(hdev, hub, port1, true); msleep(hub_power_on_good_delay(hub)); if (udev && !retval) { @@ -232,7 +235,10 @@ static int usb_port_runtime_suspend(struct device *dev) if (usb_port_block_power_off) return -EBUSY; - usb_autopm_get_interface(intf); + retval = usb_autopm_get_interface(intf); + if (retval < 0) + return retval; + retval = usb_hub_set_port_power(hdev, hub, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); if (!port_dev->is_superspeed) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 047bb6ebf48580f9f1f54ddd15c421d2cdcf39dc..7d3130b0209ee2ed0d1161657a2f233f12b2b1de 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -86,6 +86,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Logitech PTZ Pro Camera */ { USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech Screen Share */ + { USB_DEVICE(0x046d, 0x086c), .driver_info = USB_QUIRK_NO_LPM }, + /* Logitech Quickcam Fusion */ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -226,6 +229,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0b05, 0x17e0), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Realtek hub in Dell WD19 (Type-C) */ + { USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM }, + + /* Generic RTL8153 based ethernet adapters */ + { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM }, + /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, @@ -263,6 +272,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* Corsair K70 LUX */ { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair K70 RGB RAPDIFIRE */ + { USB_DEVICE(0x1b1c, 0x1b38), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, + /* MIDI keyboard WORLDE MINI */ { USB_DEVICE(0x1c75, 0x0204), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -297,6 +310,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + /* novation SoundControl XL */ + { USB_DEVICE(0x1235, 0x0061), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4af9a1c652edb56b3bcf87c67d6568561f496d16..aeb6f7c84ea0ae83a83c5863e37ecf6eb97fbb78 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3933,11 +3933,12 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, * a unique tx-fifo even if it is non-periodic. */ if (dir_in && hsotg->dedicated_fifos) { + unsigned fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); u32 fifo_index = 0; u32 fifo_size = UINT_MAX; size = hs_ep->ep.maxpacket * hs_ep->mc; - for (i = 1; i < hsotg->num_of_eps; ++i) { + for (i = 1; i <= fifo_count; ++i) { if (hsotg->fifo_map & (1 << i)) continue; val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ecc696189967a8e315c4c124e757361fde8680a2..f5a39d85382f62a0f1835dd28aaa150d51dcd457 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -944,6 +944,9 @@ int dwc3_core_init(struct dwc3 *dwc) if (dwc->dis_tx_ipgap_linecheck_quirk) reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; + if (dwc->parkmode_disable_ss_quirk) + reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; + /* * STAR: 9001415732: Host failure when Park mode is enabled: * Disable parkmode for Gen1 controllers to fix the stall @@ -1255,6 +1258,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-del-phy-power-chg-quirk"); dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev, "snps,dis-tx-ipgap-linecheck-quirk"); + dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, + "snps,parkmode-disable-ss-quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index ae63ee62491fa34b7cbdd6df50490e5c9c3565df..20e4dd6d9c8ba6b3d05952fc8c899aecae03484f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -220,6 +220,7 @@ #define DWC3_GCTL_DSBLCLKGTNG BIT(0) /* Global User Control 1 Register */ +#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) #define DWC3_GUCTL1_IP_GAP_ADD_ON(n) (n << 21) @@ -969,6 +970,8 @@ struct dwc3_scratchpad_array { * change quirk. * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate * check during HS transmit. + * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed + * instances in park mode. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -1163,6 +1166,7 @@ struct dwc3 { unsigned dis_u2_freeclk_exists_quirk:1; unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; + unsigned parkmode_disable_ss_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned ssp_u3_u0_quirk:1; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 9bfad4bfbb02a27ce7ffa6dcb859f65724683c7d..41afdf4860fedc9cad3035960e89f5bbab9a2482 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "power.h" #include "core.h" @@ -496,8 +497,10 @@ static inline bool dwc3_msm_is_dev_superspeed(struct dwc3_msm *mdwc) speed = dwc3_msm_read_reg(mdwc->base, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD; if ((speed & DWC3_DSTS_SUPERSPEED) || - (speed & DWC3_DSTS_SUPERSPEED_PLUS)) + (speed & DWC3_DSTS_SUPERSPEED_PLUS)) { + mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; return true; + } return false; } @@ -2253,7 +2256,7 @@ static void dwc3_msm_block_reset(struct dwc3_msm *mdwc, bool core_reset) static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - u32 val, val1; + u32 val = 0, val1 = 0; int ret; /* Configure AHB2PHY for one wait state read/write */ @@ -3294,6 +3297,12 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data) dwc->t_pwr_evt_irq = ktime_get(); dev_dbg(mdwc->dev, "%s received\n", __func__); + + if (mdwc->drd_state == DRD_STATE_PERIPHERAL_SUSPEND) { + dev_info(mdwc->dev, "USB Resume start\n"); + place_marker("M - USB device resume started"); + } + /* * When in Low Power Mode, can't read PWR_EVNT_IRQ_STAT_REG to acertain * which interrupts have been triggered, as the clocks are disabled. @@ -5161,6 +5170,12 @@ static int dwc3_msm_pm_resume(struct device *dev) flush_workqueue(mdwc->dwc3_wq); atomic_set(&mdwc->pm_suspended, 0); + if (atomic_read(&dwc->in_lpm) && + mdwc->drd_state == DRD_STATE_PERIPHERAL_SUSPEND) { + dev_info(mdwc->dev, "USB Resume start\n"); + place_marker("M - USB device resume started"); + } + if (!dwc->ignore_wakeup_src_in_hostmode || !mdwc->in_host_mode) { /* kick in otg state machine */ queue_work(mdwc->dwc3_wq, &mdwc->resume_work); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c6f0ce788048552b1046fe34c83656f494cb7e27..c8e8f7dd29a273e742eff5d3308a87fdef441f47 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1939,8 +1939,10 @@ static int dwc3_gadget_wakeup_int(struct dwc3 *dwc) link_state = dwc3_get_link_state(dwc); switch (link_state) { + case DWC3_LINK_STATE_RESET: case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ + case DWC3_LINK_STATE_RESUME: break; case DWC3_LINK_STATE_U1: if (dwc->gadget.speed < USB_SPEED_SUPER) { diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 12fe70beae6991026f6ff2c19d0c92b4d5d5bc2a..21244c556b8102eb1bcb19a61a8372f2e56e10b9 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -738,19 +738,19 @@ static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb) case COMP_USB_TRANSACTION_ERROR: case COMP_STALL_ERROR: default: - if (ep_id == XDBC_EPID_OUT) + if (ep_id == XDBC_EPID_OUT || ep_id == XDBC_EPID_OUT_INTEL) xdbc.flags |= XDBC_FLAGS_OUT_STALL; - if (ep_id == XDBC_EPID_IN) + if (ep_id == XDBC_EPID_IN || ep_id == XDBC_EPID_IN_INTEL) xdbc.flags |= XDBC_FLAGS_IN_STALL; xdbc_trace("endpoint %d stalled\n", ep_id); break; } - if (ep_id == XDBC_EPID_IN) { + if (ep_id == XDBC_EPID_IN || ep_id == XDBC_EPID_IN_INTEL) { xdbc.flags &= ~XDBC_FLAGS_IN_PROCESS; xdbc_bulk_transfer(NULL, XDBC_MAX_PACKET, true); - } else if (ep_id == XDBC_EPID_OUT) { + } else if (ep_id == XDBC_EPID_OUT || ep_id == XDBC_EPID_OUT_INTEL) { xdbc.flags &= ~XDBC_FLAGS_OUT_PROCESS; } else { xdbc_trace("invalid endpoint id %d\n", ep_id); diff --git a/drivers/usb/early/xhci-dbc.h b/drivers/usb/early/xhci-dbc.h index a516cab0bf4a5401d90f9d4c2c941f650eb0a375..6c9200d913daf060466adcbca7ef7e0a2d132458 100644 --- a/drivers/usb/early/xhci-dbc.h +++ b/drivers/usb/early/xhci-dbc.h @@ -123,8 +123,22 @@ struct xdbc_ring { u32 cycle_state; }; -#define XDBC_EPID_OUT 2 -#define XDBC_EPID_IN 3 +/* + * These are the "Endpoint ID" (also known as "Context Index") values for the + * OUT Transfer Ring and the IN Transfer Ring of a Debug Capability Context data + * structure. + * According to the "eXtensible Host Controller Interface for Universal Serial + * Bus (xHCI)" specification, section "7.6.3.2 Endpoint Contexts and Transfer + * Rings", these should be 0 and 1, and those are the values AMD machines give + * you; but Intel machines seem to use the formula from section "4.5.1 Device + * Context Index", which is supposed to be used for the Device Context only. + * Luckily the values from Intel don't overlap with those from AMD, so we can + * just test for both. + */ +#define XDBC_EPID_OUT 0 +#define XDBC_EPID_IN 1 +#define XDBC_EPID_OUT_INTEL 2 +#define XDBC_EPID_IN_INTEL 3 struct xdbc_state { u16 vendor; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 904cfe925ad92ba02dc1174aa24da82a4e56d3f1..21fbcec38aefcf21578594f454fc24166bb445ba 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -671,34 +671,6 @@ config USB_CONFIGFS_F_MDM_DATA help USB QTI modem data function driver. -choice - tristate "USB Gadget precomposed configurations" - default USB_ETH - optional - help - A Linux "Gadget Driver" talks to the USB Peripheral Controller - driver through the abstract "gadget" API. Some other operating - systems call these "client" drivers, of which "class drivers" - are a subset (implementing a USB device class specification). - A gadget driver implements one or more USB functions using - the peripheral hardware. - - Gadget drivers are hardware-neutral, or "platform independent", - except that they sometimes must understand quirks or limitations - of the particular controllers they work with. For example, when - a controller doesn't support alternate configurations or provide - enough of the right types of endpoints, the gadget driver might - not be able work with that controller, or might need to implement - a less common variant of a device class protocol. - - The available choices each represent a single precomposed USB - gadget configuration. In the device model, each option contains - both the device instantiation as a child for a USB gadget - controller, and the relevant drivers for each function declared - by the device. - source "drivers/usb/gadget/legacy/Kconfig" -endchoice - endif # USB_GADGET diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 73f1fd35e3869c519828df9cc21abd52fd8f80c3..f7a57942f2df1179314fcc61af6f1cacff5a0229 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -569,14 +569,14 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, val = CONFIG_USB_GADGET_VBUS_DRAW; if (!val) return 0; - switch (speed) { - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - return (u8)(val / 8); - default: - /* only SuperSpeed and faster support > 500mA */ - return DIV_ROUND_UP(min(val, 500U), 2); - } + if (speed < USB_SPEED_SUPER) + return min(val, 500U) / 2; + else + /* + * USB 3.x supports up to 900mA, but since 900 isn't divisible + * by 8 the integral division will effectively cap to 896mA. + */ + return min(val, 900U) / 8; } static int config_buf(struct usb_configuration *config, @@ -978,8 +978,14 @@ static int set_config(struct usb_composite_dev *cdev, power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; if (gadget->speed < USB_SPEED_SUPER) power = min(power, 500U); - + else + power = min(power, 900U); done: + if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) + usb_gadget_set_selfpowered(gadget); + else + usb_gadget_clear_selfpowered(gadget); + usb_gadget_vbus_draw(gadget, power); if (result >= 0 && cdev->delayed_status) result = USB_GADGET_DELAYED_STATUS; @@ -2417,6 +2423,7 @@ void composite_suspend(struct usb_gadget *gadget) cdev->suspended = 1; spin_unlock_irqrestore(&cdev->lock, flags); + usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, 2); } @@ -2431,7 +2438,7 @@ void composite_resume(struct usb_gadget *gadget) /* REVISIT: should we have config level * suspend/resume callbacks? */ - INFO(cdev, "USB Resume\n"); + INFO(cdev, "USB Resume end\n"); place_marker("M - USB device is resumed"); if (cdev->driver->resume) cdev->driver->resume(cdev); @@ -2466,10 +2473,16 @@ void composite_resume(struct usb_gadget *gadget) f->resume(f); } - maxpower = cdev->config->MaxPower; - maxpower = maxpower ? maxpower : CONFIG_USB_GADGET_VBUS_DRAW; + maxpower = cdev->config->MaxPower ? + cdev->config->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; if (gadget->speed < USB_SPEED_SUPER) maxpower = min(maxpower, 500U); + else + maxpower = min(maxpower, 900U); + + if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW) + usb_gadget_clear_selfpowered(gadget); + usb_gadget_vbus_draw(gadget, maxpower); } diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 2451aab593ba9771d8d1dd56c3c1ceea6489178c..b0faafca4b1b291aa5cf5edce04e969fbcefb986 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -57,11 +57,8 @@ #define BRIDGE_RX_QUEUE_SIZE 8 #define BRIDGE_RX_BUF_SIZE 2048 #define BRIDGE_TX_QUEUE_SIZE 8 -#if IS_ENABLED(CONFIG_ARCH_SM8150) -#define BRIDGE_TX_BUF_SIZE (50 * 1024) -#else -#define BRIDGE_TX_BUF_SIZE 2048 -#endif +#define BRIDGE_TX_BUF_SIZE 2048 + #define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ #define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index f7dfb0aba38a71dcb30f5e5230a2b3e2ea54f7e3..a3a4e5da90f7c1bdf1fa6ad56a53ae3fec1369ef 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -56,6 +56,7 @@ struct f_ecm { struct usb_ep *notify; struct usb_request *notify_req; u8 notify_state; + atomic_t notify_count; bool is_open; /* FIXME is_open needs some irq-ish locking @@ -384,7 +385,7 @@ static void ecm_do_notify(struct f_ecm *ecm) int status; /* notification already in flight? */ - if (!req) + if (atomic_read(&ecm->notify_count)) return; event = req->buf; @@ -424,10 +425,10 @@ static void ecm_do_notify(struct f_ecm *ecm) event->bmRequestType = 0xA1; event->wIndex = cpu_to_le16(ecm->ctrl_id); - ecm->notify_req = NULL; + atomic_inc(&ecm->notify_count); status = usb_ep_queue(ecm->notify, req, GFP_ATOMIC); if (status < 0) { - ecm->notify_req = req; + atomic_dec(&ecm->notify_count); DBG(cdev, "notify --> %d\n", status); } } @@ -452,17 +453,19 @@ static void ecm_notify_complete(struct usb_ep *ep, struct usb_request *req) switch (req->status) { case 0: /* no fault */ + atomic_dec(&ecm->notify_count); break; case -ECONNRESET: case -ESHUTDOWN: + atomic_set(&ecm->notify_count, 0); ecm->notify_state = ECM_NOTIFY_NONE; break; default: DBG(cdev, "event %02x --> %d\n", event->bNotificationType, req->status); + atomic_dec(&ecm->notify_count); break; } - ecm->notify_req = req; ecm_do_notify(ecm); } @@ -922,6 +925,11 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); + if (atomic_read(&ecm->notify_count)) { + usb_ep_dequeue(ecm->notify, ecm->notify_req); + atomic_set(&ecm->notify_count, 0); + } + kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); opts->bound = false; diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 31780ddf09c025d567608b0af802968d2321d1c8..c46874d6f3b0ece628717cb6f1ced6a3273fe222 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1138,6 +1138,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); if (unlikely(ret)) { + io_data->req = NULL; usb_ep_free_request(ep->ep, req); goto error_lock; } @@ -1191,6 +1192,7 @@ static int ffs_aio_cancel(struct kiocb *kiocb) struct ffs_io_data *io_data = kiocb->private; struct ffs_epfile *epfile = kiocb->ki_filp->private_data; struct ffs_data *ffs = epfile->ffs; + unsigned long flags; int value; ENTER(); @@ -1198,14 +1200,14 @@ static int ffs_aio_cancel(struct kiocb *kiocb) ffs_log("enter:state %d setup_state %d flag %lu", ffs->state, ffs->setup_state, ffs->flags); - spin_lock_irq(&epfile->ffs->eps_lock); + spin_lock_irqsave(&epfile->ffs->eps_lock, flags); if (likely(io_data && io_data->ep && io_data->req)) value = usb_ep_dequeue(io_data->ep, io_data->req); else value = -EINVAL; - spin_unlock_irq(&epfile->ffs->eps_lock); + spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags); ffs_log("exit: value %d", value); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 5a2b8ab2b95cfc2f7191a36554e035c37df38210..ad88ebd612858d1c7806e3e07481fcf28e1a5edc 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1858,9 +1858,41 @@ static int queue_notification_request(struct f_gsi *gsi) { int ret; unsigned long flags; + struct usb_function *func = &gsi->function; + struct usb_request *req = gsi->c_port.notify_req; + struct usb_ep *ep = gsi->c_port.notify; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (gsi->c_port.is_suspended) { + /*For remote wakeup, queue the req from gsi_resume*/ + spin_lock_irqsave(&gsi->c_port.lock, flags); + gsi->c_port.notify_req_queued = false; + spin_unlock_irqrestore(&gsi->c_port.lock, flags); + + if (gsi->rwake_inprogress) { + log_event_dbg("%s remote-wakeup in progress\n", + __func__); + return -EBUSY; + } + + if (!usb_gsi_remote_wakeup_allowed(func)) { + log_event_dbg("%s remote-wakeup not capable\n", + __func__); + return -EOPNOTSUPP; + } - ret = usb_func_ep_queue(&gsi->function, gsi->c_port.notify, - gsi->c_port.notify_req, GFP_ATOMIC); + log_event_dbg("%s wakeup host\n", __func__); + if (gadget->speed >= USB_SPEED_SUPER + && func->func_is_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + gsi->rwake_inprogress = true; + return ret; + } + + ret = usb_ep_queue(ep, req, GFP_ATOMIC); if (ret < 0) { spin_lock_irqsave(&gsi->c_port.lock, flags); gsi->c_port.notify_req_queued = false; @@ -2493,6 +2525,7 @@ static int gsi_set_alt(struct usb_function *f, unsigned int intf, gsi->data_id, gsi->data_interface_up); } + gsi->c_port.is_suspended = false; atomic_set(&gsi->connected, 1); /* send 0 len pkt to qti to notify state change */ @@ -2593,6 +2626,7 @@ static void gsi_suspend(struct usb_function *f) return; } + gsi->c_port.is_suspended = true; block_db = true; usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); @@ -2624,6 +2658,8 @@ static void gsi_resume(struct usb_function *f) if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); + gsi->c_port.is_suspended = false; + /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); @@ -2968,7 +3004,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.out_epname = "gsi-epout"; info.in_req_buf_len = GSI_IN_RNDIS_BUFF_SIZE; gsi->d_port.in_aggr_size = GSI_IN_RNDIS_AGGR_SIZE; - info.in_req_num_buf = GSI_NUM_IN_RNDIS_BUFFERS; + info.in_req_num_buf = GSI_NUM_IN_RNDIS_RMNET_ECM_BUFFERS; gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE; info.out_req_buf_len = GSI_OUT_AGGR_SIZE; info.out_req_num_buf = GSI_NUM_OUT_BUFFERS; @@ -3167,7 +3203,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.out_epname = "gsi-epout"; gsi->d_port.in_aggr_size = GSI_IN_RMNET_AGGR_SIZE; info.in_req_buf_len = GSI_IN_RMNET_BUFF_SIZE; - info.in_req_num_buf = GSI_NUM_IN_RMNET_BUFFERS; + info.in_req_num_buf = GSI_NUM_IN_RNDIS_RMNET_ECM_BUFFERS; gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE; info.out_req_buf_len = GSI_OUT_RMNET_BUF_LEN; info.out_req_num_buf = GSI_NUM_OUT_BUFFERS; @@ -3200,7 +3236,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.out_epname = "gsi-epout"; gsi->d_port.in_aggr_size = GSI_ECM_AGGR_SIZE; info.in_req_buf_len = GSI_IN_BUFF_SIZE; - info.in_req_num_buf = GSI_NUM_IN_BUFFERS; + info.in_req_num_buf = GSI_NUM_IN_RNDIS_RMNET_ECM_BUFFERS; gsi->d_port.out_aggr_size = GSI_ECM_AGGR_SIZE; info.out_req_buf_len = GSI_OUT_ECM_BUF_LEN; info.out_req_num_buf = GSI_NUM_OUT_BUFFERS; diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 43fba6d611795f4b5578f1c4fe1d2b4fa59ac217..7e9da0a189fa0c478dd0811d9b46d890d518f2a4 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -44,8 +44,7 @@ #define GSI_MAX_CTRL_PKT_SIZE 8192 #define GSI_CTRL_DTR (1 << 0) -#define GSI_NUM_IN_RNDIS_BUFFERS 50 -#define GSI_NUM_IN_RMNET_BUFFERS 50 +#define GSI_NUM_IN_RNDIS_RMNET_ECM_BUFFERS 50 #define GSI_NUM_IN_BUFFERS 15 #define GSI_IN_BUFF_SIZE 2048 #define GSI_IN_RMNET_BUFF_SIZE 31744 @@ -210,6 +209,7 @@ struct gsi_ctrl_port { atomic_t ctrl_online; bool is_open; + bool is_suspended; wait_queue_head_t read_wq; diff --git a/drivers/usb/gadget/function/f_ipc.c b/drivers/usb/gadget/function/f_ipc.c index 1e6a1b4ac822eee507e56366e45b624a3700791a..d0c1613a1d27af4372201a5962617fb67eb55499 100644 --- a/drivers/usb/gadget/function/f_ipc.c +++ b/drivers/usb/gadget/function/f_ipc.c @@ -21,11 +21,12 @@ #include #include #include +#include #define MAX_INST_NAME_LEN 40 -#define IPC_BRIDGE_MAX_READ_SZ (8 * 1024) -#define IPC_BRIDGE_MAX_WRITE_SZ (8 * 1024) +#define IPC_BRIDGE_MAX_READ_SZ (24 * 1024) +#define IPC_BRIDGE_MAX_WRITE_SZ (24 * 1024) #define IPC_WRITE_WAIT_TIMEOUT 10000 @@ -272,22 +273,34 @@ static int ipc_write(struct platform_device *pdev, char *buf, reinit_completion(&ipc_dev->write_done); if (usb_ep_queue(in, req, GFP_KERNEL)) { + /* Notify GPIO driver to wakup the host if host + * is in suspend mode. + */ + sb_notifier_call_chain(EVT_WAKE_UP, NULL); wait_event_interruptible(ipc_dev->state_wq, ipc_dev->online || ipc_dev->current_state == IPC_DISCONNECTED); pr_debug("%s: Interface ready, Retry IN request\n", __func__); goto retry_write; } +retry_write_done: ret = wait_for_completion_interruptible_timeout(&ipc_dev->write_done, msecs_to_jiffies(IPC_WRITE_WAIT_TIMEOUT)); if (ret < 0) { pr_err("%s: Interruption triggered\n", __func__); ret = -EINTR; goto fail; - } else if (ret == 0) { + } else if (ret == 0 && ipc_dev->online) { pr_err("%s: Request timed out\n", __func__); ret = -ETIMEDOUT; goto fail; + /* Notify the GPIO driver to wakeup the host and reintialize the + * completion structure. + */ + } else if (ipc_dev->connected && !ipc_dev->online) { + sb_notifier_call_chain(EVT_WAKE_UP, NULL); + reinit_completion(&ipc_dev->write_done); + goto retry_write_done; } return !req->status ? req->actual : req->status; diff --git a/drivers/usb/gadget/function/f_mdm_data.c b/drivers/usb/gadget/function/f_mdm_data.c index 757a2af20d7a9fb158479b68d0ba5ccabff61126..7d50e8392e3c4758a91b329d772c2fa716d5740d 100644 --- a/drivers/usb/gadget/function/f_mdm_data.c +++ b/drivers/usb/gadget/function/f_mdm_data.c @@ -579,6 +579,15 @@ static void mdm_data_start_rx(struct mdm_data_port *port) return; } + if (!test_bit(CH_READY, &port->bridge_sts)) { + while (!list_empty(&port->rx_idle)) { + req = list_first_entry(&port->rx_idle, + struct usb_request, list); + list_del(&req->list); + usb_ep_free_request(ep, req); + } + } + while (atomic_read(&port->connected) && !list_empty(&port->rx_idle)) { if (port->rx_skb_q.qlen > mdm_data_pend_limit_with_bridge) break; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index f0a8e66e7a9cb7174de6f429bc5818c5f287d590..6b8b80879ec8c4285ad1972822e98dfc0d7e4865 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1221,7 +1221,7 @@ static ssize_t alsa_show(struct device *dev, if (fi_midi && fi_midi->f) { midi = func_to_midi(fi_midi->f); - if (midi->rmidi && midi->rmidi->card) + if (midi->rmidi && midi->card && midi->rmidi->card) return sprintf(buf, "%d %d\n", midi->rmidi->card->number, midi->rmidi->device); } diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index f1429ba14aef074e30b98b345b83d275e097d103..64f8b35ece9ac68a01d9c65862b9486d8651293d 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -58,6 +58,7 @@ struct f_ncm { struct usb_ep *notify; struct usb_request *notify_req; u8 notify_state; + atomic_t notify_count; bool is_open; const struct ndp_parser_opts *parser_opts; @@ -553,7 +554,7 @@ static void ncm_do_notify(struct f_ncm *ncm) int status; /* notification already in flight? */ - if (!req) + if (atomic_read(&ncm->notify_count)) return; event = req->buf; @@ -593,7 +594,8 @@ static void ncm_do_notify(struct f_ncm *ncm) event->bmRequestType = 0xA1; event->wIndex = cpu_to_le16(ncm->ctrl_id); - ncm->notify_req = NULL; + atomic_inc(&ncm->notify_count); + /* * In double buffering if there is a space in FIFO, * completion callback can be called right after the call, @@ -603,7 +605,7 @@ static void ncm_do_notify(struct f_ncm *ncm) status = usb_ep_queue(ncm->notify, req, GFP_ATOMIC); spin_lock(&ncm->lock); if (status < 0) { - ncm->notify_req = req; + atomic_dec(&ncm->notify_count); DBG(cdev, "notify --> %d\n", status); } } @@ -638,17 +640,19 @@ static void ncm_notify_complete(struct usb_ep *ep, struct usb_request *req) case 0: VDBG(cdev, "Notification %02x sent\n", event->bNotificationType); + atomic_dec(&ncm->notify_count); break; case -ECONNRESET: case -ESHUTDOWN: + atomic_set(&ncm->notify_count, 0); ncm->notify_state = NCM_NOTIFY_NONE; break; default: DBG(cdev, "event %02x --> %d\n", event->bNotificationType, req->status); + atomic_dec(&ncm->notify_count); break; } - ncm->notify_req = req; ncm_do_notify(ncm); spin_unlock(&ncm->lock); } @@ -1709,6 +1713,11 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) ncm_string_defs[0].id = 0; usb_free_all_descriptors(f); + if (atomic_read(&ncm->notify_count)) { + usb_ep_dequeue(ncm->notify, ncm->notify_req); + atomic_set(&ncm->notify_count, 0); + } + kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); diff --git a/drivers/usb/gadget/function/u_bam_dmux.c b/drivers/usb/gadget/function/u_bam_dmux.c index f40b8e7ecb7f5dd2a0938c1e11c9c5f9374b4af6..57aaebfcfd64c43b55e658df13bd2b60f12c599b 100644 --- a/drivers/usb/gadget/function/u_bam_dmux.c +++ b/drivers/usb/gadget/function/u_bam_dmux.c @@ -35,7 +35,6 @@ static struct workqueue_struct *gbam_wq; static unsigned int n_tx_req_queued; static unsigned int bam_ch_ids[BAM_DMUX_NUM_FUNCS] = { - BAM_DMUX_USB_RMNET_0, BAM_DMUX_USB_RMNET_0, BAM_DMUX_USB_DPL }; @@ -1026,11 +1025,12 @@ static void gbam_port_free(enum bam_dmux_func_type func) struct gbam_port *port = bam_ports[func].port; struct platform_driver *pdrv = &bam_ports[func].pdrv; - if (port) + if (port) { platform_driver_unregister(pdrv); - kfree(port); - bam_ports[func].port = NULL; + kfree(port); + bam_ports[func].port = NULL; + } } static int gbam_port_alloc(enum bam_dmux_func_type func) @@ -1217,6 +1217,9 @@ static void gbam_debugfs_init(void) } static void gbam_debugfs_remove(void) { + if (!gbam_dent) + return; + debugfs_remove_recursive(gbam_dent); debugfs_remove(gbam_dent); gbam_dent = NULL; @@ -1451,7 +1454,8 @@ int gbam_mbim_setup(void) { int ret = 0; - ret = gbam_setup(BAM_DMUX_FUNC_MBIM); + if (!bam_ports[BAM_DMUX_FUNC_RMNET].port) + ret = gbam_setup(BAM_DMUX_FUNC_MBIM); return ret; } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 7fdcc368fc910db7c9e4ce2f6b22ecb41897bf2a..fc5f05a4b5aba37ff455809d0b7b1962a54fac4f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -804,7 +804,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } /* apply outgoing CDC or RNDIS filters */ - if (!test_bit(RMNET_MODE_LLP_IP, &dev->flags) && + if (skb && !test_bit(RMNET_MODE_LLP_IP, &dev->flags) && !is_promisc(cdc_filter)) { u8 *dest = skb->data; @@ -872,16 +872,17 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, if (dev->wrap) { if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); - if (!skb) { - spin_unlock_irqrestore(&dev->lock, flags); - /* Multi frame CDC protocols may store the frame for - * later which is not a dropped frame. - */ - if (dev->port_usb && - dev->port_usb->supports_multi_frame) - goto multiframe; - goto drop; - } + } + + if (!skb) { + spin_unlock_irqrestore(&dev->lock, flags); + /* Multi frame CDC protocols may store the frame for + * later which is not a dropped frame. + */ + if (dev->port_usb && + dev->port_usb->supports_multi_frame) + goto multiframe; + goto drop; } dev->tx_skb_hold_count++; diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h index dbc3002bb99ed67e874eba2a14e3ca66d09a3ee7..2e963f813a7f054c0b968135aaaa2efd99518511 100644 --- a/drivers/usb/gadget/function/u_rmnet.h +++ b/drivers/usb/gadget/function/u_rmnet.h @@ -22,7 +22,7 @@ enum bam_dmux_func_type { BAM_DMUX_FUNC_RMNET, - BAM_DMUX_FUNC_MBIM, + BAM_DMUX_FUNC_MBIM = 0, BAM_DMUX_FUNC_DPL, BAM_DMUX_NUM_FUNCS, }; diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index d8a50c7da202dcf9ed59d5545762bc5735b37350..eb04868e9e080256e51dc9508ab9a612a5333d0e 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -715,8 +715,10 @@ static int gs_start_io(struct gs_port *port) port->n_read = 0; started = gs_start_rx(port); - /* unblock any pending writes into our circular buffer */ if (started) { + gs_start_tx(port); + /* Unblock any pending writes into our circular buffer, in case + * we didn't in gs_start_tx() */ tty_wakeup(port->port.tty); } else { gs_free_requests(ep, head, &port->read_allocated); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 11d70dead32b67bb0d2218060303cec352a3415d..bf5f25349531721c2cfc9cbde2afafe921533b6b 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -94,7 +94,7 @@ extern unsigned int uvc_gadget_trace_param; * Driver specific constants */ -#define UVC_NUM_REQUESTS 4 +#define UVC_NUM_REQUESTS 8 #define UVC_MAX_REQUEST_SIZE 64 #define UVC_MAX_EVENTS 4 diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 82445dd40a96b7c64755c3e79d3c69decb642553..56590504057c3f03c20d0c51fbc836d4c9edf46d 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -13,6 +13,32 @@ # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). # +choice + tristate "USB Gadget precomposed configurations" + default USB_ETH + optional + help + A Linux "Gadget Driver" talks to the USB Peripheral Controller + driver through the abstract "gadget" API. Some other operating + systems call these "client" drivers, of which "class drivers" + are a subset (implementing a USB device class specification). + A gadget driver implements one or more USB functions using + the peripheral hardware. + + Gadget drivers are hardware-neutral, or "platform independent", + except that they sometimes must understand quirks or limitations + of the particular controllers they work with. For example, when + a controller doesn't support alternate configurations or provide + enough of the right types of endpoints, the gadget driver might + not be able work with that controller, or might need to implement + a less common variant of a device class protocol. + + The available choices each represent a single precomposed USB + gadget configuration. In the device model, each option contains + both the device instantiation as a child for a USB gadget + controller, and the relevant drivers for each function declared + by the device. + config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE @@ -500,3 +526,16 @@ config USB_G_WEBCAM Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_webcam". + +config USB_RAW_GADGET + tristate "USB Raw Gadget" + help + USB Raw Gadget is a kernel module that provides a userspace interface + for the USB Gadget subsystem. Essentially it allows to emulate USB + devices from userspace. See Documentation/usb/raw-gadget.rst for + details. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "raw_gadget". + +endchoice diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile index 216d5cf177caee76e2ab1682c2ef5228af236845..2220792c3f5735dce1bd362bf4a5896971a42a2a 100644 --- a/drivers/usb/gadget/legacy/Makefile +++ b/drivers/usb/gadget/legacy/Makefile @@ -45,3 +45,4 @@ obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o obj-$(CONFIG_USB_G_QTI) += g_qti_gadget.o +obj-$(CONFIG_USB_RAW_GADGET) += raw_gadget.o diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index 51c08682de846a1dbb264dad9aa5bfeaba99a759..5ee25beb52f0d38c0bbe183bb3e3540fc06032d5 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -229,7 +229,7 @@ static struct usb_composite_driver cdc_driver = { .name = "g_cdc", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .bind = cdc_bind, .unbind = cdc_unbind, }; diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index 6da7316f8e87d73d7edb8a8215ac886db381c9bc..54ee4e31645b92bbc2cf94167542eb512c26c967 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -153,7 +153,7 @@ static struct usb_composite_driver gfs_driver = { .name = DRIVER_NAME, .dev = &gfs_dev_desc, .strings = gfs_dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .bind = gfs_bind, .unbind = gfs_unbind, }; diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index a70a406580eae509839f58c6c91447402f51601d..3b7fc5c7e9c3a97df557f022b4bb79f277daaaa6 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -486,7 +486,7 @@ static struct usb_composite_driver multi_driver = { .name = "g_multi", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .bind = multi_bind, .unbind = multi_unbind, .needs_serial = 1, diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c index 0aba68253e3d61d544b6180baec6c0b0b7b1336f..2fb4a847dd5262a9fe3c0c2a291abc3933faa6b4 100644 --- a/drivers/usb/gadget/legacy/ncm.c +++ b/drivers/usb/gadget/legacy/ncm.c @@ -203,7 +203,7 @@ static struct usb_composite_driver ncm_driver = { .name = "g_ncm", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .bind = gncm_bind, .unbind = gncm_unbind, }; diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c new file mode 100644 index 0000000000000000000000000000000000000000..76406343fbe577d2d8e9fafe03c72a27dba8a051 --- /dev/null +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -0,0 +1,1078 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USB Raw Gadget driver. + * See Documentation/usb/raw-gadget.rst for more details. + * + * Andrey Konovalov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DRIVER_DESC "USB Raw Gadget" +#define DRIVER_NAME "raw-gadget" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Andrey Konovalov"); +MODULE_LICENSE("GPL"); + +/*----------------------------------------------------------------------*/ + +#define RAW_EVENT_QUEUE_SIZE 16 + +struct raw_event_queue { + /* See the comment in raw_event_queue_fetch() for locking details. */ + spinlock_t lock; + struct semaphore sema; + struct usb_raw_event *events[RAW_EVENT_QUEUE_SIZE]; + int size; +}; + +static void raw_event_queue_init(struct raw_event_queue *queue) +{ + spin_lock_init(&queue->lock); + sema_init(&queue->sema, 0); + queue->size = 0; +} + +static int raw_event_queue_add(struct raw_event_queue *queue, + enum usb_raw_event_type type, size_t length, const void *data) +{ + unsigned long flags; + struct usb_raw_event *event; + + spin_lock_irqsave(&queue->lock, flags); + if (WARN_ON(queue->size >= RAW_EVENT_QUEUE_SIZE)) { + spin_unlock_irqrestore(&queue->lock, flags); + return -ENOMEM; + } + event = kmalloc(sizeof(*event) + length, GFP_ATOMIC); + if (!event) { + spin_unlock_irqrestore(&queue->lock, flags); + return -ENOMEM; + } + event->type = type; + event->length = length; + if (event->length) + memcpy(&event->data[0], data, length); + queue->events[queue->size] = event; + queue->size++; + up(&queue->sema); + spin_unlock_irqrestore(&queue->lock, flags); + return 0; +} + +static struct usb_raw_event *raw_event_queue_fetch( + struct raw_event_queue *queue) +{ + unsigned long flags; + struct usb_raw_event *event; + + /* + * This function can be called concurrently. We first check that + * there's at least one event queued by decrementing the semaphore, + * and then take the lock to protect queue struct fields. + */ + if (down_interruptible(&queue->sema)) + return NULL; + spin_lock_irqsave(&queue->lock, flags); + if (WARN_ON(!queue->size)) + return NULL; + event = queue->events[0]; + queue->size--; + memmove(&queue->events[0], &queue->events[1], + queue->size * sizeof(queue->events[0])); + spin_unlock_irqrestore(&queue->lock, flags); + return event; +} + +static void raw_event_queue_destroy(struct raw_event_queue *queue) +{ + int i; + + for (i = 0; i < queue->size; i++) + kfree(queue->events[i]); + queue->size = 0; +} + +/*----------------------------------------------------------------------*/ + +struct raw_dev; + +#define USB_RAW_MAX_ENDPOINTS 32 + +enum ep_state { + STATE_EP_DISABLED, + STATE_EP_ENABLED, +}; + +struct raw_ep { + struct raw_dev *dev; + enum ep_state state; + struct usb_ep *ep; + struct usb_request *req; + bool urb_queued; + bool disabling; + ssize_t status; +}; + +enum dev_state { + STATE_DEV_INVALID = 0, + STATE_DEV_OPENED, + STATE_DEV_INITIALIZED, + STATE_DEV_RUNNING, + STATE_DEV_CLOSED, + STATE_DEV_FAILED +}; + +struct raw_dev { + struct kref count; + spinlock_t lock; + + const char *udc_name; + struct usb_gadget_driver driver; + + /* Reference to misc device: */ + struct device *dev; + + /* Protected by lock: */ + enum dev_state state; + bool gadget_registered; + struct usb_gadget *gadget; + struct usb_request *req; + bool ep0_in_pending; + bool ep0_out_pending; + bool ep0_urb_queued; + ssize_t ep0_status; + struct raw_ep eps[USB_RAW_MAX_ENDPOINTS]; + + struct completion ep0_done; + struct raw_event_queue queue; +}; + +static struct raw_dev *dev_new(void) +{ + struct raw_dev *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + /* Matches kref_put() in raw_release(). */ + kref_init(&dev->count); + spin_lock_init(&dev->lock); + init_completion(&dev->ep0_done); + raw_event_queue_init(&dev->queue); + return dev; +} + +static void dev_free(struct kref *kref) +{ + struct raw_dev *dev = container_of(kref, struct raw_dev, count); + int i; + + kfree(dev->udc_name); + kfree(dev->driver.udc_name); + if (dev->req) { + if (dev->ep0_urb_queued) + usb_ep_dequeue(dev->gadget->ep0, dev->req); + usb_ep_free_request(dev->gadget->ep0, dev->req); + } + raw_event_queue_destroy(&dev->queue); + for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) { + if (dev->eps[i].state != STATE_EP_ENABLED) + continue; + usb_ep_disable(dev->eps[i].ep); + usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req); + kfree(dev->eps[i].ep->desc); + dev->eps[i].state = STATE_EP_DISABLED; + } + kfree(dev); +} + +/*----------------------------------------------------------------------*/ + +static int raw_queue_event(struct raw_dev *dev, + enum usb_raw_event_type type, size_t length, const void *data) +{ + int ret = 0; + unsigned long flags; + + ret = raw_event_queue_add(&dev->queue, type, length, data); + if (ret < 0) { + spin_lock_irqsave(&dev->lock, flags); + dev->state = STATE_DEV_FAILED; + spin_unlock_irqrestore(&dev->lock, flags); + } + return ret; +} + +static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct raw_dev *dev = req->context; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (req->status) + dev->ep0_status = req->status; + else + dev->ep0_status = req->actual; + if (dev->ep0_in_pending) + dev->ep0_in_pending = false; + else + dev->ep0_out_pending = false; + spin_unlock_irqrestore(&dev->lock, flags); + + complete(&dev->ep0_done); +} + +static int gadget_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + int ret = 0; + struct raw_dev *dev = container_of(driver, struct raw_dev, driver); + struct usb_request *req; + unsigned long flags; + + if (strcmp(gadget->name, dev->udc_name) != 0) + return -ENODEV; + + set_gadget_data(gadget, dev); + req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); + if (!req) { + dev_err(&gadget->dev, "usb_ep_alloc_request failed\n"); + set_gadget_data(gadget, NULL); + return -ENOMEM; + } + + spin_lock_irqsave(&dev->lock, flags); + dev->req = req; + dev->req->context = dev; + dev->req->complete = gadget_ep0_complete; + dev->gadget = gadget; + spin_unlock_irqrestore(&dev->lock, flags); + + /* Matches kref_put() in gadget_unbind(). */ + kref_get(&dev->count); + + ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL); + if (ret < 0) + dev_err(&gadget->dev, "failed to queue event\n"); + + return ret; +} + +static void gadget_unbind(struct usb_gadget *gadget) +{ + struct raw_dev *dev = get_gadget_data(gadget); + + set_gadget_data(gadget, NULL); + /* Matches kref_get() in gadget_bind(). */ + kref_put(&dev->count, dev_free); +} + +static int gadget_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl) +{ + int ret = 0; + struct raw_dev *dev = get_gadget_data(gadget); + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_err(&gadget->dev, "ignoring, device is not running\n"); + ret = -ENODEV; + goto out_unlock; + } + if (dev->ep0_in_pending || dev->ep0_out_pending) { + dev_dbg(&gadget->dev, "stalling, request already pending\n"); + ret = -EBUSY; + goto out_unlock; + } + if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength) + dev->ep0_in_pending = true; + else + dev->ep0_out_pending = true; + spin_unlock_irqrestore(&dev->lock, flags); + + ret = raw_queue_event(dev, USB_RAW_EVENT_CONTROL, sizeof(*ctrl), ctrl); + if (ret < 0) + dev_err(&gadget->dev, "failed to queue event\n"); + goto out; + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); +out: + return ret; +} + +/* These are currently unused but present in case UDC driver requires them. */ +static void gadget_disconnect(struct usb_gadget *gadget) { } +static void gadget_suspend(struct usb_gadget *gadget) { } +static void gadget_resume(struct usb_gadget *gadget) { } +static void gadget_reset(struct usb_gadget *gadget) { } + +/*----------------------------------------------------------------------*/ + +static struct miscdevice raw_misc_device; + +static int raw_open(struct inode *inode, struct file *fd) +{ + struct raw_dev *dev; + + /* Nonblocking I/O is not supported yet. */ + if (fd->f_flags & O_NONBLOCK) + return -EINVAL; + + dev = dev_new(); + if (!dev) + return -ENOMEM; + fd->private_data = dev; + dev->state = STATE_DEV_OPENED; + dev->dev = raw_misc_device.this_device; + return 0; +} + +static int raw_release(struct inode *inode, struct file *fd) +{ + int ret = 0; + struct raw_dev *dev = fd->private_data; + unsigned long flags; + bool unregister = false; + + spin_lock_irqsave(&dev->lock, flags); + dev->state = STATE_DEV_CLOSED; + if (!dev->gadget) { + spin_unlock_irqrestore(&dev->lock, flags); + goto out_put; + } + if (dev->gadget_registered) + unregister = true; + dev->gadget_registered = false; + spin_unlock_irqrestore(&dev->lock, flags); + + if (unregister) { + ret = usb_gadget_unregister_driver(&dev->driver); + if (ret != 0) + dev_err(dev->dev, + "usb_gadget_unregister_driver() failed with %d\n", + ret); + /* Matches kref_get() in raw_ioctl_run(). */ + kref_put(&dev->count, dev_free); + } + +out_put: + /* Matches dev_new() in raw_open(). */ + kref_put(&dev->count, dev_free); + return ret; +} + +/*----------------------------------------------------------------------*/ + +static int raw_ioctl_init(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + struct usb_raw_init arg; + char *udc_driver_name; + char *udc_device_name; + unsigned long flags; + + ret = copy_from_user(&arg, (void __user *)value, sizeof(arg)); + if (ret) + return ret; + + switch (arg.speed) { + case USB_SPEED_UNKNOWN: + arg.speed = USB_SPEED_HIGH; + break; + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: + return -EINVAL; + } + + udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL); + if (!udc_driver_name) + return -ENOMEM; + ret = strscpy(udc_driver_name, &arg.driver_name[0], + UDC_NAME_LENGTH_MAX); + if (ret < 0) { + kfree(udc_driver_name); + return ret; + } + ret = 0; + + udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL); + if (!udc_device_name) { + kfree(udc_driver_name); + return -ENOMEM; + } + ret = strscpy(udc_device_name, &arg.device_name[0], + UDC_NAME_LENGTH_MAX); + if (ret < 0) { + kfree(udc_driver_name); + kfree(udc_device_name); + return ret; + } + ret = 0; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_OPENED) { + dev_dbg(dev->dev, "fail, device is not opened\n"); + kfree(udc_driver_name); + kfree(udc_device_name); + ret = -EINVAL; + goto out_unlock; + } + dev->udc_name = udc_driver_name; + + dev->driver.function = DRIVER_DESC; + dev->driver.max_speed = arg.speed; + dev->driver.setup = gadget_setup; + dev->driver.disconnect = gadget_disconnect; + dev->driver.bind = gadget_bind; + dev->driver.unbind = gadget_unbind; + dev->driver.suspend = gadget_suspend; + dev->driver.resume = gadget_resume; + dev->driver.reset = gadget_reset; + dev->driver.driver.name = DRIVER_NAME; + dev->driver.udc_name = udc_device_name; + dev->driver.match_existing_only = 1; + + dev->state = STATE_DEV_INITIALIZED; + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int raw_ioctl_run(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + unsigned long flags; + + if (value) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_INITIALIZED) { + dev_dbg(dev->dev, "fail, device is not initialized\n"); + ret = -EINVAL; + goto out_unlock; + } + spin_unlock_irqrestore(&dev->lock, flags); + + ret = usb_gadget_probe_driver(&dev->driver); + + spin_lock_irqsave(&dev->lock, flags); + if (ret) { + dev_err(dev->dev, + "fail, usb_gadget_probe_driver returned %d\n", ret); + dev->state = STATE_DEV_FAILED; + goto out_unlock; + } + dev->gadget_registered = true; + dev->state = STATE_DEV_RUNNING; + /* Matches kref_put() in raw_release(). */ + kref_get(&dev->count); + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + struct usb_raw_event arg; + unsigned long flags; + struct usb_raw_event *event; + uint32_t length; + + ret = copy_from_user(&arg, (void __user *)value, sizeof(arg)); + if (ret) + return ret; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + spin_unlock_irqrestore(&dev->lock, flags); + return -EINVAL; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + spin_unlock_irqrestore(&dev->lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&dev->lock, flags); + + event = raw_event_queue_fetch(&dev->queue); + if (!event) { + dev_dbg(&dev->gadget->dev, "event fetching interrupted\n"); + return -EINTR; + } + length = min(arg.length, event->length); + ret = copy_to_user((void __user *)value, event, + sizeof(*event) + length); + return ret; +} + +static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr, + bool get_from_user) +{ + int ret; + void *data; + + ret = copy_from_user(io, ptr, sizeof(*io)); + if (ret) + return ERR_PTR(ret); + if (io->ep >= USB_RAW_MAX_ENDPOINTS) + return ERR_PTR(-EINVAL); + if (!usb_raw_io_flags_valid(io->flags)) + return ERR_PTR(-EINVAL); + if (io->length > PAGE_SIZE) + return ERR_PTR(-EINVAL); + if (get_from_user) + data = memdup_user(ptr + sizeof(*io), io->length); + else { + data = kmalloc(io->length, GFP_KERNEL); + if (!data) + data = ERR_PTR(-ENOMEM); + } + return data; +} + +static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, + void *data, bool in) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + if (dev->ep0_urb_queued) { + dev_dbg(&dev->gadget->dev, "fail, urb already queued\n"); + ret = -EBUSY; + goto out_unlock; + } + if ((in && !dev->ep0_in_pending) || + (!in && !dev->ep0_out_pending)) { + dev_dbg(&dev->gadget->dev, "fail, wrong direction\n"); + ret = -EBUSY; + goto out_unlock; + } + if (WARN_ON(in && dev->ep0_out_pending)) { + ret = -ENODEV; + dev->state = STATE_DEV_FAILED; + goto out_done; + } + if (WARN_ON(!in && dev->ep0_in_pending)) { + ret = -ENODEV; + dev->state = STATE_DEV_FAILED; + goto out_done; + } + + dev->req->buf = data; + dev->req->length = io->length; + dev->req->zero = usb_raw_io_flags_zero(io->flags); + dev->ep0_urb_queued = true; + spin_unlock_irqrestore(&dev->lock, flags); + + ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL); + if (ret) { + dev_err(&dev->gadget->dev, + "fail, usb_ep_queue returned %d\n", ret); + spin_lock_irqsave(&dev->lock, flags); + dev->state = STATE_DEV_FAILED; + goto out_done; + } + + ret = wait_for_completion_interruptible(&dev->ep0_done); + if (ret) { + dev_dbg(&dev->gadget->dev, "wait interrupted\n"); + usb_ep_dequeue(dev->gadget->ep0, dev->req); + wait_for_completion(&dev->ep0_done); + spin_lock_irqsave(&dev->lock, flags); + goto out_done; + } + + spin_lock_irqsave(&dev->lock, flags); + ret = dev->ep0_status; + +out_done: + dev->ep0_urb_queued = false; +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + void *data; + struct usb_raw_ep_io io; + + data = raw_alloc_io_data(&io, (void __user *)value, true); + if (IS_ERR(data)) + return PTR_ERR(data); + ret = raw_process_ep0_io(dev, &io, data, true); + kfree(data); + return ret; +} + +static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + void *data; + struct usb_raw_ep_io io; + unsigned int length; + + data = raw_alloc_io_data(&io, (void __user *)value, false); + if (IS_ERR(data)) + return PTR_ERR(data); + ret = raw_process_ep0_io(dev, &io, data, false); + if (ret < 0) { + kfree(data); + return ret; + } + length = min(io.length, (unsigned int)ret); + ret = copy_to_user((void __user *)(value + sizeof(io)), data, length); + kfree(data); + return ret; +} + +static bool check_ep_caps(struct usb_ep *ep, + struct usb_endpoint_descriptor *desc) +{ + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return false; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return false; + break; + case USB_ENDPOINT_XFER_INT: + if (!ep->caps.type_int) + return false; + break; + default: + return false; + } + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return false; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return false; + + return true; +} + +static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value) +{ + int ret = 0, i; + unsigned long flags; + struct usb_endpoint_descriptor *desc; + struct usb_ep *ep = NULL; + + desc = memdup_user((void __user *)value, sizeof(*desc)); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + /* + * Endpoints with a maxpacket length of 0 can cause crashes in UDC + * drivers. + */ + if (usb_endpoint_maxp(desc) == 0) { + dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n"); + kfree(desc); + return -EINVAL; + } + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_free; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_free; + } + + for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) { + if (dev->eps[i].state == STATE_EP_ENABLED) + continue; + break; + } + if (i == USB_RAW_MAX_ENDPOINTS) { + dev_dbg(&dev->gadget->dev, + "fail, no device endpoints available\n"); + ret = -EBUSY; + goto out_free; + } + + gadget_for_each_ep(ep, dev->gadget) { + if (ep->enabled) + continue; + if (!check_ep_caps(ep, desc)) + continue; + ep->desc = desc; + ret = usb_ep_enable(ep); + if (ret < 0) { + dev_err(&dev->gadget->dev, + "fail, usb_ep_enable returned %d\n", ret); + goto out_free; + } + dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (!dev->eps[i].req) { + dev_err(&dev->gadget->dev, + "fail, usb_ep_alloc_request failed\n"); + usb_ep_disable(ep); + ret = -ENOMEM; + goto out_free; + } + dev->eps[i].ep = ep; + dev->eps[i].state = STATE_EP_ENABLED; + ep->driver_data = &dev->eps[i]; + ret = i; + goto out_unlock; + } + + dev_dbg(&dev->gadget->dev, "fail, no gadget endpoints available\n"); + ret = -EBUSY; + +out_free: + kfree(desc); +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) +{ + int ret = 0, i = value; + unsigned long flags; + const void *desc; + + if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + if (dev->eps[i].state != STATE_EP_ENABLED) { + dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); + ret = -EINVAL; + goto out_unlock; + } + if (dev->eps[i].disabling) { + dev_dbg(&dev->gadget->dev, + "fail, disable already in progress\n"); + ret = -EINVAL; + goto out_unlock; + } + if (dev->eps[i].urb_queued) { + dev_dbg(&dev->gadget->dev, + "fail, waiting for urb completion\n"); + ret = -EINVAL; + goto out_unlock; + } + dev->eps[i].disabling = true; + spin_unlock_irqrestore(&dev->lock, flags); + + usb_ep_disable(dev->eps[i].ep); + + spin_lock_irqsave(&dev->lock, flags); + usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req); + desc = dev->eps[i].ep->desc; + dev->eps[i].ep = NULL; + dev->eps[i].state = STATE_EP_DISABLED; + kfree(desc); + dev->eps[i].disabling = false; + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data; + struct raw_dev *dev = r_ep->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (req->status) + r_ep->status = req->status; + else + r_ep->status = req->actual; + spin_unlock_irqrestore(&dev->lock, flags); + + complete((struct completion *)req->context); +} + +static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io, + void *data, bool in) +{ + int ret = 0; + unsigned long flags; + struct raw_ep *ep = &dev->eps[io->ep]; + DECLARE_COMPLETION_ONSTACK(done); + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + if (ep->state != STATE_EP_ENABLED) { + dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); + ret = -EBUSY; + goto out_unlock; + } + if (ep->disabling) { + dev_dbg(&dev->gadget->dev, + "fail, endpoint is already being disabled\n"); + ret = -EBUSY; + goto out_unlock; + } + if (ep->urb_queued) { + dev_dbg(&dev->gadget->dev, "fail, urb already queued\n"); + ret = -EBUSY; + goto out_unlock; + } + if ((in && !ep->ep->caps.dir_in) || (!in && ep->ep->caps.dir_in)) { + dev_dbg(&dev->gadget->dev, "fail, wrong direction\n"); + ret = -EINVAL; + goto out_unlock; + } + + ep->dev = dev; + ep->req->context = &done; + ep->req->complete = gadget_ep_complete; + ep->req->buf = data; + ep->req->length = io->length; + ep->req->zero = usb_raw_io_flags_zero(io->flags); + ep->urb_queued = true; + spin_unlock_irqrestore(&dev->lock, flags); + + ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL); + if (ret) { + dev_err(&dev->gadget->dev, + "fail, usb_ep_queue returned %d\n", ret); + spin_lock_irqsave(&dev->lock, flags); + dev->state = STATE_DEV_FAILED; + goto out_done; + } + + ret = wait_for_completion_interruptible(&done); + if (ret) { + dev_dbg(&dev->gadget->dev, "wait interrupted\n"); + usb_ep_dequeue(ep->ep, ep->req); + wait_for_completion(&done); + spin_lock_irqsave(&dev->lock, flags); + goto out_done; + } + + spin_lock_irqsave(&dev->lock, flags); + ret = ep->status; + +out_done: + ep->urb_queued = false; +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + char *data; + struct usb_raw_ep_io io; + + data = raw_alloc_io_data(&io, (void __user *)value, true); + if (IS_ERR(data)) + return PTR_ERR(data); + ret = raw_process_ep_io(dev, &io, data, true); + kfree(data); + return ret; +} + +static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + char *data; + struct usb_raw_ep_io io; + unsigned int length; + + data = raw_alloc_io_data(&io, (void __user *)value, false); + if (IS_ERR(data)) + return PTR_ERR(data); + ret = raw_process_ep_io(dev, &io, data, false); + if (ret < 0) { + kfree(data); + return ret; + } + length = min(io.length, (unsigned int)ret); + ret = copy_to_user((void __user *)(value + sizeof(io)), data, length); + kfree(data); + return ret; +} + +static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + unsigned long flags; + + if (value) + return -EINVAL; + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED); + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + usb_gadget_vbus_draw(dev->gadget, 2 * value); + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value) +{ + struct raw_dev *dev = fd->private_data; + int ret = 0; + + if (!dev) + return -EBUSY; + + switch (cmd) { + case USB_RAW_IOCTL_INIT: + ret = raw_ioctl_init(dev, value); + break; + case USB_RAW_IOCTL_RUN: + ret = raw_ioctl_run(dev, value); + break; + case USB_RAW_IOCTL_EVENT_FETCH: + ret = raw_ioctl_event_fetch(dev, value); + break; + case USB_RAW_IOCTL_EP0_WRITE: + ret = raw_ioctl_ep0_write(dev, value); + break; + case USB_RAW_IOCTL_EP0_READ: + ret = raw_ioctl_ep0_read(dev, value); + break; + case USB_RAW_IOCTL_EP_ENABLE: + ret = raw_ioctl_ep_enable(dev, value); + break; + case USB_RAW_IOCTL_EP_DISABLE: + ret = raw_ioctl_ep_disable(dev, value); + break; + case USB_RAW_IOCTL_EP_WRITE: + ret = raw_ioctl_ep_write(dev, value); + break; + case USB_RAW_IOCTL_EP_READ: + ret = raw_ioctl_ep_read(dev, value); + break; + case USB_RAW_IOCTL_CONFIGURE: + ret = raw_ioctl_configure(dev, value); + break; + case USB_RAW_IOCTL_VBUS_DRAW: + ret = raw_ioctl_vbus_draw(dev, value); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/*----------------------------------------------------------------------*/ + +static const struct file_operations raw_fops = { + .open = raw_open, + .unlocked_ioctl = raw_ioctl, + .compat_ioctl = raw_ioctl, + .release = raw_release, + .llseek = no_llseek, +}; + +static struct miscdevice raw_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRIVER_NAME, + .fops = &raw_fops, +}; + +module_misc_device(raw_misc_device); diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index bfd8f7ade9351b5f933525b90dd06d7ee547248d..be9f40bc9c12b93be4ca5797031d87b40a5fdcd2 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -546,7 +546,7 @@ static void bdc_req_complete(struct bdc_ep *ep, struct bdc_req *req, { struct bdc *bdc = ep->bdc; - if (req == NULL || &req->queue == NULL || &req->usb_req == NULL) + if (req == NULL) return; dev_dbg(bdc->dev, "%s ep:%s status:%d\n", __func__, ep->name, status); diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index 1f9941145746ee4d8b8130d4721e2fb2720fae54..feb73a1c42ef9ca554c3a5136045b37411a7eda5 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -2200,8 +2200,6 @@ static int gr_probe(struct platform_device *pdev) return -ENOMEM; } - spin_lock(&dev->lock); - /* Inside lock so that no gadget can use this udc until probe is done */ retval = usb_add_gadget_udc(dev->dev, &dev->gadget); if (retval) { @@ -2210,15 +2208,21 @@ static int gr_probe(struct platform_device *pdev) } dev->added = 1; + spin_lock(&dev->lock); + retval = gr_udc_init(dev); - if (retval) + if (retval) { + spin_unlock(&dev->lock); goto out; - - gr_dfs_create(dev); + } /* Clear all interrupt enables that might be left on since last boot */ gr_disable_interrupts_and_pullup(dev); + spin_unlock(&dev->lock); + + gr_dfs_create(dev); + retval = gr_request_irq(dev, dev->irq); if (retval) { dev_err(dev->dev, "Failed to request irq %d\n", dev->irq); @@ -2247,8 +2251,6 @@ static int gr_probe(struct platform_device *pdev) dev_info(dev->dev, "regs: %p, irq %d\n", dev->regs, dev->irq); out: - spin_unlock(&dev->lock); - if (retval) gr_remove(pdev); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index f567fec65b505d688f0497ec3f733121eaf8a851..e6ba86defeaf6015c25dd3d7efbc339f18458338 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1479,14 +1479,15 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* Allow 3 retries for everything but isoc, set CErr = 3 */ if (!usb_endpoint_xfer_isoc(&ep->desc)) err_count = 3; - /* Some devices get this wrong */ - if (usb_endpoint_xfer_bulk(&ep->desc) && udev->speed == USB_SPEED_HIGH) - max_packet = 512; - - if (usb_endpoint_xfer_bulk(&ep->desc) && udev->speed == USB_SPEED_FULL - && max_packet < 8) - max_packet = 8; - + /* HS bulk max packet should be 512, FS bulk supports 8, 16, 32 or 64 */ + if (usb_endpoint_xfer_bulk(&ep->desc)) { + if (udev->speed == USB_SPEED_HIGH) + max_packet = 512; + if (udev->speed == USB_SPEED_FULL) { + max_packet = rounddown_pow_of_two(max_packet); + max_packet = clamp_val(max_packet, 8, 64); + } + } /* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */ if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100) avg_trb_len = 8; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 09f228279c01224285f44ea1aceb29d5a32c471c..c01a0d1e8b5ccb40b7b06a65fc96b7a93c2de90f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -53,6 +53,7 @@ #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 +#define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba @@ -139,7 +140,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_AMD_PLL_FIX; if (pdev->vendor == PCI_VENDOR_ID_AMD && - (pdev->device == 0x15e0 || + (pdev->device == 0x145c || + pdev->device == 0x15e0 || pdev->device == 0x15e1 || pdev->device == 0x43bb)) xhci->quirks |= XHCI_SUSPEND_DELAY; @@ -191,7 +193,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) { + pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_CML_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && @@ -284,6 +287,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd) if (!usb_hcd_is_primary_hcd(hcd)) return 0; + if (xhci->quirks & XHCI_PME_STUCK_QUIRK) + xhci_pme_acpi_rtd3_enable(pdev); + xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); /* Find any debug ports */ @@ -344,9 +350,6 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; - if (xhci->quirks & XHCI_PME_STUCK_QUIRK) - xhci_pme_acpi_rtd3_enable(dev); - /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ pm_runtime_put_noidle(&dev->dev); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 85b3c924f25a8c0bab78bca0ceb7b1df549573e1..6102ac50d753e96d0aa65280421687bcec31d227 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -592,6 +592,7 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xhci-hcd", .pm = &xhci_plat_pm_ops, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 37dfef107d3ce5a49ee49f82d48be3724cd4771d..0ece43c0cf112e0adf20280cc0249852956505b1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1640,6 +1640,12 @@ static void handle_port_status(struct xhci_hcd *xhci, if ((major_revision == 0x03) != (hcd->speed >= HCD_USB3)) hcd = xhci->shared_hcd; + if (!hcd) { + xhci_dbg(xhci, "No hcd found for port %u event\n", port_id); + bogus_port_status = true; + goto cleanup; + } + if (major_revision == 0) { xhci_warn(xhci, "Event for port %u not in " "Extended Capabilities, ignoring.\n", @@ -2758,6 +2764,42 @@ static int xhci_handle_event(struct xhci_hcd *xhci) return 1; } +/* + * Update Event Ring Dequeue Pointer: + * - When all events have finished + * - To avoid "Event Ring Full Error" condition + */ +static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + union xhci_trb *event_ring_deq) +{ + u64 temp_64; + dma_addr_t deq; + + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + /* If necessary, update the HW's version of the event ring deq ptr. */ + if (event_ring_deq != xhci->event_ring->dequeue) { + deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, + xhci->event_ring->dequeue); + if (deq == 0) + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n"); + /* + * Per 4.9.4, Software writes to the ERDP register shall + * always advance the Event Ring Dequeue Pointer value. + */ + if ((temp_64 & (u64) ~ERST_PTR_MASK) == + ((u64) deq & (u64) ~ERST_PTR_MASK)) + return; + + /* Update HC event ring dequeue pointer */ + temp_64 &= ERST_PTR_MASK; + temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); + } + + /* Clear the event handler busy flag (RW1C) */ + temp_64 |= ERST_EHB; + xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); +} + /* * xHCI spec says we can get an interrupt, and if the HC has an error condition, * we might get bad data out of the event ring. Section 4.10.2.7 has a list of @@ -2769,9 +2811,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) union xhci_trb *event_ring_deq; irqreturn_t ret = IRQ_NONE; unsigned long flags; - dma_addr_t deq; u64 temp_64; u32 status; + int event_loop = 0; spin_lock_irqsave(&xhci->lock, flags); /* Check if the xHC generated the interrupt, or the irq is shared */ @@ -2825,24 +2867,14 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) /* FIXME this should be a delayed service routine * that clears the EHB. */ - while (xhci_handle_event(xhci) > 0) {} - - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - /* If necessary, update the HW's version of the event ring deq ptr. */ - if (event_ring_deq != xhci->event_ring->dequeue) { - deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, - xhci->event_ring->dequeue); - if (deq == 0) - xhci_warn(xhci, "WARN something wrong with SW event " - "ring dequeue ptr.\n"); - /* Update HC event ring dequeue pointer */ - temp_64 &= ERST_PTR_MASK; - temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); + while (xhci_handle_event(xhci) > 0) { + if (event_loop++ < TRBS_PER_SEGMENT / 2) + continue; + xhci_update_erst_dequeue(xhci, event_ring_deq); + event_loop = 0; } - /* Clear the event handler busy flag (RW1C); event ring is empty. */ - temp_64 |= ERST_EHB; - xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); + xhci_update_erst_dequeue(xhci, event_ring_deq); ret = IRQ_HANDLED; out: diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 1eedf99969594b0d87c7344086d691f010af47a0..a98b5ab628f46c29a3406e3bc18d453a2faebb16 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -276,23 +276,12 @@ DECLARE_EVENT_CLASS(xhci_log_urb, ), TP_printk("ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x", __entry->epnum, __entry->dir_in ? "in" : "out", - ({ char *s; - switch (__entry->type) { - case USB_ENDPOINT_XFER_INT: - s = "intr"; - break; - case USB_ENDPOINT_XFER_CONTROL: - s = "control"; - break; - case USB_ENDPOINT_XFER_BULK: - s = "bulk"; - break; - case USB_ENDPOINT_XFER_ISOC: - s = "isoc"; - break; - default: - s = "UNKNOWN"; - } s; }), __entry->urb, __entry->pipe, __entry->slot_id, + __print_symbolic(__entry->type, + { USB_ENDPOINT_XFER_INT, "intr" }, + { USB_ENDPOINT_XFER_CONTROL, "control" }, + { USB_ENDPOINT_XFER_BULK, "bulk" }, + { USB_ENDPOINT_XFER_ISOC, "isoc" }), + __entry->urb, __entry->pipe, __entry->slot_id, __entry->actual, __entry->length, __entry->num_mapped_sgs, __entry->num_sgs, __entry->stream, __entry->flags ) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 76c839717f16d3375137fc541d0dae90a2badae9..4c6519248b11e5d394a96510d645629c8d08f1a8 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1633,7 +1633,7 @@ struct urb_priv { * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, * meaning 64 ring segments. * Initial allocated size of the ERST, in number of entries */ -#define ERST_NUM_SEGS 1 +#define ERST_NUM_SEGS 4 /* Initial allocated size of the ERST, in number of entries */ #define ERST_SIZE 64 /* Initial number of event segment rings allocated */ diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 7f226cc3ef8a5953dbafbc1a08c60435aad636c7..1ec32e5aa004cb56fbc2bcacbc0e1aaa9dea55cb 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -32,6 +32,14 @@ #define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512 /* full speed iowarrior */ #define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503 +/* fuller speed iowarrior */ +#define USB_DEVICE_ID_CODEMERCS_IOW28 0x1504 +#define USB_DEVICE_ID_CODEMERCS_IOW28L 0x1505 +#define USB_DEVICE_ID_CODEMERCS_IOW100 0x1506 + +/* OEMed devices */ +#define USB_DEVICE_ID_CODEMERCS_IOW24SAG 0x158a +#define USB_DEVICE_ID_CODEMERCS_IOW56AM 0x158b /* Get a minor range for your devices from the usb maintainer */ #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -137,6 +145,11 @@ static const struct usb_device_id iowarrior_ids[] = { {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)}, {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)}, {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24SAG)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56AM)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28L)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW100)}, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, iowarrior_ids); @@ -364,6 +377,7 @@ static ssize_t iowarrior_write(struct file *file, } switch (dev->product_id) { case USB_DEVICE_ID_CODEMERCS_IOW24: + case USB_DEVICE_ID_CODEMERCS_IOW24SAG: case USB_DEVICE_ID_CODEMERCS_IOWPV1: case USB_DEVICE_ID_CODEMERCS_IOWPV2: case USB_DEVICE_ID_CODEMERCS_IOW40: @@ -378,6 +392,10 @@ static ssize_t iowarrior_write(struct file *file, goto exit; break; case USB_DEVICE_ID_CODEMERCS_IOW56: + case USB_DEVICE_ID_CODEMERCS_IOW56AM: + case USB_DEVICE_ID_CODEMERCS_IOW28: + case USB_DEVICE_ID_CODEMERCS_IOW28L: + case USB_DEVICE_ID_CODEMERCS_IOW100: /* The IOW56 uses asynchronous IO and more urbs */ if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { /* Wait until we are below the limit for submitted urbs */ @@ -502,6 +520,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case IOW_WRITE: if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24SAG || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { @@ -786,7 +805,11 @@ static int iowarrior_probe(struct usb_interface *interface, goto error; } - if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) { + if ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)) { res = usb_find_last_int_out_endpoint(iface_desc, &dev->int_out_endpoint); if (res) { @@ -799,7 +822,11 @@ static int iowarrior_probe(struct usb_interface *interface, /* we have to check the report_size often, so remember it in the endianness suitable for our machine */ dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && - (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56)) + ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100))) /* IOWarrior56 has wMaxPacketSize different from report size */ dev->report_size = 7; diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c index 9bd5a1f00d3fd2de665408de943906fa6571b250..3cc96fa06628dd5c25fe51f7ac017fad474a2265 100644 --- a/drivers/usb/misc/mdm_data_bridge.c +++ b/drivers/usb/misc/mdm_data_bridge.c @@ -863,6 +863,12 @@ bridge_probe(struct usb_interface *iface, const struct usb_device_id *id) return -EINVAL; } + if (devid == USB_BRIDGE_DIAG && + udev->actconfig->desc.bNumInterfaces == 1) { + pr_err("Invalid configuration: Only one interface\n"); + return -EINVAL; + } + num_eps = iface->cur_altsetting->desc.bNumEndpoints; for (i = 0; i < num_eps; i++) { endpoint = iface->cur_altsetting->endpoint + i; diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 3121fa31aabf93a64448d1852466e717e54e7f9e..a6f88442a53a92f6be78f35d766215aa6c87808f 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1198,18 +1198,18 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, /* High level: Gfx (indexed) register access */ #ifdef INCL_SISUSB_CON -int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data) +int sisusb_setreg(struct sisusb_usb_data *sisusb, u32 port, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); } -int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data) +int sisusb_getreg(struct sisusb_usb_data *sisusb, u32 port, u8 *data) { return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); } #endif -int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, +int sisusb_setidxreg(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 data) { int ret; @@ -1219,7 +1219,7 @@ int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, return ret; } -int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, +int sisusb_getidxreg(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 *data) { int ret; @@ -1229,7 +1229,7 @@ int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, return ret; } -int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, +int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, u32 port, u8 idx, u8 myand, u8 myor) { int ret; @@ -1244,7 +1244,7 @@ int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, } static int sisusb_setidxregmask(struct sisusb_usb_data *sisusb, - int port, u8 idx, u8 data, u8 mask) + u32 port, u8 idx, u8 data, u8 mask) { int ret; u8 tmp; @@ -1257,13 +1257,13 @@ static int sisusb_setidxregmask(struct sisusb_usb_data *sisusb, return ret; } -int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, +int sisusb_setidxregor(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 myor) { return sisusb_setidxregandor(sisusb, port, index, 0xff, myor); } -int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, +int sisusb_setidxregand(struct sisusb_usb_data *sisusb, u32 port, u8 idx, u8 myand) { return sisusb_setidxregandor(sisusb, port, idx, myand, 0x00); @@ -2786,8 +2786,8 @@ static loff_t sisusb_lseek(struct file *file, loff_t offset, int orig) static int sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, unsigned long arg) { - int retval, port, length; - u32 address; + int retval, length; + u32 port, address; /* All our commands require the device * to be initialized. diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index e79a616f0d26ca6d33db4d9504dff49d45aaad33..f7182257f7e1e81d92da4acbdd9ae12509459117 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -811,17 +811,17 @@ static const struct SiS_VCLKData SiSUSB_VCLKData[] = { int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, u32 port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, u32 port, u8 * data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 * data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, u32 port, u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, u32 port, u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, u32 port, u8 idx, u8 myand); void sisusb_delete(struct kref *kref); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 802388bb42ba707ee4432456aaaf1718af151d9f..3ec0752e67ac6fd8a58f67c97842cff46fc72d59 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1494,10 +1494,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) * We need to map sg if the transfer_buffer is * NULL. */ - if (!urb->transfer_buffer) - qh->use_sg = true; - - if (qh->use_sg) { + if (!urb->transfer_buffer) { /* sg_miter_start is already done in musb_ep_program */ if (!sg_miter_next(&qh->sg_miter)) { dev_err(musb->controller, "error: sg list empty\n"); @@ -1505,9 +1502,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) status = -EINVAL; goto done; } - urb->transfer_buffer = qh->sg_miter.addr; length = min_t(u32, length, qh->sg_miter.length); - musb_write_fifo(hw_ep, length, urb->transfer_buffer); + musb_write_fifo(hw_ep, length, qh->sg_miter.addr); qh->sg_miter.consumed = length; sg_miter_stop(&qh->sg_miter); } else { @@ -1516,11 +1512,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) qh->segsize = length; - if (qh->use_sg) { - if (offset + length >= urb->transfer_buffer_length) - qh->use_sg = false; - } - musb_ep_select(mbase, epnum); musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); @@ -2038,8 +2029,10 @@ void musb_host_rx(struct musb *musb, u8 epnum) urb->actual_length += xfer_len; qh->offset += xfer_len; if (done) { - if (qh->use_sg) + if (qh->use_sg) { qh->use_sg = false; + urb->transfer_buffer = NULL; + } if (urb->status == -EINPROGRESS) urb->status = status; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 456f3e6ecf034b31cee97f734753055524c38fa2..26e69c2766f560e17930b7b4d11ddb77d3ef4af6 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -388,8 +388,6 @@ static const struct musb_platform_ops omap2430_ops = { .init = omap2430_musb_init, .exit = omap2430_musb_exit, - .set_vbus = omap2430_musb_set_vbus, - .enable = omap2430_musb_enable, .disable = omap2430_musb_disable, diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 7e0e4d83f16b47f6de7d2522210145217943edf7..b7827f001b382d8601ab78b8b258c925c68c992b 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1869,10 +1869,12 @@ int usbpd_send_svdm(struct usbpd *pd, u16 svid, u8 cmd, enum usbpd_svdm_cmd_type cmd_type, int obj_pos, const u32 *vdos, int num_vdos) { - u32 svdm_hdr = SVDM_HDR(svid, 0, obj_pos, cmd_type, cmd); + u32 svdm_hdr = SVDM_HDR(svid, pd->spec_rev == USBPD_REV_30 ? 1 : 0, + obj_pos, cmd_type, cmd); - usbpd_dbg(&pd->dev, "VDM tx: svid:%x cmd:%x cmd_type:%x svdm_hdr:%x\n", - svid, cmd, cmd_type, svdm_hdr); + usbpd_dbg(&pd->dev, "VDM tx: svid:%04x ver:%d obj_pos:%d cmd:%x cmd_type:%x svdm_hdr:%x\n", + svid, pd->spec_rev == USBPD_REV_30 ? 1 : 0, obj_pos, + cmd, cmd_type, svdm_hdr); return usbpd_send_vdm(pd, svdm_hdr, vdos, num_vdos); } @@ -1902,7 +1904,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) ktime_t recvd_time = ktime_get(); usbpd_dbg(&pd->dev, - "VDM rx: svid:%x cmd:%x cmd_type:%x vdm_hdr:%x has_dp: %s\n", + "VDM rx: svid:%04x cmd:%x cmd_type:%x vdm_hdr:%x has_dp: %s\n", svid, cmd, cmd_type, vdm_hdr, pd->has_dp ? "true" : "false"); @@ -1930,11 +1932,9 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) return; } - if (SVDM_HDR_VER(vdm_hdr) > 1) { - usbpd_dbg(&pd->dev, "Discarding SVDM with incorrect version:%d\n", + if (SVDM_HDR_VER(vdm_hdr) > 1) + usbpd_dbg(&pd->dev, "Received SVDM with incorrect version:%d\n", SVDM_HDR_VER(vdm_hdr)); - return; - } if (cmd_type != SVDM_CMD_TYPE_INITIATOR && pd->current_state != PE_SRC_STARTUP_WAIT_FOR_VDM_RESP) diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c index 913c612c2abd6d23d9f79ab5fd40cb7d1fcd99c8..2bb473d2409b21dd3747fcef092fde08cbd3bf31 100644 --- a/drivers/usb/phy/phy-msm-snps-hs.c +++ b/drivers/usb/phy/phy-msm-snps-hs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -515,9 +515,17 @@ static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { /* Bus suspend */ - if (phy->cable_connected) { - /* Enable auto-resume functionality by pulsing signal */ - if (phy->phy.flags & PHY_HOST_MODE) { + if (phy->cable_connected || + (phy->phy.flags & PHY_HOST_MODE)) { + /* Enable auto-resume functionality only when + * there is some peripheral connected and real + * bus suspend happened + */ + if ((phy->phy.flags & PHY_HSFS_MODE) || + (phy->phy.flags & PHY_LS_MODE)) { + /* Enable auto-resume functionality by pulsing + * signal + */ msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2, USB2_AUTO_RESUME, USB2_AUTO_RESUME); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 3705b64ab948323740aaba443e8079ec5b1d8c97..45d5e5c899e1ff55128a3a9ffeaef029264ea236 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -714,7 +714,7 @@ static void edge_interrupt_callback(struct urb *urb) /* grab the txcredits for the ports if available */ position = 2; portNumber = 0; - while ((position < length) && + while ((position < length - 1) && (portNumber < edge_serial->serial->num_ports)) { txCredits = data[position] | (data[position+1] << 8); if (txCredits) { diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index eff353de47cd5b60a3b48d547eda970d48e84ff9..3621bde2a0ed7b064ac8069d953b8be0048cfb6b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1186,6 +1186,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff), /* Telit ME910G1 */ .driver_info = NCTRL(0) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110b, 0xff), /* Telit ME910G1 (ECM) */ + .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), @@ -1992,8 +1994,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */ + { USB_DEVICE_INTERFACE_CLASS(0x1435, 0xd191, 0xff), /* Wistron Neweb D19Q1 */ + .driver_info = RSVD(1) | RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(0x1690, 0x7588, 0xff), /* ASKEY WWHC050 */ + .driver_info = RSVD(1) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2031, 0xff), /* Olicard 600 */ .driver_info = RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2033, 0xff), /* BroadMobi BM806U */ + .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2060, 0xff), /* BroadMobi BM818 */ .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1c4d3dbd4635d4f1e1ce549946f62bd0fcdaa3a0..5051b1dad09eeb166ecb061dd12867995841d435 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -96,6 +96,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD381_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index fcc2cfc1da28d2d99b00645d20baa2085dd56534..f0a9eeb6272de7661baaa6d4b29dffb9308a24a9 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -129,6 +129,7 @@ #define HP_LM920_PRODUCT_ID 0x026b #define HP_TD620_PRODUCT_ID 0x0956 #define HP_LD960_PRODUCT_ID 0x0b39 +#define HP_LD381_PRODUCT_ID 0x0f7f #define HP_LCM220_PRODUCT_ID 0x3139 #define HP_LCM960_PRODUCT_ID 0x3239 #define HP_LD220_PRODUCT_ID 0x3524 diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 8391a88cf90f3446c5de267067fa0978dd72d883..20dd8df864c45ab75c056de8bcdd10beaa2f3454 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -46,6 +46,7 @@ struct uas_dev_info { struct scsi_cmnd *cmnd[MAX_CMNDS]; spinlock_t lock; struct work_struct work; + struct work_struct scan_work; /* for async scanning */ }; enum { @@ -81,6 +82,19 @@ static void uas_free_streams(struct uas_dev_info *devinfo); static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, int status); +/* + * This driver needs its own workqueue, as we need to control memory allocation. + * + * In the course of error handling and power management uas_wait_for_pending_cmnds() + * needs to flush pending work items. In these contexts we cannot allocate memory + * by doing block IO as we would deadlock. For the same reason we cannot wait + * for anything allocating memory not heeding these constraints. + * + * So we have to control all work items that can be on the workqueue we flush. + * Hence we cannot share a queue and need our own. + */ +static struct workqueue_struct *workqueue; + static void uas_do_work(struct work_struct *work) { struct uas_dev_info *devinfo = @@ -109,12 +123,23 @@ static void uas_do_work(struct work_struct *work) if (!err) cmdinfo->state &= ~IS_IN_WORK_LIST; else - schedule_work(&devinfo->work); + queue_work(workqueue, &devinfo->work); } out: spin_unlock_irqrestore(&devinfo->lock, flags); } +static void uas_scan_work(struct work_struct *work) +{ + struct uas_dev_info *devinfo = + container_of(work, struct uas_dev_info, scan_work); + struct Scsi_Host *shost = usb_get_intfdata(devinfo->intf); + + dev_dbg(&devinfo->intf->dev, "starting scan\n"); + scsi_scan_host(shost); + dev_dbg(&devinfo->intf->dev, "scan complete\n"); +} + static void uas_add_work(struct uas_cmd_info *cmdinfo) { struct scsi_pointer *scp = (void *)cmdinfo; @@ -123,7 +148,7 @@ static void uas_add_work(struct uas_cmd_info *cmdinfo) lockdep_assert_held(&devinfo->lock); cmdinfo->state |= IS_IN_WORK_LIST; - schedule_work(&devinfo->work); + queue_work(workqueue, &devinfo->work); } static void uas_zap_pending(struct uas_dev_info *devinfo, int result) @@ -179,6 +204,9 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, struct uas_cmd_info *ci = (void *)&cmnd->SCp; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; + if (status == -ENODEV) /* too late */ + return; + scmd_printk(KERN_INFO, cmnd, "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", prefix, status, cmdinfo->uas_tag, @@ -989,6 +1017,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) init_usb_anchor(&devinfo->data_urbs); spin_lock_init(&devinfo->lock); INIT_WORK(&devinfo->work, uas_do_work); + INIT_WORK(&devinfo->scan_work, uas_scan_work); result = uas_configure_endpoints(devinfo); if (result) @@ -1005,7 +1034,9 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) if (result) goto free_streams; - scsi_scan_host(shost); + /* Submit the delayed_work for SCSI-device scanning */ + schedule_work(&devinfo->scan_work); + return result; free_streams: @@ -1173,6 +1204,12 @@ static void uas_disconnect(struct usb_interface *intf) usb_kill_anchored_urbs(&devinfo->data_urbs); uas_zap_pending(devinfo, DID_NO_CONNECT); + /* + * Prevent SCSI scanning (if it hasn't started yet) + * or wait for the SCSI-scanning routine to stop. + */ + cancel_work_sync(&devinfo->scan_work); + scsi_remove_host(shost); uas_free_streams(devinfo); scsi_host_put(shost); @@ -1212,7 +1249,31 @@ static struct usb_driver uas_driver = { .id_table = uas_usb_ids, }; -module_usb_driver(uas_driver); +static int __init uas_init(void) +{ + int rv; + + workqueue = alloc_workqueue("uas", WQ_MEM_RECLAIM, 0); + if (!workqueue) + return -ENOMEM; + + rv = usb_register(&uas_driver); + if (rv) { + destroy_workqueue(workqueue); + return -ENOMEM; + } + + return 0; +} + +static void __exit uas_exit(void) +{ + usb_deregister(&uas_driver); + destroy_workqueue(workqueue); +} + +module_init(uas_init); +module_exit(uas_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR( diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index fb69cb64f7d457a097541d8c54bc6ec4c46eabcb..5c3f2eaf59e8c2f641d3f783006b8280040d59e5 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1277,6 +1277,12 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, USB_SC_RBC, USB_PR_BULK, NULL, 0 ), +UNUSUAL_DEV(0x090c, 0x1000, 0x1100, 0x1100, + "Samsung", + "Flash Drive FIT", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64), + /* aeb */ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, "Feiya", @@ -2336,6 +2342,13 @@ UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000, USB_SC_DEVICE,USB_PR_DEVICE,NULL, US_FL_MAX_SECTORS_64 ), +/* Reported by Cyril Roelandt */ +UNUSUAL_DEV( 0x357d, 0x7788, 0x0114, 0x0114, + "JMicron", + "USB to ATA/ATAPI Bridge", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BROKEN_FUA ), + /* Reported by Andrey Rahmatullin */ UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100, "iRiver", diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 8a00d80e415de3cad03c0fdad6dd1943b6834171..2c68fa5b02219dc4295c1a0ac9e86040d701dfaf 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -380,8 +380,8 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, vma = find_vma_intersection(mm, vaddr, vaddr + 1); if (vma && vma->vm_flags & VM_PFNMAP) { - *pfn = ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - if (is_invalid_reserved_pfn(*pfn)) + if (!follow_pfn(vma, vaddr, pfn) && + is_invalid_reserved_pfn(*pfn)) ret = 0; } @@ -593,7 +593,7 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data, continue; } - remote_vaddr = dma->vaddr + iova - dma->iova; + remote_vaddr = dma->vaddr + (iova - dma->iova); ret = vfio_pin_page_external(dma, remote_vaddr, &phys_pfn[i], do_accounting); if (ret) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 4d11152e60c155007a18b0d390c931d87588fc8c..8fe07622ae59ef5b863419554b314ef145832526 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1025,11 +1025,7 @@ static int vhost_net_release(struct inode *inode, struct file *f) static struct socket *get_raw_socket(int fd) { - struct { - struct sockaddr_ll sa; - char buf[MAX_ADDR_LEN]; - } uaddr; - int uaddr_len = sizeof uaddr, r; + int r; struct socket *sock = sockfd_lookup(fd, &r); if (!sock) @@ -1041,12 +1037,7 @@ static struct socket *get_raw_socket(int fd) goto err; } - r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, - &uaddr_len, 0); - if (r) - goto err; - - if (uaddr.sa.sll_family != AF_PACKET) { + if (sock->sk->sk_family != AF_PACKET) { r = -EPFNOSUPPORT; goto err; } diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 6391dc5b0ebe89de2d0cf3a676deb3575d395b86..834e88e20550f2c1729946447dea1ee033e41b7d 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -499,6 +499,11 @@ static int vhost_vsock_start(struct vhost_vsock *vsock) mutex_unlock(&vq->mutex); } + /* Some packets may have been queued before the device was started, + * let's kick the send worker to send them. + */ + vhost_work_queue(&vsock->dev, &vsock->send_pkt_work); + mutex_unlock(&vsock->dev.mutex); return 0; diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index 830ac900038ac1a20bc9d363f004e7fd515f99e9..1f21f15ab0b9fd12a1862dccf0bdef19395e3626 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -1,6 +1,6 @@ /* Copyright (c) 2015, Sony Mobile Communications, AB. * - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -91,6 +91,7 @@ #define WLED_SINK_REG_STR_MOD_EN BIT(7) #define WLED_SINK_SYNC_DLY_REG(n) (0x51 + (n * 0x10)) +#define WLED_SINK_SYNC_DLY_MASK GENMASK(2, 0) #define WLED_SINK_FS_CURR_REG(n) (0x52 + (n * 0x10)) #define WLED_SINK_FS_MASK GENMASK(3, 0) @@ -207,6 +208,7 @@ struct wled_config { int string_cfg; int mod_sel; int cabc_sel; + int sync_dly; bool en_cabc; bool ext_pfet_sc_pro_en; bool auto_calib_enabled; @@ -1254,6 +1256,14 @@ static int wled4_setup(struct wled *wled) if (rc < 0) return rc; + addr = wled->sink_addr + + WLED_SINK_SYNC_DLY_REG(i); + rc = regmap_update_bits(wled->regmap, addr, + WLED_SINK_SYNC_DLY_MASK, + wled->cfg.sync_dly); + if (rc < 0) + return rc; + temp = i + WLED_SINK_CURR_SINK_SHFT; sink_en |= 1 << temp; } @@ -1339,6 +1349,7 @@ static const struct wled_config wled4_config_defaults = { .fs_current = 10, .ovp = 1, .switch_freq = 11, + .sync_dly = 2, .string_cfg = 0xf, .mod_sel = -EINVAL, .cabc_sel = -EINVAL, @@ -1404,6 +1415,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = { .size = ARRAY_SIZE(wled4_ovp_values), }; +static const u32 wled4_sync_dly_values[] = { + 0, 200, 400, 600, 800, 1000, 1200, 1400, +}; + +static const struct wled_var_cfg wled4_sync_dly_cfg = { + .values = wled4_sync_dly_values, + .size = ARRAY_SIZE(wled4_sync_dly_values), +}; + static inline u32 wled5_ovp_values_fn(u32 idx) { /* @@ -2126,6 +2146,11 @@ static int wled_configure(struct wled *wled, struct device *dev) .val_ptr = &cfg->string_cfg, .cfg = &wled_string_cfg, }, + { + .name = "qcom,sync-dly", + .val_ptr = &cfg->sync_dly, + .cfg = &wled4_sync_dly_cfg, + }, }; const struct wled_u32_opts wled5_opts[] = { diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f09e17b60e45ef611f51e2e21528432731fac8f0..0fdd6761d6c31c1b43c6a58ea7b3a1bf49db9f57 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1310,6 +1310,9 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) static int vgacon_resize(struct vc_data *c, unsigned int width, unsigned int height, unsigned int user) { + if ((width << 1) * height > vga_vram_size) + return -EINVAL; + if (width % 2 || width > screen_info.orig_video_cols || height > (screen_info.orig_video_lines * vga_default_font_height)/ c->vc_font.height) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 553763a637501401cd69cd035aa5a8f1773de0d5..2f946cdd9945a958f9c9eb7e422ecb273886db46 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1221,6 +1221,9 @@ static void fbcon_deinit(struct vc_data *vc) if (!con_is_bound(&fb_con)) fbcon_exit(); + if (vc->vc_num == logo_shown) + logo_shown = FBCON_LOGO_CANSHOW; + return; } diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index b5b66b288bc9fc2efbfbb9e51a0bd4812b1e97d5..4e2c6c8e549a9390cc9c2b9ded3cd3c34def8b19 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1148,7 +1148,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, case FBIOGET_FSCREENINFO: if (!lock_fb_info(info)) return -ENODEV; - fix = info->fix; + memcpy(&fix, &info->fix, sizeof(fix)); unlock_fb_info(info); ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 0a72aadca7393a52d054d119440e638b136a52da..da704cbe96827a900c1902345ac60c15038e6945 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -476,6 +476,7 @@ struct mdss_dsi_ctrl_pdata { bool dsi_irq_line; bool dcs_cmd_insert; atomic_t te_irq_ready; + bool idle; bool cmd_sync_wait_broadcast; bool cmd_sync_wait_trigger; @@ -507,6 +508,8 @@ struct mdss_dsi_ctrl_pdata { struct dsi_panel_cmds lp_on_cmds; struct dsi_panel_cmds lp_off_cmds; struct dsi_panel_cmds status_cmds; + struct dsi_panel_cmds idle_on_cmds; /* for lp mode */ + struct dsi_panel_cmds idle_off_cmds; u32 *status_valid_params; u32 *status_cmds_rlen; u32 *status_value; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index f9f41f5aeb62173d83b6bd471a524a5b46012f2d..998f6a0e3e2b90f8bedf88aa188331cb476cbf69 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -251,6 +251,55 @@ static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) mdss_dsi_cmdlist_put(ctrl, &cmdreq); } +static void mdss_dsi_panel_set_idle_mode(struct mdss_panel_data *pdata, + bool enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pr_debug("%s: Idle (%d->%d)\n", __func__, ctrl->idle, enable); + + if (ctrl->idle == enable) + return; + + if (enable) { + if (ctrl->idle_on_cmds.cmd_cnt) { + mdss_dsi_panel_cmds_send(ctrl, &ctrl->idle_on_cmds, + CMD_REQ_COMMIT); + ctrl->idle = true; + pr_debug("Idle on\n"); + } + } else { + if (ctrl->idle_off_cmds.cmd_cnt) { + mdss_dsi_panel_cmds_send(ctrl, &ctrl->idle_off_cmds, + CMD_REQ_COMMIT); + ctrl->idle = false; + pr_debug("Idle off\n"); + } + } +} + +static bool mdss_dsi_panel_get_idle_mode(struct mdss_panel_data *pdata) + +{ + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return 0; + } + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + return ctrl->idle; +} + static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int rc = 0; @@ -411,6 +460,11 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) return rc; } + if (pinfo->skip_panel_reset && !pinfo->cont_splash_enabled) { + pr_debug("%s: skip_panel_reset is set\n", __func__); + return 0; + } + pr_debug("%s: enable = %d\n", __func__, enable); if (enable) { @@ -1009,6 +1063,8 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata) } end: + /* clear idle state */ + ctrl->idle = false; pr_debug("%s:-\n", __func__); return 0; } @@ -1066,7 +1122,11 @@ static int mdss_dsi_panel_low_power_config(struct mdss_panel_data *pdata, enable); /* Any panel specific low power commands/config */ - + /* Control idle mode for panel */ + if (enable) + mdss_dsi_panel_set_idle_mode(pdata, true); + else + mdss_dsi_panel_set_idle_mode(pdata, false); pr_debug("%s:-\n", __func__); return 0; } @@ -2984,12 +3044,26 @@ static int mdss_panel_parse_dt(struct device_node *np, mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds, "qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state"); + mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->idle_on_cmds, + "qcom,mdss-dsi-idle-on-command", + "qcom,mdss-dsi-idle-on-command-state"); + + mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->idle_off_cmds, + "qcom,mdss-dsi-idle-off-command", + "qcom,mdss-dsi-idle-off-command-state"); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-idle-fps", &tmp); + pinfo->mipi.frame_rate_idle = (!rc ? tmp : 60); + rc = of_property_read_u32(np, "qcom,adjust-timer-wakeup-ms", &tmp); pinfo->adjust_timer_delay_ms = (!rc ? tmp : 0); pinfo->mipi.force_clk_lane_hs = of_property_read_bool(np, "qcom,mdss-dsi-force-clock-lane-hs"); + pinfo->skip_panel_reset = + of_property_read_bool(np, "qcom,mdss-skip-panel-reset"); + rc = mdss_dsi_parse_panel_features(np, ctrl_pdata); if (rc) { pr_err("%s: failed to parse panel features\n", __func__); @@ -3075,6 +3149,6 @@ int mdss_dsi_panel_init(struct device_node *node, ctrl_pdata->panel_data.apply_display_setting = mdss_dsi_panel_apply_display_setting; ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; - + ctrl_pdata->panel_data.get_idle = mdss_dsi_panel_get_idle_mode; return 0; } diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 55bf8c06ec908282b96d56eef577604255a0ac29..50d219e903a26b46925187ba7858b36ccd26b04c 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -519,6 +519,7 @@ struct mipi_panel_info { char traffic_mode; char frame_rate; /* command mode */ + char frame_rate_idle; char interleave_max; char insert_dcs_cmd; char wr_mem_continue; @@ -942,6 +943,12 @@ struct mdss_panel_info { /* stores initial adaptive variable refresh vtotal value */ u32 saved_avr_vtotal; + /* + * Skip panel reset during panel on/off. + * Set for some in-cell panels + */ + bool skip_panel_reset; + /* HDR properties of display panel*/ struct mdss_panel_hdr_properties hdr_properties; @@ -1003,6 +1010,7 @@ struct mdss_panel_data { */ int (*event_handler)(struct mdss_panel_data *pdata, int e, void *arg); struct device_node *(*get_fb_node)(struct platform_device *pdev); + bool (*get_idle)(struct mdss_panel_data *pdata); struct list_head timings_list; struct mdss_panel_timing *current_timing; @@ -1038,6 +1046,10 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info) { u32 frame_rate, pixel_total; u64 rate; + struct mdss_panel_data *panel_data = + container_of(panel_info, typeof(*panel_data), + panel_info); + bool idle = false; if (panel_info == NULL) return DEFAULT_FRAME_RATE; @@ -1046,6 +1058,12 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info) case MIPI_VIDEO_PANEL: case MIPI_CMD_PANEL: frame_rate = panel_info->mipi.frame_rate; + if (panel_data->get_idle) + idle = panel_data->get_idle(panel_data); + if (idle) + frame_rate = panel_info->mipi.frame_rate_idle; + else + frame_rate = panel_info->mipi.frame_rate; break; case EDP_PANEL: frame_rate = panel_info->edp.frame_rate; diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c index d059d04c63acd7bc118bbc0ec02fc3cb1dfa41f8..20195d3dbf088c87195c2976f09acefb1f5895da 100644 --- a/drivers/video/fbdev/pxa168fb.c +++ b/drivers/video/fbdev/pxa168fb.c @@ -769,8 +769,8 @@ static int pxa168fb_probe(struct platform_device *pdev) failed_free_clk: clk_disable_unprepare(fbi->clk); failed_free_fbmem: - dma_free_coherent(fbi->dev, info->fix.smem_len, - info->screen_base, fbi->fb_start_dma); + dma_free_wc(fbi->dev, info->fix.smem_len, + info->screen_base, fbi->fb_start_dma); failed_free_info: kfree(info); @@ -804,7 +804,7 @@ static int pxa168fb_remove(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); - dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len), + dma_free_wc(fbi->dev, info->fix.smem_len, info->screen_base, info->fix.smem_start); clk_disable_unprepare(fbi->clk); diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c index 1ec9c3e0e1d85092f4e06b3a2db04d9836e36a1f..f23a381442d3dc090f6bd1cb289a206aec3120dc 100644 --- a/drivers/video/fbdev/sis/init301.c +++ b/drivers/video/fbdev/sis/init301.c @@ -522,9 +522,7 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime) SiS_DDC2Delay(SiS_Pr, 0x4000); } - } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* || - (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || - (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */ + } else if (SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* 315 series, LVDS; Special */ if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 499531608fa26813c39e046f8b6d6e0b94ccb34d..71970773aad1375f796a17543b9343dd09408be1 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -132,6 +132,8 @@ static void set_page_pfns(struct virtio_balloon *vb, { unsigned int i; + BUILD_BUG_ON(VIRTIO_BALLOON_PAGES_PER_PAGE > VIRTIO_BALLOON_ARRAY_PFNS_MAX); + /* * Set balloon pfns pointing at this page. * Note that the first pfn points at start of the page. diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c index 89e14b01959bf82a6bda12fe52cc73b889b8dc84..0073d078e50ebdb804df58d85dcc71b8625051d2 100644 --- a/drivers/virtio/virtio_input.c +++ b/drivers/virtio/virtio_input.c @@ -164,12 +164,15 @@ static void virtinput_cfg_abs(struct virtio_input *vi, int abs) virtio_cread(vi->vdev, struct virtio_input_config, u.abs.flat, &fl); input_set_abs_params(vi->idev, abs, mi, ma, fu, fl); input_abs_set_res(vi->idev, abs, re); - if (abs == ABS_MT_TRACKING_ID) + if (abs == ABS_MT_TRACKING_ID) { + unsigned int slot_flags = + test_bit(INPUT_PROP_DIRECT, vi->idev->propbit) ? + INPUT_MT_DIRECT : 0; + input_mt_init_slots(vi->idev, ma, /* input max finger */ - INPUT_MT_DIRECT - | INPUT_MT_DROP_UNUSED - | INPUT_MT_TRACK); + slot_flags); + } } static int virtinput_init_vqs(struct virtio_input *vi) diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/vme/bridges/vme_fake.c index 30b3acc9383309509862e0d1b942c22bc82a5361..e81ec763b5555026f9bcc395d620199f9fd58079 100644 --- a/drivers/vme/bridges/vme_fake.c +++ b/drivers/vme/bridges/vme_fake.c @@ -418,8 +418,9 @@ static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr, } } -static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr, - u32 aspace, u32 cycle) +static noinline_for_stack u8 fake_vmeread8(struct fake_driver *bridge, + unsigned long long addr, + u32 aspace, u32 cycle) { u8 retval = 0xff; int i; @@ -450,8 +451,9 @@ static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr, return retval; } -static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr, - u32 aspace, u32 cycle) +static noinline_for_stack u16 fake_vmeread16(struct fake_driver *bridge, + unsigned long long addr, + u32 aspace, u32 cycle) { u16 retval = 0xffff; int i; @@ -482,8 +484,9 @@ static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr, return retval; } -static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr, - u32 aspace, u32 cycle) +static noinline_for_stack u32 fake_vmeread32(struct fake_driver *bridge, + unsigned long long addr, + u32 aspace, u32 cycle) { u32 retval = 0xffffffff; int i; @@ -613,8 +616,9 @@ static ssize_t fake_master_read(struct vme_master_resource *image, void *buf, return retval; } -static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf, - unsigned long long addr, u32 aspace, u32 cycle) +static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge, + u8 *buf, unsigned long long addr, + u32 aspace, u32 cycle) { int i; unsigned long long start, end, offset; @@ -643,8 +647,9 @@ static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf, } -static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf, - unsigned long long addr, u32 aspace, u32 cycle) +static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge, + u16 *buf, unsigned long long addr, + u32 aspace, u32 cycle) { int i; unsigned long long start, end, offset; @@ -673,8 +678,9 @@ static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf, } -static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf, - unsigned long long addr, u32 aspace, u32 cycle) +static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge, + u32 *buf, unsigned long long addr, + u32 aspace, u32 cycle) { int i; unsigned long long start, end, offset; diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index 9083d3d922b0b4304a3623b307c3b6a66e99f2ef..79383ff620199c20db7d97f61366a24d499d3760 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -126,13 +126,6 @@ static int da9062_wdt_stop(struct watchdog_device *wdd) struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd); int ret; - ret = da9062_reset_watchdog_timer(wdt); - if (ret) { - dev_err(wdt->hw->dev, "Failed to ping the watchdog (err = %d)\n", - ret); - return ret; - } - ret = regmap_update_bits(wdt->hw->regmap, DA9062AA_CONTROL_D, DA9062AA_TWDSCALE_MASK, diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index b30fb637ae947885e04eba1819e7d8cd145764d1..52e03f1c76e383e1d70675a6f4057144af34de0b 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -245,6 +245,7 @@ static int watchdog_start(struct watchdog_device *wdd) if (err == 0) { set_bit(WDOG_ACTIVE, &wdd->status); wd_data->last_keepalive = started_at; + wd_data->last_hw_keepalive = started_at; watchdog_update_worker(wdd); } diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index 0da9943d405f8ff89efc87a0cf6df5ff43df9d6f..c310e841561cbb1b15d03e498a764f25e1b9e1c5 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -392,7 +392,7 @@ static int wdat_wdt_probe(struct platform_device *pdev) memset(&r, 0, sizeof(r)); r.start = gas->address; - r.end = r.start + gas->access_width - 1; + r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1; if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { r.flags = IORESOURCE_MEM; } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c index 08cb419eb4e63c90f30ea7cdb541d31c14da2391..5f6b77ea34fb5b5ddef4d4fb5e3ba722194ded6f 100644 --- a/drivers/xen/preempt.c +++ b/drivers/xen/preempt.c @@ -37,7 +37,9 @@ asmlinkage __visible void xen_maybe_preempt_hcall(void) * cpu. */ __this_cpu_write(xen_in_preemptible_hcall, false); - _cond_resched(); + local_irq_enable(); + cond_resched(); + local_irq_disable(); __this_cpu_write(xen_in_preemptible_hcall, true); } } diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index cf8ef8cee5a0a7decef75453675e15ef24a2a978..112e8b5e6feed298e5731426a6348ffcb0891d6b 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -82,7 +82,7 @@ static void watch_target(struct xenbus_watch *watch, "%llu", &static_max) == 1)) static_max >>= PAGE_SHIFT - 10; else - static_max = new_target; + static_max = balloon_stats.current_pages; target_diff = (xen_pv_domain() || xen_initial_domain()) ? 0 : static_max - balloon_stats.target_pages; diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index a1c17000129ba1cb4465df0bc679a0756f8937a3..e94a61eaeceb08a0172d50a3b8070f0c72ce9705 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -450,7 +450,14 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn); int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs, unsigned int nr_grefs, void **vaddr) { - return ring_ops->map(dev, gnt_refs, nr_grefs, vaddr); + int err; + + err = ring_ops->map(dev, gnt_refs, nr_grefs, vaddr); + /* Some hypervisors are buggy and can return 1. */ + if (err > 0) + err = GNTST_general_error; + + return err; } EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c index d239fc3c5e3ded66ad28194fcdc7d09a6df801da..eb5151fc8efab02899ce764b99a8d6f2955e9ca7 100644 --- a/drivers/xen/xenbus/xenbus_comms.c +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -313,6 +313,8 @@ static int process_msg(void) req->msg.type = state.msg.type; req->msg.len = state.msg.len; req->body = state.body; + /* write body, then update state */ + virt_wmb(); req->state = xb_req_state_got_reply; req->cb(req); } else @@ -395,6 +397,8 @@ static int process_writes(void) if (state.req->state == xb_req_state_aborted) kfree(state.req); else { + /* write err, then update state */ + virt_wmb(); state.req->state = xb_req_state_got_reply; wake_up(&state.req->wq); } diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 3f3b29398ab8e2b711ce724cf756ea8c241433cb..b609c6e08796e45bebdc1fbb79f5f97c892a66c6 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -188,8 +188,11 @@ static bool xenbus_ok(void) static bool test_reply(struct xb_req_data *req) { - if (req->state == xb_req_state_got_reply || !xenbus_ok()) + if (req->state == xb_req_state_got_reply || !xenbus_ok()) { + /* read req->state before all other fields */ + virt_rmb(); return true; + } /* Make sure to reread req->state each time. */ barrier(); @@ -199,7 +202,7 @@ static bool test_reply(struct xb_req_data *req) static void *read_reply(struct xb_req_data *req) { - while (req->state != xb_req_state_got_reply) { + do { wait_event(req->wq, test_reply(req)); if (!xenbus_ok()) @@ -213,7 +216,7 @@ static void *read_reply(struct xb_req_data *req) if (req->err) return ERR_PTR(req->err); - } + } while (req->state != xb_req_state_got_reply); return req->body; } diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index ccc9c708a860a5d5c405a7198e9a29110f4dc390..7dc9c78a1c31cac07c13f5516a9cc88b4861b2a6 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -173,7 +173,7 @@ void afs_put_call(struct afs_call *call) int n = atomic_dec_return(&call->usage); int o = atomic_read(&afs_outstanding_calls); - trace_afs_call(call, afs_call_trace_put, n + 1, o, + trace_afs_call(call, afs_call_trace_put, n, o, __builtin_return_address(0)); ASSERTCMP(n, >=, 0); @@ -619,7 +619,7 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, u = __atomic_add_unless(&call->usage, 1, 0); if (u != 0) { - trace_afs_call(call, afs_call_trace_wake, u, + trace_afs_call(call, afs_call_trace_wake, u + 1, atomic_read(&afs_outstanding_calls), __builtin_return_address(0)); diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 72d7589072f523cf283b27b053aef31cc399d130..92615badc17341f3749577d465fd2fdb4d9aa3d5 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -447,3 +447,11 @@ void btrfs_set_work_high_priority(struct btrfs_work *work) { set_bit(WORK_HIGH_PRIO_BIT, &work->flags); } + +void btrfs_flush_workqueue(struct btrfs_workqueue *wq) +{ + if (wq->high) + flush_workqueue(wq->high->normal_wq); + + flush_workqueue(wq->normal->normal_wq); +} diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index fc957e00cef144385e8368a44cfc418b412eadc0..2a25aef6ef2a5a86cfb71718ce672635292081d9 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -85,4 +85,6 @@ void btrfs_set_work_high_priority(struct btrfs_work *work); struct btrfs_fs_info *btrfs_work_owner(const struct btrfs_work *work); struct btrfs_fs_info *btrfs_workqueue_owner(const struct __btrfs_workqueue *wq); bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq); +void btrfs_flush_workqueue(struct btrfs_workqueue *wq); + #endif diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 7d5a9b51f0d7a81fa7d5adf9900e4fcc744a80c0..4be07cf31d74cc9c1e7303dbdeec1e8f2bbb4d6a 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -642,7 +642,6 @@ static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup(dev_t dev, static int btrfsic_process_superblock(struct btrfsic_state *state, struct btrfs_fs_devices *fs_devices) { - struct btrfs_fs_info *fs_info = state->fs_info; struct btrfs_super_block *selected_super; struct list_head *dev_head = &fs_devices->devices; struct btrfs_device *device; @@ -713,7 +712,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, break; } - num_copies = btrfs_num_copies(fs_info, next_bytenr, + num_copies = btrfs_num_copies(state->fs_info, next_bytenr, state->metablock_size); if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) pr_info("num_copies(log_bytenr=%llu) = %d\n", diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 740ef428acdd9444af76a630715d7fab5acf9481..f5a8c0d26cf365cd7592fdcb5611aa8577a13d82 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -334,26 +334,6 @@ struct tree_mod_elem { struct tree_mod_root old_root; }; -static inline void tree_mod_log_read_lock(struct btrfs_fs_info *fs_info) -{ - read_lock(&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_read_unlock(struct btrfs_fs_info *fs_info) -{ - read_unlock(&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_write_lock(struct btrfs_fs_info *fs_info) -{ - write_lock(&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info) -{ - write_unlock(&fs_info->tree_mod_log_lock); -} - /* * Pull a new tree mod seq number for our operation. */ @@ -373,14 +353,12 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, struct seq_list *elem) { - tree_mod_log_write_lock(fs_info); - spin_lock(&fs_info->tree_mod_seq_lock); + write_lock(&fs_info->tree_mod_log_lock); if (!elem->seq) { elem->seq = btrfs_inc_tree_mod_seq(fs_info); list_add_tail(&elem->list, &fs_info->tree_mod_seq_list); } - spin_unlock(&fs_info->tree_mod_seq_lock); - tree_mod_log_write_unlock(fs_info); + write_unlock(&fs_info->tree_mod_log_lock); return elem->seq; } @@ -399,7 +377,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, if (!seq_putting) return; - spin_lock(&fs_info->tree_mod_seq_lock); + write_lock(&fs_info->tree_mod_log_lock); list_del(&elem->list); elem->seq = 0; @@ -410,19 +388,17 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, * blocker with lower sequence number exists, we * cannot remove anything from the log */ - spin_unlock(&fs_info->tree_mod_seq_lock); + write_unlock(&fs_info->tree_mod_log_lock); return; } min_seq = cur_elem->seq; } } - spin_unlock(&fs_info->tree_mod_seq_lock); /* * anything that's lower than the lowest existing (read: blocked) * sequence number can be removed from the tree. */ - tree_mod_log_write_lock(fs_info); tm_root = &fs_info->tree_mod_log; for (node = rb_first(tm_root); node; node = next) { next = rb_next(node); @@ -432,7 +408,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, rb_erase(node, tm_root); kfree(tm); } - tree_mod_log_write_unlock(fs_info); + write_unlock(&fs_info->tree_mod_log_lock); } /* @@ -443,7 +419,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, * for root replace operations, or the logical address of the affected * block for all other operations. * - * Note: must be called with write lock (tree_mod_log_write_lock). + * Note: must be called with write lock for fs_info::tree_mod_log_lock. */ static noinline int __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) @@ -481,7 +457,7 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) * Determines if logging can be omitted. Returns 1 if it can. Otherwise, it * returns zero with the tree_mod_log_lock acquired. The caller must hold * this until all tree mod log insertions are recorded in the rb tree and then - * call tree_mod_log_write_unlock() to release. + * write unlock fs_info::tree_mod_log_lock. */ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) { @@ -491,9 +467,9 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, if (eb && btrfs_header_level(eb) == 0) return 1; - tree_mod_log_write_lock(fs_info); + write_lock(&fs_info->tree_mod_log_lock); if (list_empty(&(fs_info)->tree_mod_seq_list)) { - tree_mod_log_write_unlock(fs_info); + write_unlock(&fs_info->tree_mod_log_lock); return 1; } @@ -557,7 +533,7 @@ tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, } ret = __tree_mod_log_insert(fs_info, tm); - tree_mod_log_write_unlock(fs_info); + write_unlock(&eb->fs_info->tree_mod_log_lock); if (ret) kfree(tm); @@ -621,7 +597,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, ret = __tree_mod_log_insert(fs_info, tm); if (ret) goto free_tms; - tree_mod_log_write_unlock(fs_info); + write_unlock(&eb->fs_info->tree_mod_log_lock); kfree(tm_list); return 0; @@ -632,7 +608,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, kfree(tm_list[i]); } if (locked) - tree_mod_log_write_unlock(fs_info); + write_unlock(&eb->fs_info->tree_mod_log_lock); kfree(tm_list); kfree(tm); @@ -713,7 +689,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, if (!ret) ret = __tree_mod_log_insert(fs_info, tm); - tree_mod_log_write_unlock(fs_info); + write_unlock(&fs_info->tree_mod_log_lock); if (ret) goto free_tms; kfree(tm_list); @@ -740,7 +716,7 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq, struct tree_mod_elem *cur = NULL; struct tree_mod_elem *found = NULL; - tree_mod_log_read_lock(fs_info); + read_lock(&fs_info->tree_mod_log_lock); tm_root = &fs_info->tree_mod_log; node = tm_root->rb_node; while (node) { @@ -768,7 +744,7 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq, break; } } - tree_mod_log_read_unlock(fs_info); + read_unlock(&fs_info->tree_mod_log_lock); return found; } @@ -849,7 +825,7 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, goto free_tms; } - tree_mod_log_write_unlock(fs_info); + write_unlock(&fs_info->tree_mod_log_lock); kfree(tm_list); return 0; @@ -861,7 +837,7 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, kfree(tm_list[i]); } if (locked) - tree_mod_log_write_unlock(fs_info); + write_unlock(&fs_info->tree_mod_log_lock); kfree(tm_list); return ret; @@ -921,7 +897,7 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) goto free_tms; ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems); - tree_mod_log_write_unlock(fs_info); + write_unlock(&eb->fs_info->tree_mod_log_lock); if (ret) goto free_tms; kfree(tm_list); @@ -1279,7 +1255,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, unsigned long p_size = sizeof(struct btrfs_key_ptr); n = btrfs_header_nritems(eb); - tree_mod_log_read_lock(fs_info); + read_lock(&fs_info->tree_mod_log_lock); while (tm && tm->seq >= time_seq) { /* * all the operations are recorded with the operator used for @@ -1334,7 +1310,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, if (tm->logical != first_tm->logical) break; } - tree_mod_log_read_unlock(fs_info); + read_unlock(&fs_info->tree_mod_log_lock); btrfs_set_header_nritems(eb, n); } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 588760c49fe28b8137d7a4136f035dd6d947e804..5412b12491cb81f47bc418a2facc94aaedb6e3cf 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -869,14 +869,12 @@ struct btrfs_fs_info { struct list_head delayed_iputs; struct mutex cleaner_delayed_iput_mutex; - /* this protects tree_mod_seq_list */ - spinlock_t tree_mod_seq_lock; atomic64_t tree_mod_seq; - struct list_head tree_mod_seq_list; - /* this protects tree_mod_log */ + /* this protects tree_mod_log and tree_mod_seq_list */ rwlock_t tree_mod_log_lock; struct rb_root tree_mod_log; + struct list_head tree_mod_seq_list; atomic_t nr_async_submits; atomic_t async_submit_draining; @@ -2408,32 +2406,6 @@ static inline u32 btrfs_file_extent_inline_item_len( return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START; } -/* this returns the number of file bytes represented by the inline item. - * If an item is compressed, this is the uncompressed size - */ -static inline u32 btrfs_file_extent_inline_len(const struct extent_buffer *eb, - int slot, - const struct btrfs_file_extent_item *fi) -{ - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - /* - * return the space used on disk if this item isn't - * compressed or encoded - */ - if (btrfs_token_file_extent_compression(eb, fi, &token) == 0 && - btrfs_token_file_extent_encryption(eb, fi, &token) == 0 && - btrfs_token_file_extent_other_encoding(eb, fi, &token) == 0) { - return btrfs_file_extent_inline_item_len(eb, - btrfs_item_nr(slot)); - } - - /* otherwise use the ram bytes field */ - return btrfs_token_file_extent_ram_bytes(eb, fi, &token); -} - - /* btrfs_dev_stats_item */ static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, const struct btrfs_dev_stats_item *ptr, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 87414fc9e268f98f9b6df4f470c1185793512998..416fb50a5378c5fd74b2438275f13363f9b2830e 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -18,6 +18,7 @@ */ #include +#include #include "delayed-inode.h" #include "disk-io.h" #include "transaction.h" @@ -833,11 +834,14 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans, { struct btrfs_fs_info *fs_info = root->fs_info; struct extent_buffer *leaf; + unsigned int nofs_flag; char *ptr; int ret; + nofs_flag = memalloc_nofs_save(); ret = btrfs_insert_empty_item(trans, root, path, &delayed_item->key, delayed_item->data_len); + memalloc_nofs_restore(nofs_flag); if (ret < 0 && ret != -EEXIST) return ret; @@ -966,6 +970,7 @@ static int btrfs_delete_delayed_items(struct btrfs_trans_handle *trans, struct btrfs_delayed_node *node) { struct btrfs_delayed_item *curr, *prev; + unsigned int nofs_flag; int ret = 0; do_again: @@ -974,7 +979,9 @@ static int btrfs_delete_delayed_items(struct btrfs_trans_handle *trans, if (!curr) goto delete_fail; + nofs_flag = memalloc_nofs_save(); ret = btrfs_search_slot(trans, root, &curr->key, path, -1, 1); + memalloc_nofs_restore(nofs_flag); if (ret < 0) goto delete_fail; else if (ret > 0) { @@ -1041,6 +1048,7 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, struct btrfs_key key; struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; + unsigned int nofs_flag; int mod; int ret; @@ -1053,7 +1061,9 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, else mod = 1; + nofs_flag = memalloc_nofs_save(); ret = btrfs_lookup_inode(trans, root, path, &key, mod); + memalloc_nofs_restore(nofs_flag); if (ret > 0) { btrfs_release_path(path); return -ENOENT; @@ -1104,7 +1114,10 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, key.type = BTRFS_INODE_EXTREF_KEY; key.offset = -1; + + nofs_flag = memalloc_nofs_save(); ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + memalloc_nofs_restore(nofs_flag); if (ret < 0) goto err_out; ASSERT(ret); diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index d56bd36254681205d0ff39c716a04dc3b81be907..45714f1c43a31367332e3873cd45e0b0b5d744fe 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -281,7 +281,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, if (head->is_data) return; - spin_lock(&fs_info->tree_mod_seq_lock); + read_lock(&fs_info->tree_mod_log_lock); if (!list_empty(&fs_info->tree_mod_seq_list)) { struct seq_list *elem; @@ -289,7 +289,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, struct seq_list, list); seq = elem->seq; } - spin_unlock(&fs_info->tree_mod_seq_lock); + read_unlock(&fs_info->tree_mod_log_lock); ref = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node, list); @@ -317,7 +317,7 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, struct seq_list *elem; int ret = 0; - spin_lock(&fs_info->tree_mod_seq_lock); + read_lock(&fs_info->tree_mod_log_lock); if (!list_empty(&fs_info->tree_mod_seq_list)) { elem = list_first_entry(&fs_info->tree_mod_seq_list, struct seq_list, list); @@ -331,7 +331,7 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, } } - spin_unlock(&fs_info->tree_mod_seq_lock); + read_unlock(&fs_info->tree_mod_log_lock); return ret; } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a8ea56218d6b6a5d89a06b3c656fcf9fee9708e7..096c015b22a46750c0374e22b0d08a518a37c845 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2051,7 +2051,7 @@ static void free_root_extent_buffers(struct btrfs_root *root) } /* helper to cleanup tree roots */ -static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) +static void free_root_pointers(struct btrfs_fs_info *info, bool free_chunk_root) { free_root_extent_buffers(info->tree_root); @@ -2060,7 +2060,7 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) free_root_extent_buffers(info->csum_root); free_root_extent_buffers(info->quota_root); free_root_extent_buffers(info->uuid_root); - if (chunk_root) + if (free_chunk_root) free_root_extent_buffers(info->chunk_root); free_root_extent_buffers(info->free_space_root); } @@ -2455,7 +2455,6 @@ int open_ctree(struct super_block *sb, spin_lock_init(&fs_info->fs_roots_radix_lock); spin_lock_init(&fs_info->delayed_iput_lock); spin_lock_init(&fs_info->defrag_inodes_lock); - spin_lock_init(&fs_info->tree_mod_seq_lock); spin_lock_init(&fs_info->super_lock); spin_lock_init(&fs_info->qgroup_op_lock); spin_lock_init(&fs_info->buffer_lock); @@ -2914,6 +2913,7 @@ int open_ctree(struct super_block *sb, /* do not make disk changes in broken FS or nologreplay is given */ if (btrfs_super_log_root(disk_super) != 0 && !btrfs_test_opt(fs_info, NOLOGREPLAY)) { + btrfs_info(fs_info, "start tree-log replay"); ret = btrfs_replay_log(fs_info, fs_devices); if (ret) { err = ret; @@ -3069,7 +3069,7 @@ int open_ctree(struct super_block *sb, btrfs_put_block_group_cache(fs_info); fail_tree_roots: - free_root_pointers(fs_info, 1); + free_root_pointers(fs_info, true); invalidate_inode_pages2(fs_info->btree_inode->i_mapping); fail_sb_buffer: @@ -3097,7 +3097,7 @@ int open_ctree(struct super_block *sb, if (!btrfs_test_opt(fs_info, USEBACKUPROOT)) goto fail_tree_roots; - free_root_pointers(fs_info, 0); + free_root_pointers(fs_info, false); /* don't use the log in recovery mode, it won't be valid */ btrfs_set_super_log_root(disk_super, 0); @@ -3725,6 +3725,19 @@ void close_ctree(struct btrfs_fs_info *fs_info) */ btrfs_delete_unused_bgs(fs_info); + /* + * There might be existing delayed inode workers still running + * and holding an empty delayed inode item. We must wait for + * them to complete first because they can create a transaction. + * This happens when someone calls btrfs_balance_delayed_items() + * and then a transaction commit runs the same delayed nodes + * before any delayed worker has done something with the nodes. + * We must wait for any worker here and not at transaction + * commit time since that could cause a deadlock. + * This is a very rare case. + */ + btrfs_flush_workqueue(fs_info->delayed_workers); + ret = btrfs_commit_super(fs_info); if (ret) btrfs_err(fs_info, "commit super ret %d", ret); @@ -3761,10 +3774,17 @@ void close_ctree(struct btrfs_fs_info *fs_info) invalidate_inode_pages2(fs_info->btree_inode->i_mapping); btrfs_stop_all_workers(fs_info); - btrfs_free_block_groups(fs_info); - clear_bit(BTRFS_FS_OPEN, &fs_info->flags); - free_root_pointers(fs_info, 1); + free_root_pointers(fs_info, true); + + /* + * We must free the block groups after dropping the fs_roots as we could + * have had an IO error and have left over tree log blocks that aren't + * cleaned up until the fs roots are freed. This makes the block group + * accounting appear to be wrong because there's pending reserved bytes, + * so make sure we do the block group cleanup afterwards. + */ + btrfs_free_block_groups(fs_info); iput(fs_info->btree_inode); @@ -4387,7 +4407,6 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, wake_up(&fs_info->transaction_wait); btrfs_destroy_delayed_inodes(fs_info); - btrfs_assert_delayed_root_empty(fs_info); btrfs_destroy_marked_extents(fs_info, &cur_trans->dirty_pages, EXTENT_DIRTY); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index fd15f396b3a0951979acde7146415b84f5c95308..51e26f90f0bb28da6a064815ce9554834cc43cec 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10554,7 +10554,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; - goto out; + goto out_put_group; } /* @@ -10591,7 +10591,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ret = btrfs_orphan_add(trans, BTRFS_I(inode)); if (ret) { btrfs_add_delayed_iput(inode); - goto out; + goto out_put_group; } clear_nlink(inode); /* One for the block groups ref */ @@ -10614,13 +10614,13 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); if (ret < 0) - goto out; + goto out_put_group; if (ret > 0) btrfs_release_path(path); if (ret == 0) { ret = btrfs_del_item(trans, tree_root, path); if (ret) - goto out; + goto out_put_group; btrfs_release_path(path); } @@ -10778,9 +10778,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ret = remove_block_group_free_space(trans, fs_info, block_group); if (ret) - goto out; + goto out_put_group; - btrfs_put_block_group(block_group); + /* Once for the block groups rbtree */ btrfs_put_block_group(block_group); ret = btrfs_search_slot(trans, root, &key, path, -1, 1); @@ -10790,6 +10790,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, goto out; ret = btrfs_del_item(trans, root, path); + +out_put_group: + /* Once for the lookup reference */ + btrfs_put_block_group(block_group); out: btrfs_free_path(path); return ret; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index c133106e5c1ea819783d6b7a07635a8561cfc640..a485e34f2c705eac68b406b28b1f3e0ebab4af81 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4037,6 +4037,14 @@ static int extent_write_cache_pages(struct address_space *mapping, */ scanned = 1; index = 0; + + /* + * If we're looping we could run into a page that is locked by a + * writer and that writer could be waiting on writeback for a + * page in our current bio, and thus deadlock, so flush the + * write bio here. + */ + flush_write_bio(data); goto retry; } diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 2e348fb0b280d64ae158a28713e33a8d48f0598d..c87d673ce3347c0cb755f0abeb8fefb00af7c835 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -228,6 +228,17 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) struct extent_map *merge = NULL; struct rb_node *rb; + /* + * We can't modify an extent map that is in the tree and that is being + * used by another task, as it can cause that other task to see it in + * inconsistent state during the merging. We always have 1 reference for + * the tree and 1 for this task (which is unpinning the extent map or + * clearing the logging flag), so anything > 2 means it's being used by + * other tasks too. + */ + if (refcount_read(&em->refs) > 2) + return; + if (em->start != 0) { rb = rb_prev(&em->rb_node); if (rb) diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index fdcb410026233ecc7c5ec475b8a5d711efc47b3c..717d82d51bb13c619b66c3e3d967b33166d7b77a 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -288,7 +288,8 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio csum += count * csum_size; nblocks -= count; next: - while (count--) { + while (count > 0) { + count--; disk_bytenr += fs_info->sectorsize; offset += fs_info->sectorsize; page_bytes_left -= fs_info->sectorsize; @@ -955,7 +956,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, btrfs_file_extent_num_bytes(leaf, fi); } else if (type == BTRFS_FILE_EXTENT_INLINE) { size_t size; - size = btrfs_file_extent_inline_len(leaf, slot, fi); + size = btrfs_file_extent_ram_bytes(leaf, fi); extent_end = ALIGN(extent_start + size, fs_info->sectorsize); } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index c68ce3412dc1152e6da4d5000c715f4d813d10e1..725544ec9c842c4bfa598cea06cf05d25026b556 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -784,8 +784,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, btrfs_file_extent_num_bytes(leaf, fi); } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { extent_end = key.offset + - btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); + btrfs_file_extent_ram_bytes(leaf, fi); } else { /* can't happen */ BUG(); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f2dc517768f02c0dad13b65bee86201363c0162d..2a196bb134d9febda7f7d31eea396dfab4531f5b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1476,8 +1476,7 @@ static noinline int run_delalloc_nocow(struct inode *inode, nocow = 1; } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { extent_end = found_key.offset + - btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); + btrfs_file_extent_ram_bytes(leaf, fi); extent_end = ALIGN(extent_end, fs_info->sectorsize); } else { @@ -4651,8 +4650,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, BTRFS_I(inode), leaf, fi, found_key.offset); } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - item_end += btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); + item_end += btrfs_file_extent_ram_bytes(leaf, + fi); trace_btrfs_truncate_show_fi_inline( BTRFS_I(inode), leaf, fi, path->slots[0], @@ -7167,7 +7166,8 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, extent_start); } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { size_t size; - size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); + + size = btrfs_file_extent_ram_bytes(leaf, item); extent_end = ALIGN(extent_start + size, fs_info->sectorsize); @@ -7218,7 +7218,7 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, if (new_inline) goto out; - size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); + size = btrfs_file_extent_ram_bytes(leaf, item); extent_offset = page_offset(page) + pg_offset - extent_start; copy_size = min_t(u64, PAGE_SIZE - pg_offset, size - extent_offset); @@ -10639,6 +10639,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_key ins; u64 cur_offset = start; + u64 clear_offset = start; u64 i_size; u64 cur_bytes; u64 last_alloc = (u64)-1; @@ -10673,6 +10674,15 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, btrfs_end_transaction(trans); break; } + + /* + * We've reserved this space, and thus converted it from + * ->bytes_may_use to ->bytes_reserved. Any error that happens + * from here on out we will only need to clear our reservation + * for the remaining unreserved area, so advance our + * clear_offset by our extent size. + */ + clear_offset += ins.offset; btrfs_dec_block_group_reservations(fs_info, ins.objectid); last_alloc = ins.offset; @@ -10753,9 +10763,9 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, if (own_trans) btrfs_end_transaction(trans); } - if (cur_offset < end) - btrfs_free_reserved_data_space(inode, NULL, cur_offset, - end - cur_offset + 1); + if (clear_offset < end) + btrfs_free_reserved_data_space(inode, NULL, clear_offset, + end - clear_offset + 1); return ret; } diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index a3aca495e33e2c97890551b409afd1ceb40b4f69..d2287ea9fc50eef189894e5d15a94c5460667a7c 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -838,10 +838,15 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) } btrfs_start_ordered_extent(inode, ordered, 1); end = ordered->file_offset; + /* + * If the ordered extent had an error save the error but don't + * exit without waiting first for all other ordered extents in + * the range to complete. + */ if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) ret = -EIO; btrfs_put_ordered_extent(ordered); - if (ret || end == 0 || end == start) + if (end == 0 || end == start) break; end--; } diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 569205e651c7dd46c98a8fe3d0798140322d4ec3..47336d4b19d848f665db6e2549c4ad2c0d898253 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -259,8 +259,8 @@ void btrfs_print_leaf(struct extent_buffer *l) struct btrfs_file_extent_item); if (btrfs_file_extent_type(l, fi) == BTRFS_FILE_EXTENT_INLINE) { - pr_info("\t\tinline extent data size %u\n", - btrfs_file_extent_inline_len(l, i, fi)); + pr_info("\t\tinline extent data size %llu\n", + btrfs_file_extent_ram_bytes(l, fi)); break; } pr_info("\t\textent data disk bytenr %llu nr %llu\n", diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index d4c00edd16d2b20efe278804d90e4730df742148..f4397dd19583bab10693ad39d6d7aa68bba7ad92 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -538,8 +538,8 @@ static int should_ignore_root(struct btrfs_root *root) if (!reloc_root) return 0; - if (btrfs_root_last_snapshot(&reloc_root->root_item) == - root->fs_info->running_transaction->transid - 1) + if (btrfs_header_generation(reloc_root->commit_root) == + root->fs_info->running_transaction->transid) return 0; /* * if there is reloc tree and it was created in previous @@ -1194,7 +1194,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, free_backref_node(cache, lower); } - free_backref_node(cache, node); + remove_backref_node(cache, node); return ERR_PTR(err); } ASSERT(!node || !node->detached); @@ -1306,7 +1306,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root) if (!node) return -ENOMEM; - node->bytenr = root->node->start; + node->bytenr = root->commit_root->start; node->data = root; spin_lock(&rc->reloc_root_tree.lock); @@ -1337,10 +1337,11 @@ static void __del_reloc_root(struct btrfs_root *root) if (rc && root->node) { spin_lock(&rc->reloc_root_tree.lock); rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); + root->commit_root->start); if (rb_node) { node = rb_entry(rb_node, struct mapping_node, rb_node); rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + RB_CLEAR_NODE(&node->rb_node); } spin_unlock(&rc->reloc_root_tree.lock); if (!node) @@ -1358,7 +1359,7 @@ static void __del_reloc_root(struct btrfs_root *root) * helper to update the 'address of tree root -> reloc tree' * mapping */ -static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr) +static int __update_reloc_root(struct btrfs_root *root) { struct btrfs_fs_info *fs_info = root->fs_info; struct rb_node *rb_node; @@ -1367,7 +1368,7 @@ static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr) spin_lock(&rc->reloc_root_tree.lock); rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); + root->commit_root->start); if (rb_node) { node = rb_entry(rb_node, struct mapping_node, rb_node); rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); @@ -1379,7 +1380,7 @@ static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr) BUG_ON((struct btrfs_root *)node->data != root); spin_lock(&rc->reloc_root_tree.lock); - node->bytenr = new_bytenr; + node->bytenr = root->node->start; rb_node = tree_insert(&rc->reloc_root_tree.rb_root, node->bytenr, &node->rb_node); spin_unlock(&rc->reloc_root_tree.lock); @@ -1524,6 +1525,7 @@ int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, } if (reloc_root->commit_root != reloc_root->node) { + __update_reloc_root(reloc_root); btrfs_set_root_node(root_item, reloc_root->node); free_extent_buffer(reloc_root->commit_root); reloc_root->commit_root = btrfs_root_node(reloc_root); @@ -2480,7 +2482,21 @@ void merge_reloc_roots(struct reloc_control *rc) free_reloc_roots(&reloc_roots); } - BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); + /* + * We used to have + * + * BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); + * + * here, but it's wrong. If we fail to start the transaction in + * prepare_to_merge() we will have only 0 ref reloc roots, none of which + * have actually been removed from the reloc_root_tree rb tree. This is + * fine because we're bailing here, and we hold a reference on the root + * for the list that holds it, so these roots will be cleaned up when we + * do the reloc_dirty_list afterwards. Meanwhile the root->reloc_root + * will be cleaned up on unmount. + * + * The remaining nodes will be cleaned up by free_reloc_control. + */ } static void free_block_list(struct rb_root *blocks) @@ -4698,11 +4714,6 @@ int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, BUG_ON(rc->stage == UPDATE_DATA_PTRS && root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID); - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { - if (buf == root->node) - __update_reloc_root(root, cow->start); - } - level = btrfs_header_level(buf); if (btrfs_header_generation(buf) <= btrfs_root_last_snapshot(&root->root_item)) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 1211fdcd425dc867602ee488fc5fc0beab400c60..ca15d65a2070c089ba53d61c4afca06e20121578 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1545,7 +1545,7 @@ static int read_symlink(struct btrfs_root *root, BUG_ON(compression); off = btrfs_file_extent_inline_start(ei); - len = btrfs_file_extent_inline_len(path->nodes[0], path->slots[0], ei); + len = btrfs_file_extent_ram_bytes(path->nodes[0], ei); ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len); @@ -5195,7 +5195,7 @@ static int clone_range(struct send_ctx *sctx, ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); type = btrfs_file_extent_type(leaf, ei); if (type == BTRFS_FILE_EXTENT_INLINE) { - ext_len = btrfs_file_extent_inline_len(leaf, slot, ei); + ext_len = btrfs_file_extent_ram_bytes(leaf, ei); ext_len = PAGE_ALIGN(ext_len); } else { ext_len = btrfs_file_extent_num_bytes(leaf, ei); @@ -5271,8 +5271,7 @@ static int send_write_or_clone(struct send_ctx *sctx, struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], ei); if (type == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], ei); + len = btrfs_file_extent_ram_bytes(path->nodes[0], ei); /* * it is possible the inline item won't cover the whole page, * but there may be items after this page. Make @@ -5405,7 +5404,7 @@ static int is_extent_unchanged(struct send_ctx *sctx, } if (right_type == BTRFS_FILE_EXTENT_INLINE) { - right_len = btrfs_file_extent_inline_len(eb, slot, ei); + right_len = btrfs_file_extent_ram_bytes(eb, ei); right_len = PAGE_ALIGN(right_len); } else { right_len = btrfs_file_extent_num_bytes(eb, ei); @@ -5526,8 +5525,7 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset) struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], fi); if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], fi); + u64 size = btrfs_file_extent_ram_bytes(path->nodes[0], fi); extent_end = ALIGN(key.offset + size, sctx->send_root->fs_info->sectorsize); } else { @@ -5590,7 +5588,7 @@ static int range_is_hole_in_parent(struct send_ctx *sctx, fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(leaf, slot, fi); + u64 size = btrfs_file_extent_ram_bytes(leaf, fi); extent_end = ALIGN(key.offset + size, root->fs_info->sectorsize); @@ -5636,8 +5634,7 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], fi); if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], fi); + u64 size = btrfs_file_extent_ram_bytes(path->nodes[0], fi); extent_end = ALIGN(key->offset + size, sctx->send_root->fs_info->sectorsize); } else { diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3ab79fa00dc7bc02bfd6df57ef5f36488a21a657..17a8463ef35c1afb49d54b8c6fdf97a25b3e4899 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1801,6 +1801,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) } if (btrfs_super_log_root(fs_info->super_copy) != 0) { + btrfs_warn(fs_info, + "mount required to replay tree-log, cannot remount read-write"); ret = -EINVAL; goto restore; } diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c index d3f25376a0f86d255fa2db7999ff8da612422da9..6c92101e80928c794aa3ad5a3a5880cda84cd8e9 100644 --- a/fs/btrfs/tests/btrfs-tests.c +++ b/fs/btrfs/tests/btrfs-tests.c @@ -115,7 +115,6 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize) spin_lock_init(&fs_info->qgroup_op_lock); spin_lock_init(&fs_info->super_lock); spin_lock_init(&fs_info->fs_roots_radix_lock); - spin_lock_init(&fs_info->tree_mod_seq_lock); mutex_init(&fs_info->qgroup_ioctl_lock); mutex_init(&fs_info->qgroup_rescan_lock); rwlock_init(&fs_info->tree_mod_log_lock); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index fa8f56e6f66546e26a1bb8915ec806fefd053147..a066ad58197690178d722639053004ee71656659 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1948,6 +1948,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) struct btrfs_transaction *prev_trans = NULL; int ret; + /* + * Some places just start a transaction to commit it. We need to make + * sure that if this commit fails that the abort code actually marks the + * transaction as failed, so set trans->dirty to make the abort code do + * the right thing. + */ + trans->dirty = true; + /* Stop the commit early if ->aborted is set */ if (unlikely(READ_ONCE(cur_trans->aborted))) { ret = cur_trans->aborted; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 98c397eb054c5fc9db04824fb219684b54074a39..bcfb7a772c8e5b5235ee074d41fca60a1d0520a2 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -619,7 +619,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, if (btrfs_file_extent_disk_bytenr(eb, item) == 0) nbytes = 0; } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - size = btrfs_file_extent_inline_len(eb, slot, item); + size = btrfs_file_extent_ram_bytes(eb, item); nbytes = btrfs_file_extent_ram_bytes(eb, item); extent_end = ALIGN(start + size, fs_info->sectorsize); @@ -3758,7 +3758,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans, static noinline int copy_items(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_path *dst_path, - struct btrfs_path *src_path, u64 *last_extent, + struct btrfs_path *src_path, int start_slot, int nr, int inode_only, u64 logged_isize) { @@ -3769,7 +3769,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, struct btrfs_file_extent_item *extent; struct btrfs_inode_item *inode_item; struct extent_buffer *src = src_path->nodes[0]; - struct btrfs_key first_key, last_key, key; int ret; struct btrfs_key *ins_keys; u32 *ins_sizes; @@ -3777,9 +3776,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, int i; struct list_head ordered_sums; int skip_csum = inode->flags & BTRFS_INODE_NODATASUM; - bool has_extents = false; - bool need_find_last_extent = true; - bool done = false; INIT_LIST_HEAD(&ordered_sums); @@ -3788,8 +3784,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, if (!ins_data) return -ENOMEM; - first_key.objectid = (u64)-1; - ins_sizes = (u32 *)ins_data; ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); @@ -3810,9 +3804,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset = btrfs_item_ptr_offset(src, start_slot + i); - if (i == nr - 1) - last_key = ins_keys[i]; - if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { inode_item = btrfs_item_ptr(dst_path->nodes[0], dst_path->slots[0], @@ -3826,20 +3817,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset, ins_sizes[i]); } - /* - * We set need_find_last_extent here in case we know we were - * processing other items and then walk into the first extent in - * the inode. If we don't hit an extent then nothing changes, - * we'll do the last search the next time around. - */ - if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { - has_extents = true; - if (first_key.objectid == (u64)-1) - first_key = ins_keys[i]; - } else { - need_find_last_extent = false; - } - /* take a reference on file data extents so that truncates * or deletes of this inode don't have to relog the inode * again @@ -3905,169 +3882,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, kfree(sums); } - if (!has_extents) - return ret; - - if (need_find_last_extent && *last_extent == first_key.offset) { - /* - * We don't have any leafs between our current one and the one - * we processed before that can have file extent items for our - * inode (and have a generation number smaller than our current - * transaction id). - */ - need_find_last_extent = false; - } - - /* - * Because we use btrfs_search_forward we could skip leaves that were - * not modified and then assume *last_extent is valid when it really - * isn't. So back up to the previous leaf and read the end of the last - * extent before we go and fill in holes. - */ - if (need_find_last_extent) { - u64 len; - - ret = btrfs_prev_leaf(inode->root, src_path); - if (ret < 0) - return ret; - if (ret) - goto fill_holes; - if (src_path->slots[0]) - src_path->slots[0]--; - src = src_path->nodes[0]; - btrfs_item_key_to_cpu(src, &key, src_path->slots[0]); - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) - goto fill_holes; - extent = btrfs_item_ptr(src, src_path->slots[0], - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(src, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, - src_path->slots[0], - extent); - *last_extent = ALIGN(key.offset + len, - fs_info->sectorsize); - } else { - len = btrfs_file_extent_num_bytes(src, extent); - *last_extent = key.offset + len; - } - } -fill_holes: - /* So we did prev_leaf, now we need to move to the next leaf, but a few - * things could have happened - * - * 1) A merge could have happened, so we could currently be on a leaf - * that holds what we were copying in the first place. - * 2) A split could have happened, and now not all of the items we want - * are on the same leaf. - * - * So we need to adjust how we search for holes, we need to drop the - * path and re-search for the first extent key we found, and then walk - * forward until we hit the last one we copied. - */ - if (need_find_last_extent) { - /* btrfs_prev_leaf could return 1 without releasing the path */ - btrfs_release_path(src_path); - ret = btrfs_search_slot(NULL, inode->root, &first_key, - src_path, 0, 0); - if (ret < 0) - return ret; - ASSERT(ret == 0); - src = src_path->nodes[0]; - i = src_path->slots[0]; - } else { - i = start_slot; - } - - /* - * Ok so here we need to go through and fill in any holes we may have - * to make sure that holes are punched for those areas in case they had - * extents previously. - */ - while (!done) { - u64 offset, len; - u64 extent_end; - - if (i >= btrfs_header_nritems(src_path->nodes[0])) { - ret = btrfs_next_leaf(inode->root, src_path); - if (ret < 0) - return ret; - ASSERT(ret == 0); - src = src_path->nodes[0]; - i = 0; - need_find_last_extent = true; - } - - btrfs_item_key_to_cpu(src, &key, i); - if (!btrfs_comp_cpu_keys(&key, &last_key)) - done = true; - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) { - i++; - continue; - } - extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); - if (btrfs_file_extent_type(src, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, i, extent); - extent_end = ALIGN(key.offset + len, - fs_info->sectorsize); - } else { - len = btrfs_file_extent_num_bytes(src, extent); - extent_end = key.offset + len; - } - i++; - - if (*last_extent == key.offset) { - *last_extent = extent_end; - continue; - } - offset = *last_extent; - len = key.offset - *last_extent; - ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode), - offset, 0, 0, len, 0, len, 0, 0, 0); - if (ret) - break; - *last_extent = extent_end; - } - - /* - * Check if there is a hole between the last extent found in our leaf - * and the first extent in the next leaf. If there is one, we need to - * log an explicit hole so that at replay time we can punch the hole. - */ - if (ret == 0 && - key.objectid == btrfs_ino(inode) && - key.type == BTRFS_EXTENT_DATA_KEY && - i == btrfs_header_nritems(src_path->nodes[0])) { - ret = btrfs_next_leaf(inode->root, src_path); - need_find_last_extent = true; - if (ret > 0) { - ret = 0; - } else if (ret == 0) { - btrfs_item_key_to_cpu(src_path->nodes[0], &key, - src_path->slots[0]); - if (key.objectid == btrfs_ino(inode) && - key.type == BTRFS_EXTENT_DATA_KEY && - *last_extent < key.offset) { - const u64 len = key.offset - *last_extent; - - ret = btrfs_insert_file_extent(trans, log, - btrfs_ino(inode), - *last_extent, 0, - 0, len, 0, len, - 0, 0, 0); - *last_extent += len; - } - } - } - /* - * Need to let the callers know we dropped the path so they should - * re-search. - */ - if (!ret && need_find_last_extent) - ret = 1; return ret; } @@ -4340,7 +4154,10 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, const u64 i_size = i_size_read(&inode->vfs_inode); const u64 ino = btrfs_ino(inode); struct btrfs_path *dst_path = NULL; - u64 last_extent = (u64)-1; + bool dropped_extents = false; + u64 truncate_offset = i_size; + struct extent_buffer *leaf; + int slot; int ins_nr = 0; int start_slot; int ret; @@ -4355,15 +4172,48 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, if (ret < 0) goto out; + /* + * We must check if there is a prealloc extent that starts before the + * i_size and crosses the i_size boundary. This is to ensure later we + * truncate down to the end of that extent and not to the i_size, as + * otherwise we end up losing part of the prealloc extent after a log + * replay and with an implicit hole if there is another prealloc extent + * that starts at an offset beyond i_size. + */ + ret = btrfs_previous_item(root, path, ino, BTRFS_EXTENT_DATA_KEY); + if (ret < 0) + goto out; + + if (ret == 0) { + struct btrfs_file_extent_item *ei; + + leaf = path->nodes[0]; + slot = path->slots[0]; + ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + + if (btrfs_file_extent_type(leaf, ei) == + BTRFS_FILE_EXTENT_PREALLOC) { + u64 extent_end; + + btrfs_item_key_to_cpu(leaf, &key, slot); + extent_end = key.offset + + btrfs_file_extent_num_bytes(leaf, ei); + + if (extent_end > i_size) + truncate_offset = extent_end; + } + } else { + ret = 0; + } + while (true) { - struct extent_buffer *leaf = path->nodes[0]; - int slot = path->slots[0]; + leaf = path->nodes[0]; + slot = path->slots[0]; if (slot >= btrfs_header_nritems(leaf)) { if (ins_nr > 0) { ret = copy_items(trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr, 1, 0); + start_slot, ins_nr, 1, 0); if (ret < 0) goto out; ins_nr = 0; @@ -4387,8 +4237,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, path->slots[0]++; continue; } - if (last_extent == (u64)-1) { - last_extent = key.offset; + if (!dropped_extents) { /* * Avoid logging extent items logged in past fsync calls * and leading to duplicate keys in the log tree. @@ -4397,11 +4246,12 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, ret = btrfs_truncate_inode_items(trans, root->log_root, &inode->vfs_inode, - i_size, + truncate_offset, BTRFS_EXTENT_DATA_KEY); } while (ret == -EAGAIN); if (ret) goto out; + dropped_extents = true; } if (ins_nr == 0) start_slot = slot; @@ -4416,7 +4266,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, } } if (ins_nr > 0) { - ret = copy_items(trans, inode, dst_path, path, &last_extent, + ret = copy_items(trans, inode, dst_path, path, start_slot, ins_nr, 1, 0); if (ret > 0) ret = 0; @@ -4610,13 +4460,8 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans, if (slot >= nritems) { if (ins_nr > 0) { - u64 last_extent = 0; - ret = copy_items(trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr, 1, 0); - /* can't be 1, extent items aren't processed */ - ASSERT(ret <= 0); + start_slot, ins_nr, 1, 0); if (ret < 0) return ret; ins_nr = 0; @@ -4640,13 +4485,8 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans, cond_resched(); } if (ins_nr > 0) { - u64 last_extent = 0; - ret = copy_items(trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr, 1, 0); - /* can't be 1, extent items aren't processed */ - ASSERT(ret <= 0); + start_slot, ins_nr, 1, 0); if (ret < 0) return ret; } @@ -4655,109 +4495,119 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans, } /* - * If the no holes feature is enabled we need to make sure any hole between the - * last extent and the i_size of our inode is explicitly marked in the log. This - * is to make sure that doing something like: - * - * 1) create file with 128Kb of data - * 2) truncate file to 64Kb - * 3) truncate file to 256Kb - * 4) fsync file - * 5) - * 6) mount fs and trigger log replay - * - * Will give us a file with a size of 256Kb, the first 64Kb of data match what - * the file had in its first 64Kb of data at step 1 and the last 192Kb of the - * file correspond to a hole. The presence of explicit holes in a log tree is - * what guarantees that log replay will remove/adjust file extent items in the - * fs/subvol tree. - * - * Here we do not need to care about holes between extents, that is already done - * by copy_items(). We also only need to do this in the full sync path, where we - * lookup for extents from the fs/subvol tree only. In the fast path case, we - * lookup the list of modified extent maps and if any represents a hole, we - * insert a corresponding extent representing a hole in the log tree. + * When using the NO_HOLES feature if we punched a hole that causes the + * deletion of entire leafs or all the extent items of the first leaf (the one + * that contains the inode item and references) we may end up not processing + * any extents, because there are no leafs with a generation matching the + * current transaction that have extent items for our inode. So we need to find + * if any holes exist and then log them. We also need to log holes after any + * truncate operation that changes the inode's size. */ -static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_inode *inode, - struct btrfs_path *path) +static int btrfs_log_holes(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_inode *inode, + struct btrfs_path *path) { struct btrfs_fs_info *fs_info = root->fs_info; - int ret; struct btrfs_key key; - u64 hole_start; - u64 hole_size; - struct extent_buffer *leaf; - struct btrfs_root *log = root->log_root; const u64 ino = btrfs_ino(inode); const u64 i_size = i_size_read(&inode->vfs_inode); + u64 prev_extent_end = 0; + int ret; - if (!btrfs_fs_incompat(fs_info, NO_HOLES)) + if (!btrfs_fs_incompat(fs_info, NO_HOLES) || i_size == 0) return 0; key.objectid = ino; key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = (u64)-1; + key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - ASSERT(ret != 0); if (ret < 0) return ret; - ASSERT(path->slots[0] > 0); - path->slots[0]--; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY) { - /* inode does not have any extents */ - hole_start = 0; - hole_size = i_size; - } else { + while (true) { struct btrfs_file_extent_item *extent; + struct extent_buffer *leaf = path->nodes[0]; u64 len; - /* - * If there's an extent beyond i_size, an explicit hole was - * already inserted by copy_items(). - */ - if (key.offset >= i_size) - return 0; + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + return ret; + if (ret > 0) { + ret = 0; + break; + } + leaf = path->nodes[0]; + } + + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY) + break; + + /* We have a hole, log it. */ + if (prev_extent_end < key.offset) { + const u64 hole_len = key.offset - prev_extent_end; + + /* + * Release the path to avoid deadlocks with other code + * paths that search the root while holding locks on + * leafs from the log root. + */ + btrfs_release_path(path); + ret = btrfs_insert_file_extent(trans, root->log_root, + ino, prev_extent_end, 0, + 0, hole_len, 0, hole_len, + 0, 0, 0); + if (ret < 0) + return ret; + + /* + * Search for the same key again in the root. Since it's + * an extent item and we are holding the inode lock, the + * key must still exist. If it doesn't just emit warning + * and return an error to fall back to a transaction + * commit. + */ + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + return ret; + if (WARN_ON(ret > 0)) + return -ENOENT; + leaf = path->nodes[0]; + } extent = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); - if (btrfs_file_extent_type(leaf, extent) == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(leaf, - path->slots[0], - extent); - ASSERT(len == i_size || - (len == fs_info->sectorsize && - btrfs_file_extent_compression(leaf, extent) != - BTRFS_COMPRESS_NONE) || - (len < i_size && i_size < fs_info->sectorsize)); - return 0; + len = btrfs_file_extent_ram_bytes(leaf, extent); + prev_extent_end = ALIGN(key.offset + len, + fs_info->sectorsize); + } else { + len = btrfs_file_extent_num_bytes(leaf, extent); + prev_extent_end = key.offset + len; } - len = btrfs_file_extent_num_bytes(leaf, extent); - /* Last extent goes beyond i_size, no need to log a hole. */ - if (key.offset + len > i_size) - return 0; - hole_start = key.offset + len; - hole_size = i_size - hole_start; + path->slots[0]++; + cond_resched(); } - btrfs_release_path(path); - /* Last extent ends at i_size. */ - if (hole_size == 0) - return 0; + if (prev_extent_end < i_size) { + u64 hole_len; - hole_size = ALIGN(hole_size, fs_info->sectorsize); - ret = btrfs_insert_file_extent(trans, log, ino, hole_start, 0, 0, - hole_size, 0, hole_size, 0, 0, 0); - return ret; + btrfs_release_path(path); + hole_len = ALIGN(i_size - prev_extent_end, fs_info->sectorsize); + ret = btrfs_insert_file_extent(trans, root->log_root, + ino, prev_extent_end, 0, 0, + hole_len, 0, hole_len, + 0, 0, 0); + if (ret < 0) + return ret; + } + + return 0; } /* @@ -4925,7 +4775,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, struct btrfs_root *log = root->log_root; struct extent_buffer *src = NULL; LIST_HEAD(logged_list); - u64 last_extent = 0; int err = 0; int ret; int nritems; @@ -5099,7 +4948,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ins_start_slot = path->slots[0]; } ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ins_start_slot, ins_nr, inode_only, logged_isize); if (ret < 0) { @@ -5153,17 +5002,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, if (ins_nr == 0) goto next_slot; ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ins_start_slot, ins_nr, inode_only, logged_isize); if (ret < 0) { err = ret; goto out_unlock; } ins_nr = 0; - if (ret) { - btrfs_release_path(path); - continue; - } goto next_slot; } @@ -5177,18 +5022,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, goto next_slot; } - ret = copy_items(trans, inode, dst_path, path, &last_extent, + ret = copy_items(trans, inode, dst_path, path, ins_start_slot, ins_nr, inode_only, logged_isize); if (ret < 0) { err = ret; goto out_unlock; } - if (ret) { - ins_nr = 0; - btrfs_release_path(path); - continue; - } ins_nr = 1; ins_start_slot = path->slots[0]; next_slot: @@ -5202,13 +5042,12 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, } if (ins_nr) { ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ins_start_slot, ins_nr, inode_only, logged_isize); if (ret < 0) { err = ret; goto out_unlock; } - ret = 0; ins_nr = 0; } btrfs_release_path(path); @@ -5223,14 +5062,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, } } if (ins_nr) { - ret = copy_items(trans, inode, dst_path, path, &last_extent, + ret = copy_items(trans, inode, dst_path, path, ins_start_slot, ins_nr, inode_only, logged_isize); if (ret < 0) { err = ret; goto out_unlock; } - ret = 0; ins_nr = 0; } @@ -5243,7 +5081,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) { btrfs_release_path(path); btrfs_release_path(dst_path); - err = btrfs_log_trailing_hole(trans, root, inode, path); + err = btrfs_log_holes(trans, root, inode, path); if (err) goto out_unlock; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 358e930df4acd8f0d397c4e0a68db1dec0b20167..6d34842912e8048b0228ad811aaa509c322ff972 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7227,6 +7227,8 @@ int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info, else btrfs_dev_stat_reset(dev, i); } + btrfs_info(fs_info, "device stats zeroed by %s (%d)", + current->comm, task_pid_nr(current)); } else { for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) if (stats->nr_items > i) diff --git a/fs/buffer.c b/fs/buffer.c index 2ebd195996a319dfc0f0c6a9fdaa2ec7eef88978..5c85f4ef66bd616850b59637c6a5feb165dcf46b 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -46,6 +46,7 @@ #include #include #include +#include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, @@ -1398,6 +1399,17 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size) } EXPORT_SYMBOL(__breadahead); +void __breadahead_gfp(struct block_device *bdev, sector_t block, unsigned size, + gfp_t gfp) +{ + struct buffer_head *bh = __getblk_gfp(bdev, block, size, gfp); + if (likely(bh)) { + ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, &bh); + brelse(bh); + } +} +EXPORT_SYMBOL(__breadahead_gfp); + /** * __bread_gfp() - reads a specified block and returns the bh * @bdev: the block_device to read from @@ -3161,6 +3173,8 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, */ bio = bio_alloc(GFP_NOIO, 1); + fscrypt_set_bio_crypt_ctx_bh(bio, bh, GFP_NOIO); + if (wbc) { wbc_init_bio(wbc, bio); wbc_account_io(wbc, bh->b_page, bh->b_size); diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index c3a3ee74e2d840758c470253efd5ae78c96853bb..1b5a50848b5be486ce9ad76b6508b1feb3e8d267 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1863,8 +1863,12 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, } /* want more caps from mds? */ - if (want & ~(cap->mds_wanted | cap->issued)) - goto ack; + if (want & ~cap->mds_wanted) { + if (want & ~(cap->mds_wanted | cap->issued)) + goto ack; + if (!__cap_is_valid(cap)) + goto ack; + } /* things we might delay */ if ((cap->issued & ~retain) == 0 && diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 3c59ad180ef0bb5b9dfb09528e5c1dc363f9b94e..4cfe1154d4c726f621b5a6f689f7e7b05ca52a39 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -151,6 +151,11 @@ static struct dentry *__get_parent(struct super_block *sb, req->r_num_caps = 1; err = ceph_mdsc_do_request(mdsc, NULL, req); + if (err) { + ceph_mdsc_put_request(req); + return ERR_PTR(err); + } + inode = req->r_target_inode; if (inode) ihold(inode); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b968334f841e81df35e2fe117035e5a6fbbc467a..f36ddfea4997e826307a368c54203adad11e0bb1 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2261,8 +2261,7 @@ static int __do_request(struct ceph_mds_client *mdsc, if (!(mdsc->fsc->mount_options->flags & CEPH_MOUNT_OPT_MOUNTWAIT) && !ceph_mdsmap_is_cluster_available(mdsc->mdsmap)) { - err = -ENOENT; - pr_info("probably no mds server is up\n"); + err = -EHOSTUNREACH; goto finish; } } diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 088c4488b4492cf705ba13f35a7196e8c80bfb0a..caa6780d8ff2f9e1b61e67e40ad3da3cabcecfd5 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -92,7 +92,6 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } - static int ceph_sync_fs(struct super_block *sb, int wait) { struct ceph_fs_client *fsc = ceph_sb_to_client(sb); @@ -189,6 +188,26 @@ static match_table_t fsopt_tokens = { {-1, NULL} }; +/* + * Remove adjacent slashes and then the trailing slash, unless it is + * the only remaining character. + * + * E.g. "//dir1////dir2///" --> "/dir1/dir2", "///" --> "/". + */ +static void canonicalize_path(char *path) +{ + int i, j = 0; + + for (i = 0; path[i] != '\0'; i++) { + if (path[i] != '/' || j < 1 || path[j - 1] != '/') + path[j++] = path[i]; + } + + if (j > 1 && path[j - 1] == '/') + j--; + path[j] = '\0'; +} + static int parse_fsopt_token(char *c, void *private) { struct ceph_mount_options *fsopt = private; @@ -390,12 +409,15 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt, ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name); if (ret) return ret; + ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace); if (ret) return ret; + ret = strcmp_null(fsopt1->server_path, fsopt2->server_path); if (ret) return ret; + ret = strcmp_null(fsopt1->fscache_uniq, fsopt2->fscache_uniq); if (ret) return ret; @@ -451,13 +473,17 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt, */ dev_name_end = strchr(dev_name, '/'); if (dev_name_end) { - if (strlen(dev_name_end) > 1) { - fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL); - if (!fsopt->server_path) { - err = -ENOMEM; - goto out; - } + /* + * The server_path will include the whole chars from userland + * including the leading '/'. + */ + fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL); + if (!fsopt->server_path) { + err = -ENOMEM; + goto out; } + + canonicalize_path(fsopt->server_path); } else { dev_name_end = dev_name + strlen(dev_name); } @@ -760,7 +786,6 @@ static void destroy_caches(void) ceph_fscache_unregister(); } - /* * ceph_umount_begin - initiate forced umount. Tear down down the * mount, skipping steps that may hang while waiting for server(s). @@ -845,9 +870,6 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, return root; } - - - /* * mount: join the ceph cluster, and open root directory. */ @@ -861,7 +883,9 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) mutex_lock(&fsc->client->mount_mutex); if (!fsc->sb->s_root) { - const char *path; + const char *path = fsc->mount_options->server_path ? + fsc->mount_options->server_path + 1 : ""; + err = __ceph_open_session(fsc->client, started); if (err < 0) goto out; @@ -873,13 +897,7 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) goto out; } - if (!fsc->mount_options->server_path) { - path = ""; - dout("mount opening path \\t\n"); - } else { - path = fsc->mount_options->server_path + 1; - dout("mount opening path %s\n", path); - } + dout("mount opening path '%s'\n", path); err = ceph_fs_debugfs_init(fsc); if (err < 0) @@ -1055,6 +1073,11 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type, return res; out_splat: + if (!ceph_mdsmap_is_cluster_available(fsc->mdsc->mdsmap)) { + pr_info("No mds server is up or the cluster is laggy\n"); + err = -EHOSTUNREACH; + } + ceph_mdsc_close_sessions(fsc->mdsc); deactivate_locked_super(sb); goto out_final; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 46f600107cb5b327bb86e4d5b193c523f6bbfc3a..dd5257dee6cb040376185833e8929d338e356d55 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -85,7 +85,7 @@ struct ceph_mount_options { char *snapdir_name; /* default ".snap" */ char *mds_namespace; /* default NULL */ - char *server_path; /* default "/" */ + char *server_path; /* default NULL (means "/") */ char *fscache_uniq; /* default NULL */ }; diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index b98436f5c7c74f9e773db0485bb9e80fcb43be99..73d428af97a9e974ad5450170dbbedfd3da48be5 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -603,7 +603,7 @@ static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode, ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) *pmode |= (S_IXUGO & (*pbits_to_set)); - cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode); + cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode); return; } @@ -632,7 +632,7 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use, if (mode & S_IXUGO) *pace_flags |= SET_FILE_EXEC_RIGHTS; - cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n", + cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n", mode, *pace_flags); return; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f0b1279a7de66716ecde8d3329784f5aba031127..58e7288e5151cedef80711f28f8339d36ddfd1c6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -348,8 +348,10 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server) return rc; } + spin_lock(&cifs_tcp_ses_lock); rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr, strlen(ipaddr)); + spin_unlock(&cifs_tcp_ses_lock); kfree(ipaddr); return !rc ? -1 : 0; @@ -3047,8 +3049,10 @@ match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data) { struct cifs_sb_info *old = CIFS_SB(sb); struct cifs_sb_info *new = mnt_data->cifs_sb; - bool old_set = old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH; - bool new_set = new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH; + bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && + old->prepath; + bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && + new->prepath; if (old_set && new_set && !strcmp(new->prepath, old->prepath)) return 1; @@ -3519,7 +3523,7 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_gid = pvolume_info->linux_gid; cifs_sb->mnt_file_mode = pvolume_info->file_mode; cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; - cifs_dbg(FYI, "file mode: 0x%hx dir mode: 0x%hx\n", + cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); cifs_sb->actimeo = pvolume_info->actimeo; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f00a7ce3eb6e4fa86f3c24bfeef291f7fbf17828..03293e543c075a2f41911b7f679b91178035af9f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -562,7 +562,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, if (server->ops->close) server->ops->close(xid, tcon, &fid); cifs_del_pending_open(&open); - fput(file); rc = -ENOMEM; } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5e75c5f77f4ceea9eb7025aec90d04d2f0a13f0c..662977b8d6aeada1da5b1ad126be437cd7354fac 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3303,7 +3303,7 @@ collect_uncached_read_data(struct cifs_aio_ctx *ctx) if (rc == -ENODATA) rc = 0; - ctx->rc = (rc == 0) ? ctx->total_len : rc; + ctx->rc = (rc == 0) ? (ssize_t)ctx->total_len : rc; mutex_unlock(&ctx->aio_mutex); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a35c1410590676bfff56b34575797ac8d6dc0b41..bdce714e9448950f4fff2deca667e929128762e1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1581,7 +1581,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) struct TCP_Server_Info *server; char *full_path; - cifs_dbg(FYI, "In cifs_mkdir, mode = 0x%hx inode = 0x%p\n", + cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n", mode, inode); cifs_sb = CIFS_SB(inode->i_sb); @@ -1998,6 +1998,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) struct inode *inode = d_inode(dentry); struct super_block *sb = dentry->d_sb; char *full_path = NULL; + int count = 0; if (inode == NULL) return -ENOENT; @@ -2019,15 +2020,18 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) full_path, inode, inode->i_count.counter, dentry, cifs_get_time(dentry), jiffies); +again: if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); - + if (rc == -EAGAIN && count++ < 10) + goto again; out: kfree(full_path); free_xid(xid); + return rc; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 4eb0a9e7194b1ce8bc237a57ca702614023ed4c4..1c87a429ce72f66f5d65e70a845ed1a7b03abe9f 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -257,9 +257,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) } rc = cifs_negotiate_protocol(0, tcon->ses); - if (!rc && tcon->ses->need_reconnect) + if (!rc && tcon->ses->need_reconnect) { rc = cifs_setup_session(0, tcon->ses, nls_codepage); - + if ((rc == -EACCES) && !tcon->retry) { + rc = -EHOSTDOWN; + mutex_unlock(&tcon->ses->session_mutex); + goto failed; + } + } if (rc || !tcon->need_reconnect) { mutex_unlock(&tcon->ses->session_mutex); goto out; @@ -301,6 +306,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) case SMB2_SET_INFO: rc = -EAGAIN; } +failed: unload_nls(nls_codepage); return rc; } diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig index 4bc66f2c571e40be4a88002b98da1d0e289ccd9f..97c0a113f4cc636783d0dd8367327123e8fc0d23 100644 --- a/fs/crypto/Kconfig +++ b/fs/crypto/Kconfig @@ -1,13 +1,8 @@ config FS_ENCRYPTION bool "FS Encryption (Per-file encryption)" select CRYPTO - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_XTS - select CRYPTO_CTS - select CRYPTO_SHA512 - select CRYPTO_HMAC + select CRYPTO_HASH + select CRYPTO_BLKCIPHER select KEYS help Enable encryption of files and directories. This @@ -15,3 +10,22 @@ config FS_ENCRYPTION efficient since it avoids caching the encrypted and decrypted pages in the page cache. Currently Ext4, F2FS and UBIFS make use of this feature. + +# Filesystems supporting encryption must select this if FS_ENCRYPTION. This +# allows the algorithms to be built as modules when all the filesystems are. +config FS_ENCRYPTION_ALGS + tristate + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_CTS + select CRYPTO_ECB + select CRYPTO_HMAC + select CRYPTO_SHA256 + select CRYPTO_SHA512 + select CRYPTO_XTS + +config FS_ENCRYPTION_INLINE_CRYPT + bool "Enable fscrypt to use inline crypto" + depends on FS_ENCRYPTION && BLK_INLINE_ENCRYPTION + help + Enable fscrypt to use inline encryption hardware if available. diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index f36e47a10455e6507f895676eef0cc105feb685f..1a6b0774f3ff4a380ff2da64b861236a4c8863f5 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,16 +1,13 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o -ccflags-y += -Ifs/ext4 -ccflags-y += -Ifs/f2fs - fscrypto-y := crypto.o \ fname.o \ hkdf.o \ hooks.o \ keyring.o \ keysetup.o \ - fscrypt_ice.o \ keysetup_v1.o \ policy.o fscrypto-$(CONFIG_BLOCK) += bio.o +fscrypto-$(CONFIG_FS_ENCRYPTION_INLINE_CRYPT) += inline_crypt.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index b0033880d8c96a20e8a578b51f61fd8c6c280e6e..aa36d245f548ded2a2e652426e601872557d8980 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -33,65 +33,162 @@ void fscrypt_decrypt_bio(struct bio *bio) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (fscrypt_using_hardware_encryption(page->mapping->host)) { - SetPageUptodate(page); - } else { - int ret = fscrypt_decrypt_pagecache_blocks(page, - bv->bv_len, bv->bv_offset); - if (ret) - SetPageError(page); - } + int ret = fscrypt_decrypt_pagecache_blocks(page, + bv->bv_len, bv->bv_offset); + if (ret) + SetPageError(page); } } EXPORT_SYMBOL(fscrypt_decrypt_bio); +static int fscrypt_zeroout_range_inlinecrypt(const struct inode *inode, + pgoff_t lblk, + sector_t pblk, unsigned int len) +{ + const unsigned int blockbits = inode->i_blkbits; + const unsigned int blocks_per_page_bits = PAGE_SHIFT - blockbits; + const unsigned int blocks_per_page = 1 << blocks_per_page_bits; + unsigned int i; + struct bio *bio; + int ret, err; + + /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */ + bio = bio_alloc(GFP_NOFS, BIO_MAX_PAGES); + + do { + bio_set_dev(bio, inode->i_sb->s_bdev); + bio->bi_iter.bi_sector = pblk << (blockbits - 9); + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOFS); + + i = 0; + do { + unsigned int blocks_this_page = + min(len, blocks_per_page); + unsigned int bytes_this_page = + blocks_this_page << blockbits; + + ret = bio_add_page(bio, ZERO_PAGE(0), + bytes_this_page, 0); + if (WARN_ON(ret != bytes_this_page)) { + err = -EIO; + goto out; + } + lblk += blocks_this_page; + pblk += blocks_this_page; + len -= blocks_this_page; + } while (++i != BIO_MAX_PAGES && len != 0); + + err = submit_bio_wait(bio); + if (err) + goto out; + bio_reset(bio); + } while (len != 0); + err = 0; +out: + bio_put(bio); + return err; +} + +/** + * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file + * @inode: the file's inode + * @lblk: the first file logical block to zero out + * @pblk: the first filesystem physical block to zero out + * @len: number of blocks to zero out + * + * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write + * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be + * both logically and physically contiguous. It's also assumed that the + * filesystem only uses a single block device, ->s_bdev. + * + * Note that since each block uses a different IV, this involves writing a + * different ciphertext to each block; we can't simply reuse the same one. + * + * Return: 0 on success; -errno on failure. + */ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, - sector_t pblk, unsigned int len) + sector_t pblk, unsigned int len) { const unsigned int blockbits = inode->i_blkbits; const unsigned int blocksize = 1 << blockbits; - struct page *ciphertext_page; + const unsigned int blocks_per_page_bits = PAGE_SHIFT - blockbits; + const unsigned int blocks_per_page = 1 << blocks_per_page_bits; + struct page *pages[16]; /* write up to 16 pages at a time */ + unsigned int nr_pages; + unsigned int i; + unsigned int offset; struct bio *bio; - int ret, err = 0; + int ret, err; - ciphertext_page = fscrypt_alloc_bounce_page(GFP_NOWAIT); - if (!ciphertext_page) - return -ENOMEM; + if (len == 0) + return 0; - while (len--) { - err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk, - ZERO_PAGE(0), ciphertext_page, - blocksize, 0, GFP_NOFS); - if (err) - goto errout; + if (fscrypt_inode_uses_inline_crypto(inode)) + return fscrypt_zeroout_range_inlinecrypt(inode, lblk, pblk, + len); - bio = bio_alloc(GFP_NOWAIT, 1); - if (!bio) { - err = -ENOMEM; - goto errout; - } + BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_PAGES); + nr_pages = min_t(unsigned int, ARRAY_SIZE(pages), + (len + blocks_per_page - 1) >> blocks_per_page_bits); + + /* + * We need at least one page for ciphertext. Allocate the first one + * from a mempool, with __GFP_DIRECT_RECLAIM set so that it can't fail. + * + * Any additional page allocations are allowed to fail, as they only + * help performance, and waiting on the mempool for them could deadlock. + */ + for (i = 0; i < nr_pages; i++) { + pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS : + GFP_NOWAIT | __GFP_NOWARN); + if (!pages[i]) + break; + } + nr_pages = i; + if (WARN_ON(nr_pages <= 0)) + return -EINVAL; + + /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */ + bio = bio_alloc(GFP_NOFS, nr_pages); + + do { bio_set_dev(bio, inode->i_sb->s_bdev); bio->bi_iter.bi_sector = pblk << (blockbits - 9); - bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_NOENCRYPT); - ret = bio_add_page(bio, ciphertext_page, blocksize, 0); - if (WARN_ON(ret != blocksize)) { - /* should never happen! */ - bio_put(bio); - err = -EIO; - goto errout; - } + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + + i = 0; + offset = 0; + do { + err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk, + ZERO_PAGE(0), pages[i], + blocksize, offset, GFP_NOFS); + if (err) + goto out; + lblk++; + pblk++; + len--; + offset += blocksize; + if (offset == PAGE_SIZE || len == 0) { + ret = bio_add_page(bio, pages[i++], offset, 0); + if (WARN_ON(ret != offset)) { + err = -EIO; + goto out; + } + offset = 0; + } + } while (i != nr_pages && len != 0); + err = submit_bio_wait(bio); - if (err == 0 && bio->bi_status) - err = -EIO; - bio_put(bio); if (err) - goto errout; - lblk++; - pblk++; - } + goto out; + bio_reset(bio); + } while (len != 0); err = 0; -errout: - fscrypt_free_bounce_page(ciphertext_page); +out: + bio_put(bio); + for (i = 0; i < nr_pages; i++) + fscrypt_free_bounce_page(pages[i]); return err; } EXPORT_SYMBOL(fscrypt_zeroout_range); diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 6e6f39ea18a7987c2919a0f9b10972bcd91140b2..02ab7b76d157d3340dcee324c085d9ace7e54a8b 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include "fscrypt_private.h" @@ -69,16 +67,35 @@ void fscrypt_free_bounce_page(struct page *bounce_page) } EXPORT_SYMBOL(fscrypt_free_bounce_page); +/* + * Generate the IV for the given logical block number within the given file. + * For filenames encryption, lblk_num == 0. + * + * Keep this in sync with fscrypt_limit_dio_pages(). fscrypt_limit_dio_pages() + * needs to know about any IV generation methods where the low bits of IV don't + * simply contain the lblk_num (e.g., IV_INO_LBLK_32). + */ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci) { u8 flags = fscrypt_policy_flags(&ci->ci_policy); + bool inlinecrypt = false; + +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT + inlinecrypt = ci->ci_inlinecrypt; +#endif memset(iv, 0, ci->ci_mode->ivsize); - if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { - WARN_ON_ONCE((u32)lblk_num != lblk_num); + if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 || + ((fscrypt_policy_contents_mode(&ci->ci_policy) == + FSCRYPT_MODE_PRIVATE) && inlinecrypt)) { + WARN_ON_ONCE(lblk_num > U32_MAX); + WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; + } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { + WARN_ON_ONCE(lblk_num > U32_MAX); + lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); } @@ -96,7 +113,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_ctfm; + struct crypto_skcipher *tfm = ci->ci_key.tfm; int res = 0; if (WARN_ON_ONCE(len <= 0)) @@ -139,7 +156,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, * multiple of the filesystem's block size. * @offs: Byte offset within @page of the first block to encrypt. Must be * a multiple of the filesystem's block size. - * @gfp_flags: Memory allocation flags + * @gfp_flags: Memory allocation flags. See details below. * * A new bounce page is allocated, and the specified block(s) are encrypted into * it. In the bounce page, the ciphertext block(s) will be located at the same @@ -149,6 +166,11 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, * * This is for use by the filesystem's ->writepages() method. * + * The bounce page allocation is mempool-backed, so it will always succeed when + * @gfp_flags includes __GFP_DIRECT_RECLAIM, e.g. when it's GFP_NOFS. However, + * only the first page of each bio can be allocated this way. To prevent + * deadlocks, for any additional pages a mask like GFP_NOWAIT must be used. + * * Return: the new encrypted bounce page on success; an ERR_PTR() on failure */ struct page *fscrypt_encrypt_pagecache_blocks(struct page *page, @@ -285,54 +307,6 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page, } EXPORT_SYMBOL(fscrypt_decrypt_block_inplace); -/* - * Validate dentries in encrypted directories to make sure we aren't potentially - * caching stale dentries after a key has been added. - */ -static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) -{ - struct dentry *dir; - int err; - int valid; - - /* - * Plaintext names are always valid, since fscrypt doesn't support - * reverting to ciphertext names without evicting the directory's inode - * -- which implies eviction of the dentries in the directory. - */ - if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME)) - return 1; - - /* - * Ciphertext name; valid if the directory's key is still unavailable. - * - * Although fscrypt forbids rename() on ciphertext names, we still must - * use dget_parent() here rather than use ->d_parent directly. That's - * because a corrupted fs image may contain directory hard links, which - * the VFS handles by moving the directory's dentry tree in the dcache - * each time ->lookup() finds the directory and it already has a dentry - * elsewhere. Thus ->d_parent can be changing, and we must safely grab - * a reference to some ->d_parent to prevent it from being freed. - */ - - if (flags & LOOKUP_RCU) - return -ECHILD; - - dir = dget_parent(dentry); - err = fscrypt_get_encryption_info(d_inode(dir)); - valid = !fscrypt_has_encryption_key(d_inode(dir)); - dput(dir); - - if (err < 0) - return err; - - return valid; -} - -const struct dentry_operations fscrypt_d_ops = { - .d_revalidate = fscrypt_d_revalidate, -}; - /** * fscrypt_initialize() - allocate major buffers for fs encryption. * @cop_flags: fscrypt operations flags diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 3da3707c10e33d4fef01248bbb1acaf4695153ab..63bfe5e8accd2814f49159d541727a77f8fbb2a4 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -11,10 +11,88 @@ * This has not yet undergone a rigorous security audit. */ +#include #include +#include +#include #include #include "fscrypt_private.h" +/** + * struct fscrypt_nokey_name - identifier for directory entry when key is absent + * + * When userspace lists an encrypted directory without access to the key, the + * filesystem must present a unique "no-key name" for each filename that allows + * it to find the directory entry again if requested. Naively, that would just + * mean using the ciphertext filenames. However, since the ciphertext filenames + * can contain illegal characters ('\0' and '/'), they must be encoded in some + * way. We use base64. But that can cause names to exceed NAME_MAX (255 + * bytes), so we also need to use a strong hash to abbreviate long names. + * + * The filesystem may also need another kind of hash, the "dirhash", to quickly + * find the directory entry. Since filesystems normally compute the dirhash + * over the on-disk filename (i.e. the ciphertext), it's not computable from + * no-key names that abbreviate the ciphertext using the strong hash to fit in + * NAME_MAX. It's also not computable if it's a keyed hash taken over the + * plaintext (but it may still be available in the on-disk directory entry); + * casefolded directories use this type of dirhash. At least in these cases, + * each no-key name must include the name's dirhash too. + * + * To meet all these requirements, we base64-encode the following + * variable-length structure. It contains the dirhash, or 0's if the filesystem + * didn't provide one; up to 149 bytes of the ciphertext name; and for + * ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes. + * + * This ensures that each no-key name contains everything needed to find the + * directory entry again, contains only legal characters, doesn't exceed + * NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only + * take the performance hit of SHA-256 on very long filenames (which are rare). + */ +struct fscrypt_nokey_name { + u32 dirhash[2]; + u8 bytes[149]; + u8 sha256[SHA256_DIGEST_SIZE]; +}; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */ + +/* + * Decoded size of max-size nokey name, i.e. a name that was abbreviated using + * the strong hash and thus includes the 'sha256' field. This isn't simply + * sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included. + */ +#define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256) + +static struct crypto_shash *sha256_hash_tfm; + +static int fscrypt_do_sha256(const u8 *data, unsigned int data_len, u8 *result) +{ + struct crypto_shash *tfm = READ_ONCE(sha256_hash_tfm); + + if (unlikely(!tfm)) { + struct crypto_shash *prev_tfm; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + fscrypt_err(NULL, + "Error allocating SHA-256 transform: %ld", + PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + prev_tfm = cmpxchg(&sha256_hash_tfm, NULL, tfm); + if (prev_tfm) { + crypto_free_shash(tfm); + tfm = prev_tfm; + } + } + { + SHASH_DESC_ON_STACK(desc, tfm); + + desc->tfm = tfm; + desc->flags = 0; + + return crypto_shash_digest(desc, data, data_len, result); + } +} + static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) { if (str->len == 1 && str->name[0] == '.') @@ -27,20 +105,20 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) } /** - * fname_encrypt() - encrypt a filename + * fscrypt_fname_encrypt() - encrypt a filename * * The output buffer must be at least as large as the input buffer. * Any extra space is filled with NUL padding before encryption. * * Return: 0 on success, -errno on failure */ -int fname_encrypt(struct inode *inode, const struct qstr *iname, - u8 *out, unsigned int olen) +int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); - struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_ctfm; + const struct fscrypt_info *ci = inode->i_crypt_info; + struct crypto_skcipher *tfm = ci->ci_key.tfm; union fscrypt_iv iv; struct scatterlist sg; int res; @@ -85,15 +163,15 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname, * * Return: 0 on success, -errno on failure */ -static int fname_decrypt(struct inode *inode, - const struct fscrypt_str *iname, - struct fscrypt_str *oname) +static int fname_decrypt(const struct inode *inode, + const struct fscrypt_str *iname, + struct fscrypt_str *oname) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist src_sg, dst_sg; - struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_ctfm; + const struct fscrypt_info *ci = inode->i_crypt_info; + struct crypto_skcipher *tfm = ci->ci_key.tfm; union fscrypt_iv iv; int res; @@ -206,9 +284,7 @@ int fscrypt_fname_alloc_buffer(const struct inode *inode, u32 max_encrypted_len, struct fscrypt_str *crypto_str) { - const u32 max_encoded_len = - max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE), - 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name))); + const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX); u32 max_presented_len; max_presented_len = max(max_encoded_len, max_encrypted_len); @@ -241,19 +317,21 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer); * * The caller must have allocated sufficient memory for the @oname string. * - * If the key is available, we'll decrypt the disk name; otherwise, we'll encode - * it for presentation. Short names are directly base64-encoded, while long - * names are encoded in fscrypt_digested_name format. + * If the key is available, we'll decrypt the disk name. Otherwise, we'll + * encode it for presentation in fscrypt_nokey_name format. + * See struct fscrypt_nokey_name for details. * * Return: 0 on success, -errno on failure */ -int fscrypt_fname_disk_to_usr(struct inode *inode, - u32 hash, u32 minor_hash, - const struct fscrypt_str *iname, - struct fscrypt_str *oname) +int fscrypt_fname_disk_to_usr(const struct inode *inode, + u32 hash, u32 minor_hash, + const struct fscrypt_str *iname, + struct fscrypt_str *oname) { const struct qstr qname = FSTR_TO_QSTR(iname); - struct fscrypt_digested_name digested_name; + struct fscrypt_nokey_name nokey_name; + u32 size; /* size of the unencoded no-key name */ + int err; if (fscrypt_is_dot_dotdot(&qname)) { oname->name[0] = '.'; @@ -268,24 +346,37 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, if (fscrypt_has_encryption_key(inode)) return fname_decrypt(inode, iname, oname); - if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) { - oname->len = base64_encode(iname->name, iname->len, - oname->name); - return 0; - } + /* + * Sanity check that struct fscrypt_nokey_name doesn't have padding + * between fields and that its encoded size never exceeds NAME_MAX. + */ + BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, dirhash) != + offsetof(struct fscrypt_nokey_name, bytes)); + BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) != + offsetof(struct fscrypt_nokey_name, sha256)); + BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX); + if (hash) { - digested_name.hash = hash; - digested_name.minor_hash = minor_hash; + nokey_name.dirhash[0] = hash; + nokey_name.dirhash[1] = minor_hash; + } else { + nokey_name.dirhash[0] = 0; + nokey_name.dirhash[1] = 0; + } + if (iname->len <= sizeof(nokey_name.bytes)) { + memcpy(nokey_name.bytes, iname->name, iname->len); + size = offsetof(struct fscrypt_nokey_name, bytes[iname->len]); } else { - digested_name.hash = 0; - digested_name.minor_hash = 0; + memcpy(nokey_name.bytes, iname->name, sizeof(nokey_name.bytes)); + /* Compute strong hash of remaining part of name. */ + err = fscrypt_do_sha256(&iname->name[sizeof(nokey_name.bytes)], + iname->len - sizeof(nokey_name.bytes), + nokey_name.sha256); + if (err) + return err; + size = FSCRYPT_NOKEY_NAME_MAX; } - memcpy(digested_name.digest, - FSCRYPT_FNAME_DIGEST(iname->name, iname->len), - FSCRYPT_FNAME_DIGEST_SIZE); - oname->name[0] = '_'; - oname->len = 1 + base64_encode((const u8 *)&digested_name, - sizeof(digested_name), oname->name + 1); + oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name); return 0; } EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); @@ -306,8 +397,7 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); * get the disk_name. * * Else, for keyless @lookup operations, @iname is the presented ciphertext, so - * we decode it to get either the ciphertext disk_name (for short names) or the - * fscrypt_digested_name (for long names). Non-@lookup operations will be + * we decode it to get the fscrypt_nokey_name. Non-@lookup operations will be * impossible in this case, so we fail them with ENOKEY. * * If successful, fscrypt_free_filename() must be called later to clean up. @@ -317,8 +407,8 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, int lookup, struct fscrypt_name *fname) { + struct fscrypt_nokey_name *nokey_name; int ret; - int digested; memset(fname, 0, sizeof(struct fscrypt_name)); fname->usr_fname = iname; @@ -342,8 +432,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, if (!fname->crypto_buf.name) return -ENOMEM; - ret = fname_encrypt(dir, iname, fname->crypto_buf.name, - fname->crypto_buf.len); + ret = fscrypt_fname_encrypt(dir, iname, fname->crypto_buf.name, + fname->crypto_buf.len); if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; @@ -358,40 +448,31 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, * We don't have the key and we are doing a lookup; decode the * user-supplied name */ - if (iname->name[0] == '_') { - if (iname->len != - 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name))) - return -ENOENT; - digested = 1; - } else { - if (iname->len > - BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE)) - return -ENOENT; - digested = 0; - } - fname->crypto_buf.name = - kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE, - sizeof(struct fscrypt_digested_name)), - GFP_KERNEL); + if (iname->len > BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX)) + return -ENOENT; + + fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL); if (fname->crypto_buf.name == NULL) return -ENOMEM; - ret = base64_decode(iname->name + digested, iname->len - digested, - fname->crypto_buf.name); - if (ret < 0) { + ret = base64_decode(iname->name, iname->len, fname->crypto_buf.name); + if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) || + (ret > offsetof(struct fscrypt_nokey_name, sha256) && + ret != FSCRYPT_NOKEY_NAME_MAX)) { ret = -ENOENT; goto errout; } fname->crypto_buf.len = ret; - if (digested) { - const struct fscrypt_digested_name *n = - (const void *)fname->crypto_buf.name; - fname->hash = n->hash; - fname->minor_hash = n->minor_hash; - } else { - fname->disk_name.name = fname->crypto_buf.name; - fname->disk_name.len = fname->crypto_buf.len; + + nokey_name = (void *)fname->crypto_buf.name; + fname->hash = nokey_name->dirhash[0]; + fname->minor_hash = nokey_name->dirhash[1]; + if (ret != FSCRYPT_NOKEY_NAME_MAX) { + /* The full ciphertext filename is available. */ + fname->disk_name.name = nokey_name->bytes; + fname->disk_name.len = + ret - offsetof(struct fscrypt_nokey_name, bytes); } return 0; @@ -400,3 +481,106 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return ret; } EXPORT_SYMBOL(fscrypt_setup_filename); + +/** + * fscrypt_match_name() - test whether the given name matches a directory entry + * @fname: the name being searched for + * @de_name: the name from the directory entry + * @de_name_len: the length of @de_name in bytes + * + * Normally @fname->disk_name will be set, and in that case we simply compare + * that to the name stored in the directory entry. The only exception is that + * if we don't have the key for an encrypted directory and the name we're + * looking for is very long, then we won't have the full disk_name and instead + * we'll need to match against a fscrypt_nokey_name that includes a strong hash. + * + * Return: %true if the name matches, otherwise %false. + */ +bool fscrypt_match_name(const struct fscrypt_name *fname, + const u8 *de_name, u32 de_name_len) +{ + const struct fscrypt_nokey_name *nokey_name = + (const void *)fname->crypto_buf.name; + u8 sha256[SHA256_DIGEST_SIZE]; + + if (likely(fname->disk_name.name)) { + if (de_name_len != fname->disk_name.len) + return false; + return !memcmp(de_name, fname->disk_name.name, de_name_len); + } + if (de_name_len <= sizeof(nokey_name->bytes)) + return false; + if (memcmp(de_name, nokey_name->bytes, sizeof(nokey_name->bytes))) + return false; + if (fscrypt_do_sha256(&de_name[sizeof(nokey_name->bytes)], + de_name_len - sizeof(nokey_name->bytes), sha256)) + return false; + return !memcmp(sha256, nokey_name->sha256, sizeof(sha256)); +} +EXPORT_SYMBOL_GPL(fscrypt_match_name); + +/** + * fscrypt_fname_siphash() - calculate the SipHash of a filename + * @dir: the parent directory + * @name: the filename to calculate the SipHash of + * + * Given a plaintext filename @name and a directory @dir which uses SipHash as + * its dirhash method and has had its fscrypt key set up, this function + * calculates the SipHash of that name using the directory's secret dirhash key. + * + * Return: the SipHash of @name using the hash key of @dir + */ +u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name) +{ + const struct fscrypt_info *ci = dir->i_crypt_info; + + WARN_ON(!ci->ci_dirhash_key_initialized); + + return siphash(name->name, name->len, &ci->ci_dirhash_key); +} +EXPORT_SYMBOL_GPL(fscrypt_fname_siphash); + +/* + * Validate dentries in encrypted directories to make sure we aren't potentially + * caching stale dentries after a key has been added. + */ +int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct dentry *dir; + int err; + int valid; + + /* + * Plaintext names are always valid, since fscrypt doesn't support + * reverting to ciphertext names without evicting the directory's inode + * -- which implies eviction of the dentries in the directory. + */ + if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME)) + return 1; + + /* + * Ciphertext name; valid if the directory's key is still unavailable. + * + * Although fscrypt forbids rename() on ciphertext names, we still must + * use dget_parent() here rather than use ->d_parent directly. That's + * because a corrupted fs image may contain directory hard links, which + * the VFS handles by moving the directory's dentry tree in the dcache + * each time ->lookup() finds the directory and it already has a dentry + * elsewhere. Thus ->d_parent can be changing, and we must safely grab + * a reference to some ->d_parent to prevent it from being freed. + */ + + if (flags & LOOKUP_RCU) + return -ECHILD; + + dir = dget_parent(dentry); + err = fscrypt_get_encryption_info(d_inode(dir)); + valid = !fscrypt_has_encryption_key(d_inode(dir)); + dput(dir); + + if (err < 0) + return err; + + return valid; +} +EXPORT_SYMBOL(fscrypt_d_revalidate); diff --git a/fs/crypto/fscrypt_ice.c b/fs/crypto/fscrypt_ice.c deleted file mode 100644 index c5b6bdf3b3eb22e4be8b749b81fa01803dd91010..0000000000000000000000000000000000000000 --- a/fs/crypto/fscrypt_ice.c +++ /dev/null @@ -1,190 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "fscrypt_ice.h" - -extern int fscrypt_get_mode_key_size(int mode); - -int fscrypt_using_hardware_encryption(const struct inode *inode) -{ - struct fscrypt_info *ci = inode->i_crypt_info; - - return S_ISREG(inode->i_mode) && ci && - (fscrypt_policy_contents_mode(&(ci->ci_policy)) == FSCRYPT_MODE_PRIVATE); -} -EXPORT_SYMBOL(fscrypt_using_hardware_encryption); - -size_t fscrypt_get_ice_encryption_key_size(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (inode) - ci = inode->i_crypt_info; - if (!ci) - return 0; - - return fscrypt_get_mode_key_size(fscrypt_policy_contents_mode(&(ci->ci_policy))) / 2; -} - -size_t fscrypt_get_ice_encryption_salt_size(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (inode) - ci = inode->i_crypt_info; - if (!ci) - return 0; - - return fscrypt_get_mode_key_size(fscrypt_policy_contents_mode(&(ci->ci_policy))) / 2; -} - -/* - * Retrieves encryption key from the inode - */ -char *fscrypt_get_ice_encryption_key(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[0]); -} - -/* - * Retrieves encryption salt from the inode - */ -char *fscrypt_get_ice_encryption_salt(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - int size = 0; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - size = fscrypt_get_ice_encryption_key_size(inode); - if (!size) - return NULL; - - return &(ci->ci_raw_key[size]); -} - -/* - * returns true if the cipher mode in inode is AES XTS - */ -int fscrypt_is_aes_xts_cipher(const struct inode *inode) -{ - struct fscrypt_info *ci = inode->i_crypt_info; - - if (!ci) - return 0; - - return (fscrypt_policy_contents_mode(&(ci->ci_policy)) == FSCRYPT_MODE_PRIVATE); -} - -/* - * returns true if encryption info in both inodes is equal - */ -bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2) -{ - char *key1 = NULL; - char *key2 = NULL; - char *salt1 = NULL; - char *salt2 = NULL; - - if (!inode1 || !inode2) - return false; - - if (inode1 == inode2) - return true; - - /* both do not belong to ice, so we don't care, they are equal - *for us - */ - if (!fscrypt_should_be_processed_by_ice(inode1) && - !fscrypt_should_be_processed_by_ice(inode2)) - return true; - - /* one belongs to ice, the other does not -> not equal */ - if (fscrypt_should_be_processed_by_ice(inode1) ^ - fscrypt_should_be_processed_by_ice(inode2)) - return false; - - key1 = fscrypt_get_ice_encryption_key(inode1); - key2 = fscrypt_get_ice_encryption_key(inode2); - salt1 = fscrypt_get_ice_encryption_salt(inode1); - salt2 = fscrypt_get_ice_encryption_salt(inode2); - - /* key and salt should not be null by this point */ - if (!key1 || !key2 || !salt1 || !salt2 || - (fscrypt_get_ice_encryption_key_size(inode1) != - fscrypt_get_ice_encryption_key_size(inode2)) || - (fscrypt_get_ice_encryption_salt_size(inode1) != - fscrypt_get_ice_encryption_salt_size(inode2))) - return false; - - if ((memcmp(key1, key2, - fscrypt_get_ice_encryption_key_size(inode1)) == 0) && - (memcmp(salt1, salt2, - fscrypt_get_ice_encryption_salt_size(inode1)) == 0)) - return true; - - return false; -} - -void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun) -{ - if (fscrypt_should_be_processed_by_ice(inode)) - bio->bi_iter.bi_dun = dun; -} -EXPORT_SYMBOL(fscrypt_set_ice_dun); - -void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip) -{ -#ifdef CONFIG_DM_DEFAULT_KEY - bio->bi_crypt_skip = bi_crypt_skip; -#endif -} -EXPORT_SYMBOL(fscrypt_set_ice_skip); - -/* - * This function will be used for filesystem when deciding to merge bios. - * Basic assumption is, if inline_encryption is set, single bio has to - * guarantee consecutive LBAs as well as ino|pg->index. - */ -bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted, - int bi_crypt_skip) -{ - if (!bio) - return true; - -#ifdef CONFIG_DM_DEFAULT_KEY - if (bi_crypt_skip != bio->bi_crypt_skip) - return false; -#endif - /* if both of them are not encrypted, no further check is needed */ - if (!bio_dun(bio) && !bio_encrypted) - return true; - - /* ICE allows only consecutive iv_key stream. */ - return bio_end_dun(bio) == dun; -} -EXPORT_SYMBOL(fscrypt_mergeable_bio); diff --git a/fs/crypto/fscrypt_ice.h b/fs/crypto/fscrypt_ice.h deleted file mode 100644 index d448b4289317654e3186c73196770dbfa7aa23b7..0000000000000000000000000000000000000000 --- a/fs/crypto/fscrypt_ice.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _FSCRYPT_ICE_H -#define _FSCRYPT_ICE_H - -#include -#include "fscrypt_private.h" - -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) -static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) -{ - if (!inode->i_sb->s_cop) - return 0; - if (!IS_ENCRYPTED((struct inode *)inode)) - return 0; - - return fscrypt_using_hardware_encryption(inode); -} - -static inline int fscrypt_is_ice_capable(const struct super_block *sb) -{ - return blk_queue_inlinecrypt(bdev_get_queue(sb->s_bdev)); -} - -int fscrypt_is_aes_xts_cipher(const struct inode *inode); - -char *fscrypt_get_ice_encryption_key(const struct inode *inode); -char *fscrypt_get_ice_encryption_salt(const struct inode *inode); - -bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2); - -size_t fscrypt_get_ice_encryption_key_size(const struct inode *inode); - -size_t fscrypt_get_ice_encryption_salt_size(const struct inode *inode); - -#else -static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) -{ - return 0; -} - -static inline int fscrypt_is_ice_capable(const struct super_block *sb) -{ - return 0; -} - -static inline char *fscrypt_get_ice_encryption_key(const struct inode *inode) -{ - return NULL; -} - -static inline char *fscrypt_get_ice_encryption_salt(const struct inode *inode) -{ - return NULL; -} - -static inline size_t fscrypt_get_ice_encryption_key_size( - const struct inode *inode) -{ - return 0; -} - -static inline size_t fscrypt_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return 0; -} - -static inline int fscrypt_is_xts_cipher(const struct inode *inode) -{ - return 0; -} - -static inline bool fscrypt_is_ice_encryption_info_equal( - const struct inode *inode1, - const struct inode *inode2) -{ - return 0; -} - -static inline int fscrypt_is_aes_xts_cipher(const struct inode *inode) -{ - return 0; -} - -#endif - -#endif /* _FSCRYPT_ICE_H */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index d6134d07ccdb47793357e77b11f7319f917d3d5a..67bcdfa1609510b3be4f177d9850515ce2e0d9b3 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -12,14 +12,16 @@ #define _FSCRYPT_PRIVATE_H #include +#include #include -#include +#include #define CONST_STRLEN(str) (sizeof(str) - 1) #define FS_KEY_DERIVATION_NONCE_SIZE 16 #define FSCRYPT_MIN_KEY_SIZE 16 +#define FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE 128 #define FSCRYPT_CONTEXT_V1 1 #define FSCRYPT_CONTEXT_V2 2 @@ -76,6 +78,26 @@ static inline int fscrypt_context_size(const union fscrypt_context *ctx) return 0; } +/* Check whether an fscrypt_context has a recognized version number and size */ +static inline bool fscrypt_context_is_valid(const union fscrypt_context *ctx, + int ctx_size) +{ + return ctx_size >= 1 && ctx_size == fscrypt_context_size(ctx); +} + +/* Retrieve the context's nonce, assuming the context was already validated */ +static inline const u8 *fscrypt_context_nonce(const union fscrypt_context *ctx) +{ + switch (ctx->version) { + case FSCRYPT_CONTEXT_V1: + return ctx->v1.nonce; + case FSCRYPT_CONTEXT_V2: + return ctx->v2.nonce; + } + WARN_ON(1); + return NULL; +} + #undef fscrypt_policy union fscrypt_policy { u8 version; @@ -137,12 +159,6 @@ fscrypt_policy_flags(const union fscrypt_policy *policy) BUG(); } -static inline bool -fscrypt_is_direct_key_policy(const union fscrypt_policy *policy) -{ - return fscrypt_policy_flags(policy) & FSCRYPT_POLICY_FLAG_DIRECT_KEY; -} - /** * For encrypted symlinks, the ciphertext length is stored at the beginning * of the string in little-endian format. @@ -152,6 +168,20 @@ struct fscrypt_symlink_data { char encrypted_path[1]; } __packed; +/** + * struct fscrypt_prepared_key - a key prepared for actual encryption/decryption + * @tfm: crypto API transform object + * @blk_key: key for blk-crypto + * + * Normally only one of the fields will be non-NULL. + */ +struct fscrypt_prepared_key { + struct crypto_skcipher *tfm; +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT + struct fscrypt_blk_crypto_key *blk_key; +#endif +}; + /* * fscrypt_info - the "encryption key" for an inode * @@ -160,13 +190,20 @@ struct fscrypt_symlink_data { * inode is evicted. */ struct fscrypt_info { - - /* The actual crypto transform used for encryption and decryption */ - struct crypto_skcipher *ci_ctfm; + /* The key in a form prepared for actual encryption/decryption */ + struct fscrypt_prepared_key ci_key; /* True if the key should be freed when this fscrypt_info is freed */ bool ci_owns_key; +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT + /* + * True if this inode will use inline encryption (blk-crypto) instead of + * the traditional filesystem-layer encryption. + */ + bool ci_inlinecrypt; +#endif + /* * Encryption mode used for this inode. It corresponds to either the * contents or filenames encryption mode, depending on the inode type. @@ -191,16 +228,26 @@ struct fscrypt_info { /* * If non-NULL, then encryption is done using the master key directly - * and ci_ctfm will equal ci_direct_key->dk_ctfm. + * and ci_key will equal ci_direct_key->dk_key. */ struct fscrypt_direct_key *ci_direct_key; + /* + * This inode's hash key for filenames. This is a 128-bit SipHash-2-4 + * key. This is only set for directories that use a keyed dirhash over + * the plaintext filenames -- currently just casefolded directories. + */ + siphash_key_t ci_dirhash_key; + bool ci_dirhash_key_initialized; + /* The encryption policy used by this inode */ union fscrypt_policy ci_policy; /* This inode's nonce, copied from the fscrypt_context */ u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE]; - u8 ci_raw_key[FSCRYPT_MAX_KEY_SIZE]; + + /* Hashed inode number. Only set for IV_INO_LBLK_32 */ + u32 ci_hashed_ino; }; typedef enum { @@ -208,28 +255,6 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; -static inline bool fscrypt_valid_enc_modes(u32 contents_mode, - u32 filenames_mode) -{ - if (contents_mode == FSCRYPT_MODE_AES_128_CBC && - filenames_mode == FSCRYPT_MODE_AES_128_CTS) - return true; - - if (contents_mode == FSCRYPT_MODE_AES_256_XTS && - filenames_mode == FSCRYPT_MODE_AES_256_CTS) - return true; - - if (contents_mode == FSCRYPT_MODE_PRIVATE && - filenames_mode == FSCRYPT_MODE_AES_256_CTS) - return true; - - if (contents_mode == FSCRYPT_MODE_ADIANTUM && - filenames_mode == FSCRYPT_MODE_ADIANTUM) - return true; - - return false; -} - /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); @@ -239,7 +264,6 @@ extern int fscrypt_crypt_block(const struct inode *inode, unsigned int len, unsigned int offs, gfp_t gfp_flags); extern struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags); -extern const struct dentry_operations fscrypt_d_ops; extern void __printf(3, 4) __cold fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...); @@ -260,14 +284,16 @@ union fscrypt_iv { u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; }; u8 raw[FSCRYPT_MAX_IV_SIZE]; + __le64 dun[FSCRYPT_MAX_IV_SIZE / sizeof(__le64)]; }; void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci); /* fname.c */ -extern int fname_encrypt(struct inode *inode, const struct qstr *iname, - u8 *out, unsigned int olen); +extern int fscrypt_fname_encrypt(const struct inode *inode, + const struct qstr *iname, + u8 *out, unsigned int olen); extern bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret); @@ -289,16 +315,112 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, * output doesn't reveal another. */ #define HKDF_CONTEXT_KEY_IDENTIFIER 1 -#define HKDF_CONTEXT_PER_FILE_KEY 2 +#define HKDF_CONTEXT_PER_FILE_ENC_KEY 2 #define HKDF_CONTEXT_DIRECT_KEY 3 #define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4 +#define HKDF_CONTEXT_DIRHASH_KEY 5 +#define HKDF_CONTEXT_IV_INO_LBLK_32_KEY 6 +#define HKDF_CONTEXT_INODE_HASH_KEY 7 -extern int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context, +extern int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen, u8 *okm, unsigned int okmlen); extern void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf); +/* inline_crypt.c */ +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT +extern int fscrypt_select_encryption_impl(struct fscrypt_info *ci, + bool is_hw_wrapped_key); + +static inline bool +fscrypt_using_inline_encryption(const struct fscrypt_info *ci) +{ + return ci->ci_inlinecrypt; +} + +extern int fscrypt_prepare_inline_crypt_key( + struct fscrypt_prepared_key *prep_key, + const u8 *raw_key, + unsigned int raw_key_size, + bool is_hw_wrapped, + const struct fscrypt_info *ci); + +extern void fscrypt_destroy_inline_crypt_key( + struct fscrypt_prepared_key *prep_key); + +extern int fscrypt_derive_raw_secret(struct super_block *sb, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *raw_secret, + unsigned int raw_secret_size); + +/* + * Check whether the crypto transform or blk-crypto key has been allocated in + * @prep_key, depending on which encryption implementation the file will use. + */ +static inline bool +fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + /* + * The READ_ONCE() here pairs with the smp_store_release() in + * fscrypt_prepare_key(). (This only matters for the per-mode keys, + * which are shared by multiple inodes.) + */ + if (fscrypt_using_inline_encryption(ci)) + return READ_ONCE(prep_key->blk_key) != NULL; + return READ_ONCE(prep_key->tfm) != NULL; +} + +#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ + +static inline int fscrypt_select_encryption_impl(struct fscrypt_info *ci, + bool is_hw_wrapped_key) +{ + return 0; +} + +static inline bool fscrypt_using_inline_encryption( + const struct fscrypt_info *ci) +{ + return false; +} + +static inline int +fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const u8 *raw_key, unsigned int raw_key_size, + bool is_hw_wrapped, + const struct fscrypt_info *ci) +{ + WARN_ON(1); + return -EOPNOTSUPP; +} + +static inline void +fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key) +{ +} + +static inline int fscrypt_derive_raw_secret(struct super_block *sb, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *raw_secret, + unsigned int raw_secret_size) +{ + fscrypt_warn(NULL, + "kernel built without support for hardware-wrapped keys"); + return -EOPNOTSUPP; +} + +static inline bool +fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + return READ_ONCE(prep_key->tfm) != NULL; +} +#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ + /* keyring.c */ /* @@ -315,8 +437,15 @@ struct fscrypt_master_key_secret { /* Size of the raw key in bytes. Set even if ->raw isn't set. */ u32 size; - /* For v1 policy keys: the raw key. Wiped for v2 policy keys. */ - u8 raw[FSCRYPT_MAX_KEY_SIZE]; + /* True if the key in ->raw is a hardware-wrapped key. */ + bool is_hw_wrapped; + + /* + * For v1 policy keys: the raw key. Wiped for v2 policy keys, unless + * ->is_hw_wrapped is true, in which case this contains the wrapped key + * rather than the key with which 'hkdf' was keyed. + */ + u8 raw[FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE]; } __randomize_layout; @@ -388,14 +517,17 @@ struct fscrypt_master_key { struct list_head mk_decrypted_inodes; spinlock_t mk_decrypted_inodes_lock; - /* Crypto API transforms for DIRECT_KEY policies, allocated on-demand */ - struct crypto_skcipher *mk_direct_tfms[__FSCRYPT_MODE_MAX + 1]; - /* - * Crypto API transforms for filesystem-layer implementation of - * IV_INO_LBLK_64 policies, allocated on-demand. + * Per-mode encryption keys for the various types of encryption policies + * that use them. Allocated and derived on-demand. */ - struct crypto_skcipher *mk_iv_ino_lblk_64_tfms[__FSCRYPT_MODE_MAX + 1]; + struct fscrypt_prepared_key mk_direct_keys[__FSCRYPT_MODE_MAX + 1]; + struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[__FSCRYPT_MODE_MAX + 1]; + struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[__FSCRYPT_MODE_MAX + 1]; + + /* Hash key for inode numbers. Initialized only when needed. */ + siphash_key_t mk_ino_hash_key; + bool mk_ino_hash_key_initialized; } __randomize_layout; @@ -452,20 +584,23 @@ struct fscrypt_mode { int keysize; int ivsize; int logged_impl_name; + enum blk_crypto_mode_num blk_crypto_mode; }; -static inline bool -fscrypt_mode_supports_direct_key(const struct fscrypt_mode *mode) -{ - return mode->ivsize >= offsetofend(union fscrypt_iv, nonce); -} +extern struct fscrypt_mode fscrypt_modes[]; + +extern int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, + const u8 *raw_key, unsigned int raw_key_size, + bool is_hw_wrapped, + const struct fscrypt_info *ci); + +extern void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key); -extern struct crypto_skcipher * -fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, - const struct inode *inode); +extern int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, + const u8 *raw_key); -extern int fscrypt_set_derived_key(struct fscrypt_info *ci, - const u8 *derived_key); +extern int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, + const struct fscrypt_master_key *mk); /* keysetup_v1.c */ diff --git a/fs/crypto/hkdf.c b/fs/crypto/hkdf.c index 2c026009c6e70b5b3aac1f3921a8e7cc1ac94e73..fd7f67628561254e5dc62a7e5b2506646a6bcf0f 100644 --- a/fs/crypto/hkdf.c +++ b/fs/crypto/hkdf.c @@ -113,7 +113,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, * adds to its application-specific info strings to guarantee that it doesn't * accidentally repeat an info string when using HKDF for different purposes.) */ -int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context, +int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen, u8 *okm, unsigned int okmlen) { diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 30b1ca66124920a23a2e226e853406045f3bfba3..a6396bf721acfd86a98c8810b2e2bf85d4d71f8d 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -4,6 +4,8 @@ * Encryption hooks for higher-level filesystem operations. */ +#include + #include "fscrypt_private.h" /** @@ -115,12 +117,53 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry, spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_ENCRYPTED_NAME; spin_unlock(&dentry->d_lock); - d_set_d_op(dentry, &fscrypt_d_ops); } return err; } EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); +/** + * fscrypt_prepare_setflags() - prepare to change flags with FS_IOC_SETFLAGS + * @inode: the inode on which flags are being changed + * @oldflags: the old flags + * @flags: the new flags + * + * The caller should be holding i_rwsem for write. + * + * Return: 0 on success; -errno if the flags change isn't allowed or if + * another error occurs. + */ +int fscrypt_prepare_setflags(struct inode *inode, + unsigned int oldflags, unsigned int flags) +{ + struct fscrypt_info *ci; + struct fscrypt_master_key *mk; + int err; + + /* + * When the CASEFOLD flag is set on an encrypted directory, we must + * derive the secret key needed for the dirhash. This is only possible + * if the directory uses a v2 encryption policy. + */ + if (IS_ENCRYPTED(inode) && (flags & ~oldflags & FS_CASEFOLD_FL)) { + err = fscrypt_require_key(inode); + if (err) + return err; + ci = inode->i_crypt_info; + if (ci->ci_policy.version != FSCRYPT_POLICY_V2) + return -EINVAL; + mk = ci->ci_master_key->payload.data[0]; + down_read(&mk->mk_secret_sem); + if (is_master_key_secret_present(&mk->mk_secret)) + err = fscrypt_derive_dirhash_key(ci, mk); + else + err = -ENOKEY; + up_read(&mk->mk_secret_sem); + return err; + } + return 0; +} + int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, unsigned int max_len, struct fscrypt_str *disk_link) @@ -187,7 +230,8 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, ciphertext_len = disk_link->len - sizeof(*sd); sd->len = cpu_to_le16(ciphertext_len); - err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len); + err = fscrypt_fname_encrypt(inode, &iname, sd->encrypted_path, + ciphertext_len); if (err) goto err_free_sd; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c new file mode 100644 index 0000000000000000000000000000000000000000..69c281a331e506cb2ebc7e5009f08948b96cb0ca --- /dev/null +++ b/fs/crypto/inline_crypt.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Inline encryption support for fscrypt + * + * Copyright 2019 Google LLC + */ + +/* + * With "inline encryption", the block layer handles the decryption/encryption + * as part of the bio, instead of the filesystem doing the crypto itself via + * crypto API. See Documentation/block/inline-encryption.rst. fscrypt still + * provides the key and IV to use. + */ + +#include +#include +#include +#include +#include +#include + +#include "fscrypt_private.h" + +struct fscrypt_blk_crypto_key { + struct blk_crypto_key base; + int num_devs; + struct request_queue *devs[]; +}; + +static int fscrypt_get_num_devices(struct super_block *sb) +{ + if (sb->s_cop->get_num_devices) + return sb->s_cop->get_num_devices(sb); + return 1; +} + +static void fscrypt_get_devices(struct super_block *sb, int num_devs, + struct request_queue **devs) +{ + if (num_devs == 1) + devs[0] = bdev_get_queue(sb->s_bdev); + else + sb->s_cop->get_devices(sb, devs); +} + +static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci) +{ + struct super_block *sb = ci->ci_inode->i_sb; + unsigned int flags = fscrypt_policy_flags(&ci->ci_policy); + int ino_bits = 64, lblk_bits = 64; + + if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) + return offsetofend(union fscrypt_iv, nonce); + + if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) + return sizeof(__le64); + + if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) + return sizeof(__le32); + + /* Default case: IVs are just the file logical block number */ + if (sb->s_cop->get_ino_and_lblk_bits) + sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits); + return DIV_ROUND_UP(lblk_bits, 8); +} + +/* Enable inline encryption for this file if supported. */ +int fscrypt_select_encryption_impl(struct fscrypt_info *ci, + bool is_hw_wrapped_key) +{ + const struct inode *inode = ci->ci_inode; + struct super_block *sb = inode->i_sb; + enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode; + unsigned int dun_bytes; + struct request_queue **devs; + int num_devs; + int i; + + /* The file must need contents encryption, not filenames encryption */ + if (!S_ISREG(inode->i_mode)) + return 0; + + /* blk-crypto must implement the needed encryption algorithm */ + if (crypto_mode == BLK_ENCRYPTION_MODE_INVALID) + return 0; + + /* The filesystem must be mounted with -o inlinecrypt */ + if (!sb->s_cop->inline_crypt_enabled || + !sb->s_cop->inline_crypt_enabled(sb)) + return 0; + + /* + * The needed encryption settings must be supported either by + * blk-crypto-fallback, or by hardware on all the filesystem's devices. + */ + + if (IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) && + !is_hw_wrapped_key) { + ci->ci_inlinecrypt = true; + return 0; + } + + num_devs = fscrypt_get_num_devices(sb); + devs = kmalloc_array(num_devs, sizeof(*devs), GFP_NOFS); + if (!devs) + return -ENOMEM; + + fscrypt_get_devices(sb, num_devs, devs); + + dun_bytes = fscrypt_get_dun_bytes(ci); + + for (i = 0; i < num_devs; i++) { + if (!keyslot_manager_crypto_mode_supported(devs[i]->ksm, + crypto_mode, + dun_bytes, + sb->s_blocksize, + is_hw_wrapped_key)) + goto out_free_devs; + } + + ci->ci_inlinecrypt = true; +out_free_devs: + kfree(devs); + return 0; +} + +int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const u8 *raw_key, + unsigned int raw_key_size, + bool is_hw_wrapped, + const struct fscrypt_info *ci) +{ + const struct inode *inode = ci->ci_inode; + struct super_block *sb = inode->i_sb; + enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode; + unsigned int dun_bytes; + int num_devs; + int queue_refs = 0; + struct fscrypt_blk_crypto_key *blk_key; + int err; + int i; + + num_devs = fscrypt_get_num_devices(sb); + if (WARN_ON(num_devs < 1)) + return -EINVAL; + + blk_key = kzalloc(struct_size(blk_key, devs, num_devs), GFP_NOFS); + if (!blk_key) + return -ENOMEM; + + blk_key->num_devs = num_devs; + fscrypt_get_devices(sb, num_devs, blk_key->devs); + + dun_bytes = fscrypt_get_dun_bytes(ci); + + BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE > + BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE); + + err = blk_crypto_init_key(&blk_key->base, raw_key, raw_key_size, + is_hw_wrapped, crypto_mode, dun_bytes, + sb->s_blocksize); + if (err) { + fscrypt_err(inode, "error %d initializing blk-crypto key", err); + goto fail; + } + + /* + * We have to start using blk-crypto on all the filesystem's devices. + * We also have to save all the request_queue's for later so that the + * key can be evicted from them. This is needed because some keys + * aren't destroyed until after the filesystem was already unmounted + * (namely, the per-mode keys in struct fscrypt_master_key). + */ + for (i = 0; i < num_devs; i++) { + if (!blk_get_queue(blk_key->devs[i])) { + fscrypt_err(inode, "couldn't get request_queue"); + err = -EAGAIN; + goto fail; + } + queue_refs++; + + err = blk_crypto_start_using_mode(crypto_mode, dun_bytes, + sb->s_blocksize, + is_hw_wrapped, + blk_key->devs[i]); + if (err) { + fscrypt_err(inode, + "error %d starting to use blk-crypto", err); + goto fail; + } + } + /* + * Pairs with READ_ONCE() in fscrypt_is_key_prepared(). (Only matters + * for the per-mode keys, which are shared by multiple inodes.) + */ + smp_store_release(&prep_key->blk_key, blk_key); + return 0; + +fail: + for (i = 0; i < queue_refs; i++) + blk_put_queue(blk_key->devs[i]); + kzfree(blk_key); + return err; +} + +void fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key) +{ + struct fscrypt_blk_crypto_key *blk_key = prep_key->blk_key; + int i; + + if (blk_key) { + for (i = 0; i < blk_key->num_devs; i++) { + blk_crypto_evict_key(blk_key->devs[i], &blk_key->base); + blk_put_queue(blk_key->devs[i]); + } + kzfree(blk_key); + } +} + +int fscrypt_derive_raw_secret(struct super_block *sb, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *raw_secret, unsigned int raw_secret_size) +{ + struct request_queue *q; + + q = sb->s_bdev->bd_queue; + if (!q->ksm) + return -EOPNOTSUPP; + + return keyslot_manager_derive_raw_secret(q->ksm, + wrapped_key, wrapped_key_size, + raw_secret, raw_secret_size); +} + +/** + * fscrypt_inode_uses_inline_crypto - test whether an inode uses inline + * encryption + * @inode: an inode + * + * Return: true if the inode requires file contents encryption and if the + * encryption should be done in the block layer via blk-crypto rather + * than in the filesystem layer. + */ +bool fscrypt_inode_uses_inline_crypto(const struct inode *inode) +{ + return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) && + inode->i_crypt_info->ci_inlinecrypt; +} +EXPORT_SYMBOL_GPL(fscrypt_inode_uses_inline_crypto); + +/** + * fscrypt_inode_uses_fs_layer_crypto - test whether an inode uses fs-layer + * encryption + * @inode: an inode + * + * Return: true if the inode requires file contents encryption and if the + * encryption should be done in the filesystem layer rather than in the + * block layer via blk-crypto. + */ +bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode) +{ + return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) && + !inode->i_crypt_info->ci_inlinecrypt; +} +EXPORT_SYMBOL_GPL(fscrypt_inode_uses_fs_layer_crypto); + +static void fscrypt_generate_dun(const struct fscrypt_info *ci, u64 lblk_num, + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE]) +{ + union fscrypt_iv iv; + int i; + + fscrypt_generate_iv(&iv, lblk_num, ci); + + BUILD_BUG_ON(FSCRYPT_MAX_IV_SIZE > BLK_CRYPTO_MAX_IV_SIZE); + memset(dun, 0, BLK_CRYPTO_MAX_IV_SIZE); + for (i = 0; i < ci->ci_mode->ivsize/sizeof(dun[0]); i++) + dun[i] = le64_to_cpu(iv.dun[i]); +} + +/** + * fscrypt_set_bio_crypt_ctx - prepare a file contents bio for inline encryption + * @bio: a bio which will eventually be submitted to the file + * @inode: the file's inode + * @first_lblk: the first file logical block number in the I/O + * @gfp_mask: memory allocation flags - these must be a waiting mask so that + * bio_crypt_set_ctx can't fail. + * + * If the contents of the file should be encrypted (or decrypted) with inline + * encryption, then assign the appropriate encryption context to the bio. + * + * Normally the bio should be newly allocated (i.e. no pages added yet), as + * otherwise fscrypt_mergeable_bio() won't work as intended. + * + * The encryption context will be freed automatically when the bio is freed. + * + * This function also handles setting bi_skip_dm_default_key when needed. + */ +void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, + u64 first_lblk, gfp_t gfp_mask) +{ + const struct fscrypt_info *ci = inode->i_crypt_info; + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + + if (fscrypt_inode_should_skip_dm_default_key(inode)) + bio_set_skip_dm_default_key(bio); + + if (!fscrypt_inode_uses_inline_crypto(inode)) + return; + + fscrypt_generate_dun(ci, first_lblk, dun); + bio_crypt_set_ctx(bio, &ci->ci_key.blk_key->base, dun, gfp_mask); +} +EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); + +/* Extract the inode and logical block number from a buffer_head. */ +static bool bh_get_inode_and_lblk_num(const struct buffer_head *bh, + const struct inode **inode_ret, + u64 *lblk_num_ret) +{ + struct page *page = bh->b_page; + const struct address_space *mapping; + const struct inode *inode; + + /* + * The ext4 journal (jbd2) can submit a buffer_head it directly created + * for a non-pagecache page. fscrypt doesn't care about these. + */ + mapping = page_mapping(page); + if (!mapping) + return false; + inode = mapping->host; + + *inode_ret = inode; + *lblk_num_ret = ((u64)page->index << (PAGE_SHIFT - inode->i_blkbits)) + + (bh_offset(bh) >> inode->i_blkbits); + return true; +} + +/** + * fscrypt_set_bio_crypt_ctx_bh - prepare a file contents bio for inline + * encryption + * @bio: a bio which will eventually be submitted to the file + * @first_bh: the first buffer_head for which I/O will be submitted + * @gfp_mask: memory allocation flags + * + * Same as fscrypt_set_bio_crypt_ctx(), except this takes a buffer_head instead + * of an inode and block number directly. + */ +void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio, + const struct buffer_head *first_bh, + gfp_t gfp_mask) +{ + const struct inode *inode; + u64 first_lblk; + + if (bh_get_inode_and_lblk_num(first_bh, &inode, &first_lblk)) + fscrypt_set_bio_crypt_ctx(bio, inode, first_lblk, gfp_mask); +} +EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh); + +/** + * fscrypt_mergeable_bio - test whether data can be added to a bio + * @bio: the bio being built up + * @inode: the inode for the next part of the I/O + * @next_lblk: the next file logical block number in the I/O + * + * When building a bio which may contain data which should undergo inline + * encryption (or decryption) via fscrypt, filesystems should call this function + * to ensure that the resulting bio contains only logically contiguous data. + * This will return false if the next part of the I/O cannot be merged with the + * bio because either the encryption key would be different or the encryption + * data unit numbers would be discontiguous. + * + * fscrypt_set_bio_crypt_ctx() must have already been called on the bio. + * + * This function also returns false if the next part of the I/O would need to + * have a different value for the bi_skip_dm_default_key flag. + * + * Return: true iff the I/O is mergeable + */ +bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, + u64 next_lblk) +{ + const struct bio_crypt_ctx *bc = bio->bi_crypt_context; + u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + + if (!!bc != fscrypt_inode_uses_inline_crypto(inode)) + return false; + if (bio_should_skip_dm_default_key(bio) != + fscrypt_inode_should_skip_dm_default_key(inode)) + return false; + if (!bc) + return true; + + /* + * Comparing the key pointers is good enough, as all I/O for each key + * uses the same pointer. I.e., there's currently no need to support + * merging requests where the keys are the same but the pointers differ. + */ + if (bc->bc_key != &inode->i_crypt_info->ci_key.blk_key->base) + return false; + + fscrypt_generate_dun(inode->i_crypt_info, next_lblk, next_dun); + return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun); +} +EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio); + +/** + * fscrypt_mergeable_bio_bh - test whether data can be added to a bio + * @bio: the bio being built up + * @next_bh: the next buffer_head for which I/O will be submitted + * + * Same as fscrypt_mergeable_bio(), except this takes a buffer_head instead of + * an inode and block number directly. + * + * Return: true iff the I/O is mergeable + */ +bool fscrypt_mergeable_bio_bh(struct bio *bio, + const struct buffer_head *next_bh) +{ + const struct inode *inode; + u64 next_lblk; + + if (!bh_get_inode_and_lblk_num(next_bh, &inode, &next_lblk)) + return !bio->bi_crypt_context && + !bio_should_skip_dm_default_key(bio); + + return fscrypt_mergeable_bio(bio, inode, next_lblk); +} +EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); + +/** + * fscrypt_dio_supported() - check whether a direct I/O request is unsupported + * due to encryption constraints + * @iocb: the file and position the I/O is targeting + * @iter: the I/O data segment(s) + * + * Return: true if direct I/O is supported + */ +bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) +{ + const struct inode *inode = file_inode(iocb->ki_filp); + const struct fscrypt_info *ci = inode->i_crypt_info; + const unsigned int blocksize = i_blocksize(inode); + + /* If the file is unencrypted, no veto from us. */ + if (!fscrypt_needs_contents_encryption(inode)) + return true; + + /* We only support direct I/O with inline crypto, not fs-layer crypto */ + if (!fscrypt_inode_uses_inline_crypto(inode)) + return false; + + /* + * Since the granularity of encryption is filesystem blocks, the I/O + * must be block aligned -- not just disk sector aligned. + */ + if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize)) + return false; + + /* + * With IV_INO_LBLK_32 and sub-page blocks, the DUN can wrap around in + * the middle of a page. This isn't handled by the direct I/O code yet. + */ + if (blocksize != PAGE_SIZE && + (fscrypt_policy_flags(&ci->ci_policy) & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(fscrypt_dio_supported); + +/** + * fscrypt_limit_dio_pages() - limit I/O pages to avoid discontiguous DUNs + * @inode: the file on which I/O is being done + * @pos: the file position (in bytes) at which the I/O is being done + * @nr_pages: the number of pages we want to submit starting at @pos + * + * For direct I/O: limit the number of pages that will be submitted in the bio + * targeting @pos, in order to avoid crossing a data unit number (DUN) + * discontinuity. This is only needed for certain IV generation methods. + * + * This assumes block_size == PAGE_SIZE; see fscrypt_dio_supported(). + * + * Return: the actual number of pages that can be submitted + */ +int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, int nr_pages) +{ + const struct fscrypt_info *ci = inode->i_crypt_info; + u32 dun; + + if (!fscrypt_inode_uses_inline_crypto(inode)) + return nr_pages; + + if (nr_pages <= 1) + return nr_pages; + + if (!(fscrypt_policy_flags(&ci->ci_policy) & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) + return nr_pages; + + if (WARN_ON_ONCE(i_blocksize(inode) != PAGE_SIZE)) + return 1; + + /* With IV_INO_LBLK_32, the DUN can wrap around from U32_MAX to 0. */ + + dun = ci->ci_hashed_ino + (pos >> inode->i_blkbits); + + return min_t(u64, nr_pages, (u64)U32_MAX + 1 - dun); +} diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 687f7659076176a5938b1304dfd6cca02e3437e3..fc9ea71b50f7f15698617586be63461c3ab0d2bf 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -44,8 +44,9 @@ static void free_master_key(struct fscrypt_master_key *mk) wipe_master_key_secret(&mk->mk_secret); for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) { - crypto_free_skcipher(mk->mk_direct_tfms[i]); - crypto_free_skcipher(mk->mk_iv_ino_lblk_64_tfms[i]); + fscrypt_destroy_prepared_key(&mk->mk_direct_keys[i]); + fscrypt_destroy_prepared_key(&mk->mk_iv_ino_lblk_64_keys[i]); + fscrypt_destroy_prepared_key(&mk->mk_iv_ino_lblk_32_keys[i]); } key_put(mk->mk_users); @@ -469,8 +470,10 @@ static int fscrypt_provisioning_key_preparse(struct key_preparsed_payload *prep) { const struct fscrypt_provisioning_key_payload *payload = prep->data; + BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE < FSCRYPT_MAX_KEY_SIZE); + if (prep->datalen < sizeof(*payload) + FSCRYPT_MIN_KEY_SIZE || - prep->datalen > sizeof(*payload) + FSCRYPT_MAX_KEY_SIZE) + prep->datalen > sizeof(*payload) + FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE) return -EINVAL; if (payload->type != FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR && @@ -568,6 +571,9 @@ static int get_keyring_key(u32 key_id, u32 type, return err; } +/* Size of software "secret" derived from hardware-wrapped key */ +#define RAW_SECRET_SIZE 32 + /* * Add a master encryption key to the filesystem, causing all files which were * encrypted with it to appear "unlocked" (decrypted) when accessed. @@ -598,6 +604,9 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg) struct fscrypt_add_key_arg __user *uarg = _uarg; struct fscrypt_add_key_arg arg; struct fscrypt_master_key_secret secret; + u8 _kdf_key[RAW_SECRET_SIZE]; + u8 *kdf_key; + unsigned int kdf_key_size; int err; if (copy_from_user(&arg, uarg, sizeof(arg))) @@ -610,23 +619,26 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg) return -EINVAL; memset(&secret, 0, sizeof(secret)); - if (arg.key_id) { if (arg.raw_size != 0) return -EINVAL; err = get_keyring_key(arg.key_id, arg.key_spec.type, &secret); if (err) goto out_wipe_secret; + err = -EINVAL; + if (!(arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) && + secret.size > FSCRYPT_MAX_KEY_SIZE) + goto out_wipe_secret; } else { if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE || - arg.raw_size > FSCRYPT_MAX_KEY_SIZE) + arg.raw_size > + ((arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) ? + FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE : FSCRYPT_MAX_KEY_SIZE)) return -EINVAL; - secret.size = arg.raw_size; err = -EFAULT; - if (copy_from_user(secret.raw, uarg->raw, secret.size)) { + if (copy_from_user(secret.raw, uarg->raw, secret.size)) goto out_wipe_secret; - } } switch (arg.key_spec.type) { @@ -639,17 +651,36 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg) err = -EACCES; if (!capable(CAP_SYS_ADMIN)) goto out_wipe_secret; + + err = -EINVAL; + if (arg.__flags & ~__FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) + goto out_wipe_secret; break; case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER: - err = fscrypt_init_hkdf(&secret.hkdf, secret.raw, secret.size); - if (err) + err = -EINVAL; + if (arg.__flags & ~__FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) goto out_wipe_secret; - + if (arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) { + kdf_key = _kdf_key; + kdf_key_size = RAW_SECRET_SIZE; + err = fscrypt_derive_raw_secret(sb, secret.raw, + secret.size, + kdf_key, kdf_key_size); + if (err) + goto out_wipe_secret; + secret.is_hw_wrapped = true; + } else { + kdf_key = secret.raw; + kdf_key_size = secret.size; + } + err = fscrypt_init_hkdf(&secret.hkdf, kdf_key, kdf_key_size); /* - * Now that the HKDF context is initialized, the raw key is no - * longer needed. + * Now that the HKDF context is initialized, the raw HKDF + * key is no longer needed. */ - memzero_explicit(secret.raw, secret.size); + memzero_explicit(kdf_key, kdf_key_size); + if (err) + goto out_wipe_secret; /* Calculate the key identifier and return it to userspace. */ err = fscrypt_hkdf_expand(&secret.hkdf, @@ -779,9 +810,6 @@ static int check_for_busy_inodes(struct super_block *sb, struct list_head *pos; size_t busy_count = 0; unsigned long ino; - struct dentry *dentry; - char _path[256]; - char *path = NULL; spin_lock(&mk->mk_decrypted_inodes_lock); @@ -800,22 +828,14 @@ static int check_for_busy_inodes(struct super_block *sb, struct fscrypt_info, ci_master_key_link)->ci_inode; ino = inode->i_ino; - dentry = d_find_alias(inode); } spin_unlock(&mk->mk_decrypted_inodes_lock); - if (dentry) { - path = dentry_path(dentry, _path, sizeof(_path)); - dput(dentry); - } - if (IS_ERR_OR_NULL(path)) - path = "(unknown)"; - fscrypt_warn(NULL, - "%s: %zu inode(s) still busy after removing key with %s %*phN, including ino %lu (%s)", + "%s: %zu inode(s) still busy after removing key with %s %*phN, including ino %lu", sb->s_id, busy_count, master_key_spec_type(&mk->mk_spec), master_key_spec_len(&mk->mk_spec), (u8 *)&mk->mk_spec.u, - ino, path); + ino); return -EBUSY; } diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 16413b728b2be8b4c2add99e186635f227e8fefa..4cac429e7adb509b2a05a79c28ce6193a808bdc1 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -12,14 +12,14 @@ #include #include "fscrypt_private.h" -#include "fscrypt_ice.h" -static struct fscrypt_mode available_modes[] = { +struct fscrypt_mode fscrypt_modes[] = { [FSCRYPT_MODE_AES_256_XTS] = { .friendly_name = "AES-256-XTS", .cipher_str = "xts(aes)", .keysize = 64, .ivsize = 16, + .blk_crypto_mode = BLK_ENCRYPTION_MODE_AES_256_XTS, }, [FSCRYPT_MODE_AES_256_CTS] = { .friendly_name = "AES-256-CTS-CBC", @@ -32,6 +32,7 @@ static struct fscrypt_mode available_modes[] = { .cipher_str = "essiv(cbc(aes),sha256)", .keysize = 16, .ivsize = 16, + .blk_crypto_mode = BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV, }, [FSCRYPT_MODE_AES_128_CTS] = { .friendly_name = "AES-128-CTS-CBC", @@ -44,29 +45,28 @@ static struct fscrypt_mode available_modes[] = { .cipher_str = "adiantum(xchacha12,aes)", .keysize = 32, .ivsize = 32, + .blk_crypto_mode = BLK_ENCRYPTION_MODE_ADIANTUM, }, [FSCRYPT_MODE_PRIVATE] = { - .friendly_name = "ICE", - .cipher_str = "bugon", + .friendly_name = "ice", + .cipher_str = "xts(aes)", .keysize = 64, + .ivsize = 16, + .blk_crypto_mode = BLK_ENCRYPTION_MODE_AES_256_XTS, }, }; -static int fscrypt_data_encryption_mode(struct inode *inode) -{ - return fscrypt_should_be_processed_by_ice(inode) ? - FSCRYPT_MODE_PRIVATE : FSCRYPT_MODE_AES_256_XTS; -} +static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex); static struct fscrypt_mode * select_encryption_mode(const union fscrypt_policy *policy, const struct inode *inode) { if (S_ISREG(inode->i_mode)) - return &available_modes[fscrypt_policy_contents_mode(policy)]; + return &fscrypt_modes[fscrypt_policy_contents_mode(policy)]; if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - return &available_modes[fscrypt_policy_fnames_mode(policy)]; + return &fscrypt_modes[fscrypt_policy_fnames_mode(policy)]; WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n", inode->i_ino, (inode->i_mode & S_IFMT)); @@ -74,9 +74,9 @@ select_encryption_mode(const union fscrypt_policy *policy, } /* Create a symmetric cipher object for the given encryption mode and key */ -struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, - const u8 *raw_key, - const struct inode *inode) +static struct crypto_skcipher * +fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, + const struct inode *inode) { struct crypto_skcipher *tfm; int err; @@ -101,8 +101,11 @@ struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, * first time a mode is used. */ pr_info("fscrypt: %s using implementation \"%s\"\n", - mode->friendly_name, - crypto_skcipher_alg(tfm)->base.cra_driver_name); + mode->friendly_name, crypto_skcipher_driver_name(tfm)); + } + if (WARN_ON(crypto_skcipher_ivsize(tfm) != mode->ivsize)) { + err = -EINVAL; + goto err_free_tfm; } crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize); @@ -116,30 +119,61 @@ struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, return ERR_PTR(err); } -/* Given the per-file key, set up the file's crypto transform object */ -int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key) +/* + * Prepare the crypto transform object or blk-crypto key in @prep_key, given the + * raw key, encryption mode, and flag indicating which encryption implementation + * (fs-layer or blk-crypto) will be used. + */ +int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, + const u8 *raw_key, unsigned int raw_key_size, + bool is_hw_wrapped, const struct fscrypt_info *ci) { struct crypto_skcipher *tfm; - tfm = fscrypt_allocate_skcipher(ci->ci_mode, derived_key, ci->ci_inode); + if (fscrypt_using_inline_encryption(ci)) + return fscrypt_prepare_inline_crypt_key(prep_key, + raw_key, raw_key_size, is_hw_wrapped, ci); + + if (WARN_ON(is_hw_wrapped || raw_key_size != ci->ci_mode->keysize)) + return -EINVAL; + + tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode); if (IS_ERR(tfm)) return PTR_ERR(tfm); + /* + * Pairs with READ_ONCE() in fscrypt_is_key_prepared(). (Only matters + * for the per-mode keys, which are shared by multiple inodes.) + */ + smp_store_release(&prep_key->tfm, tfm); + return 0; +} - ci->ci_ctfm = tfm; +/* Destroy a crypto transform object and/or blk-crypto key. */ +void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key) +{ + crypto_free_skcipher(prep_key->tfm); + fscrypt_destroy_inline_crypt_key(prep_key); +} + +/* Given a per-file encryption key, set up the file's crypto transform object */ +int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) +{ ci->ci_owns_key = true; - return 0; + return fscrypt_prepare_key(&ci->ci_key, raw_key, ci->ci_mode->keysize, + false /*is_hw_wrapped*/, ci); } -static int setup_per_mode_key(struct fscrypt_info *ci, - struct fscrypt_master_key *mk, - struct crypto_skcipher **tfms, - u8 hkdf_context, bool include_fs_uuid) +static int setup_per_mode_enc_key(struct fscrypt_info *ci, + struct fscrypt_master_key *mk, + struct fscrypt_prepared_key *keys, + u8 hkdf_context, bool include_fs_uuid) { + static DEFINE_MUTEX(mode_key_setup_mutex); const struct inode *inode = ci->ci_inode; const struct super_block *sb = inode->i_sb; struct fscrypt_mode *mode = ci->ci_mode; - u8 mode_num = mode - available_modes; - struct crypto_skcipher *tfm, *prev_tfm; + const u8 mode_num = mode - fscrypt_modes; + struct fscrypt_prepared_key *prep_key; u8 mode_key[FSCRYPT_MAX_KEY_SIZE]; u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)]; unsigned int hkdf_infolen = 0; @@ -148,87 +182,182 @@ static int setup_per_mode_key(struct fscrypt_info *ci, if (WARN_ON(mode_num > __FSCRYPT_MODE_MAX)) return -EINVAL; - /* pairs with cmpxchg() below */ - tfm = READ_ONCE(tfms[mode_num]); - if (likely(tfm != NULL)) - goto done; - - BUILD_BUG_ON(sizeof(mode_num) != 1); - BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); - BUILD_BUG_ON(sizeof(hkdf_info) != 17); - hkdf_info[hkdf_infolen++] = mode_num; - if (include_fs_uuid) { - memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid, - sizeof(sb->s_uuid)); - hkdf_infolen += sizeof(sb->s_uuid); + prep_key = &keys[mode_num]; + if (fscrypt_is_key_prepared(prep_key, ci)) { + ci->ci_key = *prep_key; + return 0; + } + + mutex_lock(&fscrypt_mode_key_setup_mutex); + + if (fscrypt_is_key_prepared(prep_key, ci)) + goto done_unlock; + + if (mk->mk_secret.is_hw_wrapped && S_ISREG(inode->i_mode)) { + int i; + + if (!fscrypt_using_inline_encryption(ci)) { + fscrypt_warn(ci->ci_inode, + "Hardware-wrapped keys require inline encryption (-o inlinecrypt)"); + err = -EINVAL; + goto out_unlock; + } + for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) { + if (fscrypt_is_key_prepared(&keys[i], ci)) { + fscrypt_warn(ci->ci_inode, + "Each hardware-wrapped key can only be used with one encryption mode"); + err = -EINVAL; + goto out_unlock; + } + } + err = fscrypt_prepare_key(prep_key, mk->mk_secret.raw, + mk->mk_secret.size, true, ci); + if (err) + goto out_unlock; + } else { + BUILD_BUG_ON(sizeof(mode_num) != 1); + BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); + BUILD_BUG_ON(sizeof(hkdf_info) != 17); + hkdf_info[hkdf_infolen++] = mode_num; + if (include_fs_uuid) { + memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid, + sizeof(sb->s_uuid)); + hkdf_infolen += sizeof(sb->s_uuid); + } + err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, + hkdf_context, hkdf_info, hkdf_infolen, + mode_key, mode->keysize); + if (err) + goto out_unlock; + err = fscrypt_prepare_key(prep_key, mode_key, mode->keysize, + false /*is_hw_wrapped*/, ci); + memzero_explicit(mode_key, mode->keysize); + if (err) + goto out_unlock; } - err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, - hkdf_context, hkdf_info, hkdf_infolen, - mode_key, mode->keysize); +done_unlock: + ci->ci_key = *prep_key; + err = 0; +out_unlock: + mutex_unlock(&fscrypt_mode_key_setup_mutex); + return err; +} + +int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, + const struct fscrypt_master_key *mk) +{ + int err; + + err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, HKDF_CONTEXT_DIRHASH_KEY, + ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE, + (u8 *)&ci->ci_dirhash_key, + sizeof(ci->ci_dirhash_key)); if (err) return err; - tfm = fscrypt_allocate_skcipher(mode, mode_key, inode); - memzero_explicit(mode_key, mode->keysize); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + ci->ci_dirhash_key_initialized = true; + return 0; +} + +static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci, + struct fscrypt_master_key *mk) +{ + int err; - /* pairs with READ_ONCE() above */ - prev_tfm = cmpxchg(&tfms[mode_num], NULL, tfm); - if (prev_tfm != NULL) { - crypto_free_skcipher(tfm); - tfm = prev_tfm; + err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys, + HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true); + if (err) + return err; + + /* pairs with smp_store_release() below */ + if (!smp_load_acquire(&mk->mk_ino_hash_key_initialized)) { + + mutex_lock(&fscrypt_mode_key_setup_mutex); + + if (mk->mk_ino_hash_key_initialized) + goto unlock; + + err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, + HKDF_CONTEXT_INODE_HASH_KEY, NULL, 0, + (u8 *)&mk->mk_ino_hash_key, + sizeof(mk->mk_ino_hash_key)); + if (err) + goto unlock; + /* pairs with smp_load_acquire() above */ + smp_store_release(&mk->mk_ino_hash_key_initialized, true); +unlock: + mutex_unlock(&fscrypt_mode_key_setup_mutex); + if (err) + return err; } -done: - ci->ci_ctfm = tfm; + + ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino, + &mk->mk_ino_hash_key); return 0; } static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, struct fscrypt_master_key *mk) { - u8 derived_key[FSCRYPT_MAX_KEY_SIZE]; int err; + if (mk->mk_secret.is_hw_wrapped && + !(ci->ci_policy.v2.flags & (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 | + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))) { + fscrypt_warn(ci->ci_inode, + "Hardware-wrapped keys are only supported with IV_INO_LBLK policies"); + return -EINVAL; + } + if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { /* - * DIRECT_KEY: instead of deriving per-file keys, the per-file - * nonce will be included in all the IVs. But unlike v1 - * policies, for v2 policies in this case we don't encrypt with - * the master key directly but rather derive a per-mode key. - * This ensures that the master key is consistently used only - * for HKDF, avoiding key reuse issues. + * DIRECT_KEY: instead of deriving per-file encryption keys, the + * per-file nonce will be included in all the IVs. But unlike + * v1 policies, for v2 policies in this case we don't encrypt + * with the master key directly but rather derive a per-mode + * encryption key. This ensures that the master key is + * consistently used only for HKDF, avoiding key reuse issues. */ - if (!fscrypt_mode_supports_direct_key(ci->ci_mode)) { - fscrypt_warn(ci->ci_inode, - "Direct key flag not allowed with %s", - ci->ci_mode->friendly_name); - return -EINVAL; - } - return setup_per_mode_key(ci, mk, mk->mk_direct_tfms, - HKDF_CONTEXT_DIRECT_KEY, false); + err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys, + HKDF_CONTEXT_DIRECT_KEY, false); } else if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { /* * IV_INO_LBLK_64: encryption keys are derived from (master_key, * mode_num, filesystem_uuid), and inode number is included in * the IVs. This format is optimized for use with inline - * encryption hardware compliant with the UFS or eMMC standards. + * encryption hardware compliant with the UFS standard. */ - return setup_per_mode_key(ci, mk, mk->mk_iv_ino_lblk_64_tfms, - HKDF_CONTEXT_IV_INO_LBLK_64_KEY, - true); + err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys, + HKDF_CONTEXT_IV_INO_LBLK_64_KEY, + true); + } else if (ci->ci_policy.v2.flags & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { + err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk); + } else { + u8 derived_key[FSCRYPT_MAX_KEY_SIZE]; + + err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, + HKDF_CONTEXT_PER_FILE_ENC_KEY, + ci->ci_nonce, + FS_KEY_DERIVATION_NONCE_SIZE, + derived_key, ci->ci_mode->keysize); + if (err) + return err; + + err = fscrypt_set_per_file_enc_key(ci, derived_key); + memzero_explicit(derived_key, ci->ci_mode->keysize); } - - err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, - HKDF_CONTEXT_PER_FILE_KEY, - ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE, - derived_key, ci->ci_mode->keysize); if (err) return err; - err = fscrypt_set_derived_key(ci, derived_key); - memzero_explicit(derived_key, ci->ci_mode->keysize); - return err; + /* Derive a secret dirhash key for directories that need it. */ + if (S_ISDIR(ci->ci_inode->i_mode) && IS_CASEFOLDED(ci->ci_inode)) { + err = fscrypt_derive_dirhash_key(ci, mk); + if (err) + return err; + } + + return 0; } /* @@ -273,6 +402,10 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, ci->ci_policy.version != FSCRYPT_POLICY_V1) return PTR_ERR(key); + err = fscrypt_select_encryption_impl(ci, false); + if (err) + return err; + /* * As a legacy fallback for v1 policies, search for the key in * the current task's subscribed keyrings too. Don't move this @@ -307,6 +440,10 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, goto out_release_key; } + err = fscrypt_select_encryption_impl(ci, mk->mk_secret.is_hw_wrapped); + if (err) + goto out_release_key; + switch (ci->ci_policy.version) { case FSCRYPT_POLICY_V1: err = fscrypt_setup_v1_file_key(ci, mk->mk_secret.raw); @@ -341,7 +478,7 @@ static void put_crypt_info(struct fscrypt_info *ci) if (ci->ci_direct_key) fscrypt_put_direct_key(ci->ci_direct_key); else if (ci->ci_owns_key) - crypto_free_skcipher(ci->ci_ctfm); + fscrypt_destroy_prepared_key(&ci->ci_key); key = ci->ci_master_key; if (key) { @@ -393,7 +530,7 @@ int fscrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.version = FSCRYPT_CONTEXT_V1; - ctx.v1.contents_encryption_mode = fscrypt_data_encryption_mode(inode); + ctx.v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS; ctx.v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS; memset(ctx.v1.master_key_descriptor, 0x42, FSCRYPT_KEY_DESCRIPTOR_SIZE); @@ -413,20 +550,8 @@ int fscrypt_get_encryption_info(struct inode *inode) goto out; } - switch (ctx.version) { - case FSCRYPT_CONTEXT_V1: - memcpy(crypt_info->ci_nonce, ctx.v1.nonce, - FS_KEY_DERIVATION_NONCE_SIZE); - break; - case FSCRYPT_CONTEXT_V2: - memcpy(crypt_info->ci_nonce, ctx.v2.nonce, - FS_KEY_DERIVATION_NONCE_SIZE); - break; - default: - WARN_ON(1); - res = -EINVAL; - goto out; - } + memcpy(crypt_info->ci_nonce, fscrypt_context_nonce(&ctx), + FS_KEY_DERIVATION_NONCE_SIZE); if (!fscrypt_supported_policy(&crypt_info->ci_policy, inode)) { res = -EINVAL; @@ -487,11 +612,6 @@ void fscrypt_put_encryption_info(struct inode *inode) } EXPORT_SYMBOL(fscrypt_put_encryption_info); -int fscrypt_get_mode_key_size(int mode) -{ - return available_modes[mode].keysize; -} - /** * fscrypt_free_inode - free an inode's fscrypt data requiring RCU delay * @@ -531,6 +651,15 @@ int fscrypt_drop_inode(struct inode *inode) return 0; mk = ci->ci_master_key->payload.data[0]; + /* + * With proper, non-racy use of FS_IOC_REMOVE_ENCRYPTION_KEY, all inodes + * protected by the key were cleaned by sync_filesystem(). But if + * userspace is still using the files, inodes can be dirtied between + * then and now. We mustn't lose any writes, so skip dirty inodes here. + */ + if (inode->i_state & I_DIRTY_ALL) + return 0; + /* * Note: since we aren't holding ->mk_secret_sem, the result here can * immediately become outdated. But there's no correctness problem with diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index b217970ef3928312c15037163fa621f0be0ce117..38e54313653d24bc1a289b414c3dbf050725d916 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -9,7 +9,7 @@ * This file implements compatibility functions for the original encryption * policy version ("v1"), including: * - * - Deriving per-file keys using the AES-128-ECB based KDF + * - Deriving per-file encryption keys using the AES-128-ECB based KDF * (rather than the new method of using HKDF-SHA512) * * - Retrieving fscrypt master keys from process-subscribed keyrings @@ -25,6 +25,7 @@ #include #include #include +#include #include "fscrypt_private.h" @@ -146,7 +147,7 @@ struct fscrypt_direct_key { struct hlist_node dk_node; refcount_t dk_refcount; const struct fscrypt_mode *dk_mode; - struct crypto_skcipher *dk_ctfm; + struct fscrypt_prepared_key dk_key; u8 dk_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; u8 dk_raw[FSCRYPT_MAX_KEY_SIZE]; }; @@ -154,7 +155,7 @@ struct fscrypt_direct_key { static void free_direct_key(struct fscrypt_direct_key *dk) { if (dk) { - crypto_free_skcipher(dk->dk_ctfm); + fscrypt_destroy_prepared_key(&dk->dk_key); kzfree(dk); } } @@ -199,6 +200,8 @@ find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, continue; if (ci->ci_mode != dk->dk_mode) continue; + if (!fscrypt_is_key_prepared(&dk->dk_key, ci)) + continue; if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize)) continue; /* using existing tfm with same (descriptor, mode, raw_key) */ @@ -231,13 +234,10 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) return ERR_PTR(-ENOMEM); refcount_set(&dk->dk_refcount, 1); dk->dk_mode = ci->ci_mode; - dk->dk_ctfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, - ci->ci_inode); - if (IS_ERR(dk->dk_ctfm)) { - err = PTR_ERR(dk->dk_ctfm); - dk->dk_ctfm = NULL; + err = fscrypt_prepare_key(&dk->dk_key, raw_key, ci->ci_mode->keysize, + false /*is_hw_wrapped*/, ci); + if (err) goto err_free_dk; - } memcpy(dk->dk_descriptor, ci->ci_policy.v1.master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE); memcpy(dk->dk_raw, raw_key, ci->ci_mode->keysize); @@ -253,28 +253,13 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) static int setup_v1_file_key_direct(struct fscrypt_info *ci, const u8 *raw_master_key) { - const struct fscrypt_mode *mode = ci->ci_mode; struct fscrypt_direct_key *dk; - if (!fscrypt_mode_supports_direct_key(mode)) { - fscrypt_warn(ci->ci_inode, - "Direct key mode not allowed with %s", - mode->friendly_name); - return -EINVAL; - } - - if (ci->ci_policy.v1.contents_encryption_mode != - ci->ci_policy.v1.filenames_encryption_mode) { - fscrypt_warn(ci->ci_inode, - "Direct key mode not allowed with different contents and filenames modes"); - return -EINVAL; - } - dk = fscrypt_get_direct_key(ci, raw_master_key); if (IS_ERR(dk)) return PTR_ERR(dk); ci->ci_direct_key = dk; - ci->ci_ctfm = dk->dk_ctfm; + ci->ci_key = dk->dk_key; return 0; } @@ -284,7 +269,28 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci, { u8 *derived_key; int err; - + int i; + union { + u8 bytes[FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE]; + u32 words[FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE / sizeof(u32)]; + } key_new; + + /*Support legacy ice based content encryption mode*/ + if ((fscrypt_policy_contents_mode(&ci->ci_policy) == + FSCRYPT_MODE_PRIVATE) && + fscrypt_using_inline_encryption(ci)) { + memcpy(key_new.bytes, raw_master_key, ci->ci_mode->keysize); + + for (i = 0; i < ARRAY_SIZE(key_new.words); i++) + __cpu_to_be32s(&key_new.words[i]); + + err = fscrypt_prepare_inline_crypt_key(&ci->ci_key, + key_new.bytes, + ci->ci_mode->keysize, + false, + ci); + return err; + } /* * This cannot be a stack buffer because it will be passed to the * scatterlist crypto API during derive_key_aes(). @@ -298,7 +304,7 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci, if (err) goto out; - err = fscrypt_set_derived_key(ci, derived_key); + err = fscrypt_set_per_file_enc_key(ci, derived_key); out: kzfree(derived_key); return err; @@ -306,25 +312,10 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci, int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, const u8 *raw_master_key) { - int err; - if (ci->ci_policy.v1.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { + if (ci->ci_policy.v1.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) return setup_v1_file_key_direct(ci, raw_master_key); - } else if(S_ISREG(ci->ci_inode->i_mode) && - (fscrypt_policy_contents_mode(&(ci->ci_policy)) == FSCRYPT_MODE_PRIVATE)) { - /* Inline encryption: no key derivation required because IVs are - * assigned based on iv_sector. - */ - if (ci->ci_mode->keysize != FSCRYPT_MAX_KEY_SIZE) { - err = -EINVAL; - } else { - memcpy(ci->ci_raw_key, raw_master_key, ci->ci_mode->keysize); - err = 0; - } - } - else { + else return setup_v1_file_key_derived(ci, raw_master_key); - } - return err; } int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 96f528071bed3f8ea401e38b90ae622d7a261745..804595aaea0387aa8116b05cfa9ea7821b643727 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -29,18 +29,55 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1, return !memcmp(policy1, policy2, fscrypt_policy_size(policy1)); } -static bool supported_iv_ino_lblk_64_policy( - const struct fscrypt_policy_v2 *policy, - const struct inode *inode) +static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) { - struct super_block *sb = inode->i_sb; - int ino_bits = 64, lblk_bits = 64; + if (contents_mode == FSCRYPT_MODE_AES_256_XTS && + filenames_mode == FSCRYPT_MODE_AES_256_CTS) + return true; + + if (contents_mode == FSCRYPT_MODE_AES_128_CBC && + filenames_mode == FSCRYPT_MODE_AES_128_CTS) + return true; + + if (contents_mode == FSCRYPT_MODE_ADIANTUM && + filenames_mode == FSCRYPT_MODE_ADIANTUM) + return true; + + if (contents_mode == FSCRYPT_MODE_PRIVATE && + filenames_mode == FSCRYPT_MODE_AES_256_CTS) + return true; + + return false; +} - if (policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { +static bool supported_direct_key_modes(const struct inode *inode, + u32 contents_mode, u32 filenames_mode) +{ + const struct fscrypt_mode *mode; + + if (contents_mode != filenames_mode) { fscrypt_warn(inode, - "The DIRECT_KEY and IV_INO_LBLK_64 flags are mutually exclusive"); + "Direct key flag not allowed with different contents and filenames modes"); + return false; + } + mode = &fscrypt_modes[contents_mode]; + + if (mode->ivsize < offsetofend(union fscrypt_iv, nonce)) { + fscrypt_warn(inode, "Direct key flag not allowed with %s", + mode->friendly_name); return false; } + return true; +} + +static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy, + const struct inode *inode, + const char *type, + int max_ino_bits, int max_lblk_bits) +{ + struct super_block *sb = inode->i_sb; + int ino_bits = 64, lblk_bits = 64; + /* * It's unsafe to include inode numbers in the IVs if the filesystem can * potentially renumber inodes, e.g. via filesystem shrinking. @@ -48,18 +85,111 @@ static bool supported_iv_ino_lblk_64_policy( if (!sb->s_cop->has_stable_inodes || !sb->s_cop->has_stable_inodes(sb)) { fscrypt_warn(inode, - "Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't have stable inode numbers", - sb->s_id); + "Can't use %s policy on filesystem '%s' because it doesn't have stable inode numbers", + type, sb->s_id); return false; } if (sb->s_cop->get_ino_and_lblk_bits) sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits); - if (ino_bits > 32 || lblk_bits > 32) { + if (ino_bits > max_ino_bits) { + fscrypt_warn(inode, + "Can't use %s policy on filesystem '%s' because its inode numbers are too long", + type, sb->s_id); + return false; + } + if (lblk_bits > max_lblk_bits) { + fscrypt_warn(inode, + "Can't use %s policy on filesystem '%s' because its block numbers are too long", + type, sb->s_id); + return false; + } + return true; +} + +static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, + const struct inode *inode) +{ + if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, + policy->filenames_encryption_mode)) { + fscrypt_warn(inode, + "Unsupported encryption modes (contents %d, filenames %d)", + policy->contents_encryption_mode, + policy->filenames_encryption_mode); + return false; + } + + if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | + FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { + fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", + policy->flags); + return false; + } + + if ((policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) && + !supported_direct_key_modes(inode, policy->contents_encryption_mode, + policy->filenames_encryption_mode)) + return false; + + if (IS_CASEFOLDED(inode)) { + /* With v1, there's no way to derive dirhash keys. */ + fscrypt_warn(inode, + "v1 policies can't be used on casefolded directories"); + return false; + } + + return true; +} + +static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, + const struct inode *inode) +{ + int count = 0; + + if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, + policy->filenames_encryption_mode)) { fscrypt_warn(inode, - "Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't use 32-bit inode and block numbers", - sb->s_id); + "Unsupported encryption modes (contents %d, filenames %d)", + policy->contents_encryption_mode, + policy->filenames_encryption_mode); return false; } + + if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) { + fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", + policy->flags); + return false; + } + + count += !!(policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY); + count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64); + count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32); + if (count > 1) { + fscrypt_warn(inode, "Mutually exclusive encryption flags (0x%02x)", + policy->flags); + return false; + } + + if ((policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) && + !supported_direct_key_modes(inode, policy->contents_encryption_mode, + policy->filenames_encryption_mode)) + return false; + + if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) && + !supported_iv_ino_lblk_policy(policy, inode, "IV_INO_LBLK_64", + 32, 32)) + return false; + + if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) && + /* This uses hashed inode numbers, so ino_bits doesn't matter. */ + !supported_iv_ino_lblk_policy(policy, inode, "IV_INO_LBLK_32", + INT_MAX, 32)) + return false; + + if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) { + fscrypt_warn(inode, "Reserved bits set in encryption policy"); + return false; + } + return true; } @@ -67,9 +197,9 @@ static bool supported_iv_ino_lblk_64_policy( * fscrypt_supported_policy - check whether an encryption policy is supported * * Given an encryption policy, check whether all its encryption modes and other - * settings are supported by this kernel. (But we don't currently don't check - * for crypto API support here, so attempting to use an algorithm not configured - * into the crypto API will still fail later.) + * settings are supported by this kernel on the given inode. (But we don't + * currently don't check for crypto API support here, so attempting to use an + * algorithm not configured into the crypto API will still fail later.) * * Return: %true if supported, else %false */ @@ -77,60 +207,10 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, const struct inode *inode) { switch (policy_u->version) { - case FSCRYPT_POLICY_V1: { - const struct fscrypt_policy_v1 *policy = &policy_u->v1; - - if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, - policy->filenames_encryption_mode)) { - fscrypt_warn(inode, - "Unsupported encryption modes (contents %d, filenames %d)", - policy->contents_encryption_mode, - policy->filenames_encryption_mode); - return false; - } - - if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | - FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { - fscrypt_warn(inode, - "Unsupported encryption flags (0x%02x)", - policy->flags); - return false; - } - - return true; - } - case FSCRYPT_POLICY_V2: { - const struct fscrypt_policy_v2 *policy = &policy_u->v2; - - if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, - policy->filenames_encryption_mode)) { - fscrypt_warn(inode, - "Unsupported encryption modes (contents %d, filenames %d)", - policy->contents_encryption_mode, - policy->filenames_encryption_mode); - return false; - } - - if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) { - fscrypt_warn(inode, - "Unsupported encryption flags (0x%02x)", - policy->flags); - return false; - } - - if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) && - !supported_iv_ino_lblk_64_policy(policy, inode)) - return false; - - if (memchr_inv(policy->__reserved, 0, - sizeof(policy->__reserved))) { - fscrypt_warn(inode, - "Reserved bits set in encryption policy"); - return false; - } - - return true; - } + case FSCRYPT_POLICY_V1: + return fscrypt_supported_v1_policy(&policy_u->v1, inode); + case FSCRYPT_POLICY_V2: + return fscrypt_supported_v2_policy(&policy_u->v2, inode); } return false; } @@ -202,7 +282,7 @@ int fscrypt_policy_from_context(union fscrypt_policy *policy_u, { memset(policy_u, 0, sizeof(*policy_u)); - if (ctx_size <= 0 || ctx_size != fscrypt_context_size(ctx_u)) + if (!fscrypt_context_is_valid(ctx_u, ctx_size)) return -EINVAL; switch (ctx_u->version) { @@ -298,6 +378,9 @@ static int set_encryption_policy(struct inode *inode, policy->v2.master_key_identifier); if (err) return err; + if (policy->v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) + pr_warn_once("%s (pid %d) is setting an IV_INO_LBLK_32 encryption policy. This should only be used if there are certain hardware limitations.\n", + current->comm, current->pid); break; default: WARN_ON(1); @@ -425,6 +508,25 @@ int fscrypt_ioctl_get_policy_ex(struct file *filp, void __user *uarg) } EXPORT_SYMBOL_GPL(fscrypt_ioctl_get_policy_ex); +/* FS_IOC_GET_ENCRYPTION_NONCE: retrieve file's encryption nonce for testing */ +int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg) +{ + struct inode *inode = file_inode(filp); + union fscrypt_context ctx; + int ret; + + ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (ret < 0) + return ret; + if (!fscrypt_context_is_valid(&ctx, ret)) + return -EINVAL; + if (copy_to_user(arg, fscrypt_context_nonce(&ctx), + FS_KEY_DERIVATION_NONCE_SIZE)) + return -EFAULT; + return 0; +} +EXPORT_SYMBOL_GPL(fscrypt_ioctl_get_nonce); + /** * fscrypt_has_permitted_context() - is a file's encryption policy permitted * within its directory? diff --git a/fs/dax.c b/fs/dax.c index ddb4981ae32eb910c66c493dfa829151a4ef9f72..34a55754164f44a997236e59303ae28b07434d79 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -1057,6 +1057,9 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, lockdep_assert_held(&inode->i_rwsem); } + if (iocb->ki_flags & IOCB_NOWAIT) + flags |= IOMAP_NOWAIT; + while (iov_iter_count(iter)) { ret = iomap_apply(inode, pos, iov_iter_count(iter), flags, ops, iter, dax_iomap_actor); diff --git a/fs/direct-io.c b/fs/direct-io.c index b88a0a9a66ddda701e0e3f07c040c515846b1da5..094421f05fda43b632e8ffe0d4e107048e4013f7 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,8 +38,6 @@ #include #include #include -#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_F2FS_FS_ENCRYPTION) -#include /* * How many user pages to map in one call to get_user_pages(). This determines @@ -433,6 +432,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, sector_t first_sector, int nr_vecs) { struct bio *bio; + struct inode *inode = dio->inode; /* * bio_alloc() is guaranteed to return a bio when called with @@ -440,6 +440,9 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, */ bio = bio_alloc(GFP_KERNEL, nr_vecs); + fscrypt_set_bio_crypt_ctx(bio, inode, + sdio->cur_page_fs_offset >> inode->i_blkbits, + GFP_KERNEL); bio_set_dev(bio, bdev); bio->bi_iter.bi_sector = first_sector; bio_set_op_attrs(bio, dio->op, dio->op_flags); @@ -454,23 +457,6 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, sdio->logical_offset_in_bio = sdio->cur_page_fs_offset; } -#ifdef CONFIG_PFK -static bool is_inode_filesystem_type(const struct inode *inode, - const char *fs_type) -{ - if (!inode || !fs_type) - return false; - - if (!inode->i_sb) - return false; - - if (!inode->i_sb->s_type) - return false; - - return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); -} -#endif - /* * In the AIO read case we speculatively dirty the pages before starting IO. * During IO completion, any of these pages which happen to have been written @@ -493,17 +479,7 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) bio_set_pages_dirty(bio); dio->bio_disk = bio->bi_disk; -#ifdef CONFIG_PFK - bio->bi_dio_inode = dio->inode; - -/* iv sector for security/pfe/pfk_fscrypt.c and f2fs in fs/f2fs/f2fs.h */ -#define PG_DUN_NEW(i,p) \ - (((((u64)(i)->i_ino) & 0xffffffff) << 32) | ((p) & 0xffffffff)) - if (is_inode_filesystem_type(dio->inode, "f2fs")) - fscrypt_set_ice_dun(dio->inode, bio, PG_DUN_NEW(dio->inode, - (sdio->logical_offset_in_bio >> PAGE_SHIFT))); -#endif if (sdio->submit_io) { sdio->submit_io(bio, dio->inode, sdio->logical_offset_in_bio); dio->bio_cookie = BLK_QC_T_NONE; @@ -515,18 +491,6 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) sdio->logical_offset_in_bio = 0; } -struct inode *dio_bio_get_inode(struct bio *bio) -{ - struct inode *inode = NULL; - - if (bio == NULL) - return NULL; -#ifdef CONFIG_PFK - inode = bio->bi_dio_inode; -#endif - return inode; -} - /* * Release any resources in case of a failure */ @@ -851,9 +815,17 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio, * current logical offset in the file does not equal what would * be the next logical offset in the bio, submit the bio we * have. + * + * When fscrypt inline encryption is used, data unit number + * (DUN) contiguity is also required. Normally that's implied + * by logical contiguity. However, certain IV generation + * methods (e.g. IV_INO_LBLK_32) don't guarantee it. So, we + * must explicitly check fscrypt_mergeable_bio() too. */ if (sdio->final_block_in_bio != sdio->cur_page_block || - cur_offset != bio_next_offset) + cur_offset != bio_next_offset || + !fscrypt_mergeable_bio(sdio->bio, dio->inode, + cur_offset >> dio->inode->i_blkbits)) dio_bio_submit(dio, sdio); } diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index bd25ab8370118cd40dd9e6e48aa689a3b3a02c9f..eed38ae86c6c1887ab32f8ff9b19cd658f057388 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -339,8 +339,10 @@ static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct extent_crypt_result ecr; int rc = 0; - BUG_ON(!crypt_stat || !crypt_stat->tfm - || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); + if (!crypt_stat || !crypt_stat->tfm + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)) + return -EINVAL; + if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", crypt_stat->key_size); diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index fa218cd64f746d2c924a786edc1c6052911c1732..b134315fb69d060974a252a1ccd2191a9be865c3 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1335,7 +1335,7 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat, printk(KERN_WARNING "Tag 1 packet contains key larger " "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES"); rc = -EINVAL; - goto out; + goto out_free; } memcpy((*new_auth_tok)->session_key.encrypted_key, &data[(*packet_size)], (body_size - (ECRYPTFS_SIG_SIZE + 2))); diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 4f457d5c49331cb7b813b5c9ca4257bd59ce5c3b..26464f9d9b769dc4250d40e923dd4f73e7ee6e74 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -397,6 +397,7 @@ int __init ecryptfs_init_messaging(void) * ecryptfs_message_buf_len), GFP_KERNEL); if (!ecryptfs_msg_ctx_arr) { + kfree(ecryptfs_daemon_hash); rc = -ENOMEM; printk(KERN_ERR "%s: Failed to allocate memory\n", __func__); goto out; diff --git a/fs/exec.c b/fs/exec.c index 81c438d94ae73d3a73ba5ef0ea76e71fee513aae..52ab168d4dcc5a37850347b974dcf1191f6d5104 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1373,7 +1373,7 @@ void setup_new_exec(struct linux_binprm * bprm) /* An exec changes our domain. We are no longer part of the thread group */ - current->self_exec_id++; + WRITE_ONCE(current->self_exec_id, current->self_exec_id + 1); flush_signal_handlers(current, 0); } EXPORT_SYMBOL(setup_new_exec); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 13f4706366729f2b999beb0d5812fe19a672e30b..4a338576ebb18e6aadfdddbcd6ceb9ce72b11816 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1077,9 +1077,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) if (EXT2_BLOCKS_PER_GROUP(sb) == 0) goto cantfind_ext2; - sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_first_data_block) - 1) - / EXT2_BLOCKS_PER_GROUP(sb)) + 1; + sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_first_data_block) - 1) + / EXT2_BLOCKS_PER_GROUP(sb)) + 1; db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / EXT2_DESC_PER_BLOCK(sb); sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index dd8f10db82e992da8b8f4fb37699d7bf4a87cf4d..bd1d68ff3a9f81ffecb3c4138cd646532ba3733c 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -84,8 +85,8 @@ printk("\n"); \ } while (0) #else -# define ea_idebug(f...) -# define ea_bdebug(f...) +# define ea_idebug(inode, f...) no_printk(f) +# define ea_bdebug(bh, f...) no_printk(f) #endif static int ext2_xattr_set2(struct inode *, struct buffer_head *, @@ -838,8 +839,7 @@ ext2_xattr_cache_insert(struct mb_cache *cache, struct buffer_head *bh) error = mb_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr, 1); if (error) { if (error == -EBUSY) { - ea_bdebug(bh, "already in cache (%d cache entries)", - atomic_read(&ext2_xattr_cache->c_entry_count)); + ea_bdebug(bh, "already in cache"); error = 0; } } else diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index 6eea530054d24b01bbd515a5d2ea6084a45e1914..332ebb130feea746a252941c3fe53d6c7b70c7b1 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -37,6 +37,7 @@ config EXT4_FS select CRC16 select CRYPTO select CRYPTO_CRC32C + select FS_ENCRYPTION_ALGS if FS_ENCRYPTION help This is the next generation of the ext3 filesystem. @@ -108,16 +109,10 @@ config EXT4_ENCRYPTION files config EXT4_FS_ENCRYPTION - bool "Ext4 FS Encryption" + bool default n depends on EXT4_ENCRYPTION -config EXT4_FS_ICE_ENCRYPTION - bool "Ext4 Encryption with ICE support" - default n - depends on EXT4_FS_ENCRYPTION - depends on PFK - config EXT4_DEBUG bool "EXT4 debugging support" depends on EXT4_FS diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 70266a3355dc320ef141c4c2b225b5a3e9211003..fb38f20f869e71e2fbf460ca5dd7168f33e54ad8 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -280,6 +280,7 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, ext4_group_t ngroups = ext4_get_groups_count(sb); struct ext4_group_desc *desc; struct ext4_sb_info *sbi = EXT4_SB(sb); + struct buffer_head *bh_p; if (block_group >= ngroups) { ext4_error(sb, "block_group >= groups_count - block_group = %u," @@ -290,7 +291,14 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); - if (!sbi->s_group_desc[group_desc]) { + bh_p = sbi_array_rcu_deref(sbi, s_group_desc, group_desc); + /* + * sbi_array_rcu_deref returns with rcu unlocked, this is ok since + * the pointer being dereferenced won't be dereferenced again. By + * looking at the usage in add_new_gdb() the value isn't modified, + * just the pointer, and so it remains valid. + */ + if (!bh_p) { ext4_error(sb, "Group descriptor not loaded - " "block_group = %u, group_desc = %u, desc = %u", block_group, group_desc, offset); @@ -298,10 +306,10 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, } desc = (struct ext4_group_desc *)( - (__u8 *)sbi->s_group_desc[group_desc]->b_data + + (__u8 *)bh_p->b_data + offset * EXT4_DESC_SIZE(sb)); if (bh) - *bh = sbi->s_group_desc[group_desc]; + *bh = bh_p; return desc; } diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c index bee888e0e2db3e7ae415ab9d7f67c45b6a29061a..13eb028607caf20d171314adae0a60618a52ae2f 100644 --- a/fs/ext4/block_validity.c +++ b/fs/ext4/block_validity.c @@ -137,6 +137,49 @@ static void debug_print_tree(struct ext4_sb_info *sbi) printk(KERN_CONT "\n"); } +static int ext4_protect_reserved_inode(struct super_block *sb, u32 ino) +{ + struct inode *inode; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_map_blocks map; + u32 i = 0, num; + int err = 0, n; + + if ((ino < EXT4_ROOT_INO) || + (ino > le32_to_cpu(sbi->s_es->s_inodes_count))) + return -EINVAL; + inode = ext4_iget(sb, ino, EXT4_IGET_SPECIAL); + if (IS_ERR(inode)) + return PTR_ERR(inode); + num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; + while (i < num) { + map.m_lblk = i; + map.m_len = num - i; + n = ext4_map_blocks(NULL, inode, &map, 0); + if (n < 0) { + err = n; + break; + } + if (n == 0) { + i++; + } else { + if (!ext4_data_block_valid(sbi, map.m_pblk, n)) { + ext4_error(sb, "blocks %llu-%llu from inode %u " + "overlap system zone", map.m_pblk, + map.m_pblk + map.m_len - 1, ino); + err = -EFSCORRUPTED; + break; + } + err = add_system_zone(sbi, map.m_pblk, n); + if (err < 0) + break; + i += n; + } + } + iput(inode); + return err; +} + int ext4_setup_system_zone(struct super_block *sb) { ext4_group_t ngroups = ext4_get_groups_count(sb); @@ -171,6 +214,12 @@ int ext4_setup_system_zone(struct super_block *sb) if (ret) return ret; } + if (ext4_has_feature_journal(sb) && sbi->s_es->s_journal_inum) { + ret = ext4_protect_reserved_inode(sb, + le32_to_cpu(sbi->s_es->s_journal_inum)); + if (ret) + return ret; + } if (test_opt(sb, DEBUG)) debug_print_tree(EXT4_SB(sb)); @@ -227,6 +276,11 @@ int ext4_check_blockref(const char *function, unsigned int line, __le32 *bref = p; unsigned int blk; + if (ext4_has_feature_journal(inode->i_sb) && + (inode->i_ino == + le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) + return 0; + while (bref < p+max) { blk = le32_to_cpu(*bref++); if (blk && diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 1014369e535b070b98f1387f4dad699e1a94e6a4..ee766e3bed8b6182502f7d169e3b176ac4301389 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -117,7 +117,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) if (IS_ENCRYPTED(inode)) { err = fscrypt_get_encryption_info(inode); - if (err && err != -ENOKEY) + if (err) return err; } @@ -126,12 +126,14 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) if (err != ERR_BAD_DX_DIR) { return err; } - /* - * We don't set the inode dirty flag since it's not - * critical that it get flushed back to the disk. - */ - ext4_clear_inode_flag(file_inode(file), - EXT4_INODE_INDEX); + /* Can we just clear INDEX flag to ignore htree information? */ + if (!ext4_has_metadata_csum(sb)) { + /* + * We don't set the inode dirty flag since it's not + * critical that it gets flushed back to the disk. + */ + ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); + } } if (ext4_has_inline_data(inode)) { @@ -662,51 +664,3 @@ const struct file_operations ext4_dir_operations = { .open = ext4_dir_open, .release = ext4_release_dir, }; - -#ifdef CONFIG_UNICODE -static int ext4_d_compare(const struct dentry *dentry, unsigned int len, - const char *str, const struct qstr *name) -{ - struct qstr qstr = {.name = str, .len = len }; - struct inode *inode = dentry->d_parent->d_inode; - - if (!IS_CASEFOLDED(inode) || !EXT4_SB(inode->i_sb)->s_encoding) { - if (len != name->len) - return -1; - return memcmp(str, name->name, len); - } - - return ext4_ci_compare(inode, name, &qstr, false); -} - -static int ext4_d_hash(const struct dentry *dentry, struct qstr *str) -{ - const struct ext4_sb_info *sbi = EXT4_SB(dentry->d_sb); - const struct unicode_map *um = sbi->s_encoding; - unsigned char *norm; - int len, ret = 0; - - if (!IS_CASEFOLDED(dentry->d_inode) || !um) - return 0; - - norm = kmalloc(PATH_MAX, GFP_ATOMIC); - if (!norm) - return -ENOMEM; - - len = utf8_casefold(um, str, norm, PATH_MAX); - if (len < 0) { - if (ext4_has_strict_mode(sbi)) - ret = -EINVAL; - goto out; - } - str->hash = full_name_hash(dentry, norm, len); -out: - kfree(norm); - return ret; -} - -const struct dentry_operations ext4_dentry_ops = { - .d_hash = ext4_d_hash, - .d_compare = ext4_d_compare, -}; -#endif diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 3bab4b55fa3ccc3a5a35bd0141b4f27dc99326da..a2d6e8f0eb971ddb357e6e549b7fb4352cc3cd24 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -205,10 +205,7 @@ typedef struct ext4_io_end { ssize_t size; /* size of the extent */ } ext4_io_end_t; -#define EXT4_IO_ENCRYPTED 1 - struct ext4_io_submit { - unsigned int io_flags; struct writeback_control *io_wbc; struct bio *io_bio; ext4_io_end_t *io_end; @@ -1158,6 +1155,7 @@ struct ext4_inode_info { #define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000 /* Enable support for dio read nolocking */ #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ +#define EXT4_MOUNT_INLINECRYPT 0x4000000 /* Inline encryption support */ #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ @@ -1378,14 +1376,6 @@ struct ext4_super_block { #define EXT4_ENC_UTF8_12_1 1 -/* - * Flags for ext4_sb_info.s_encoding_flags. - */ -#define EXT4_ENC_STRICT_MODE_FL (1 << 0) - -#define ext4_has_strict_mode(sbi) \ - (sbi->s_encoding_flags & EXT4_ENC_STRICT_MODE_FL) - /* * fourth extended-fs super-block data in memory */ @@ -1406,7 +1396,7 @@ struct ext4_sb_info { loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ struct buffer_head * s_sbh; /* Buffer containing the super block */ struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ - struct buffer_head **s_group_desc; + struct buffer_head * __rcu *s_group_desc; unsigned int s_mount_opt; unsigned int s_mount_opt2; unsigned int s_mount_flags; @@ -1437,10 +1427,6 @@ struct ext4_sb_info { struct kobject s_kobj; struct completion s_kobj_unregister; struct super_block *s_sb; -#ifdef CONFIG_UNICODE - struct unicode_map *s_encoding; - __u16 s_encoding_flags; -#endif /* Journaling */ struct journal_s *s_journal; @@ -1470,7 +1456,7 @@ struct ext4_sb_info { #endif /* for buddy allocator */ - struct ext4_group_info ***s_group_info; + struct ext4_group_info ** __rcu *s_group_info; struct inode *s_buddy_cache; spinlock_t s_md_lock; unsigned short *s_mb_offsets; @@ -1520,7 +1506,7 @@ struct ext4_sb_info { unsigned int s_extent_max_zeroout_kb; unsigned int s_log_groups_per_flex; - struct flex_groups *s_flex_groups; + struct flex_groups * __rcu *s_flex_groups; ext4_group_t s_flex_groups_allocated; /* workqueue for reserved extent conversions (buffered io) */ @@ -1560,8 +1546,11 @@ struct ext4_sb_info { struct ratelimit_state s_warning_ratelimit_state; struct ratelimit_state s_msg_ratelimit_state; - /* Barrier between changing inodes' journal flags and writepages ops. */ - struct percpu_rw_semaphore s_journal_flag_rwsem; + /* + * Barrier between writepages ops and changing any inode's JOURNAL_DATA + * or EXTENTS flag. + */ + struct percpu_rw_semaphore s_writepages_rwsem; struct dax_device *s_daxdev; }; @@ -1581,6 +1570,23 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)); } +/* + * Returns: sbi->field[index] + * Used to access an array element from the following sbi fields which require + * rcu protection to avoid dereferencing an invalid pointer due to reassignment + * - s_group_desc + * - s_group_info + * - s_flex_group + */ +#define sbi_array_rcu_deref(sbi, field, index) \ +({ \ + typeof(*((sbi)->field)) _v; \ + rcu_read_lock(); \ + _v = ((typeof(_v)*)rcu_dereference((sbi)->field))[index]; \ + rcu_read_unlock(); \ + _v; \ +}) + /* * Inode dynamic state flags */ @@ -2486,8 +2492,11 @@ void ext4_insert_dentry(struct inode *inode, struct ext4_filename *fname); static inline void ext4_update_dx_flag(struct inode *inode) { - if (!ext4_has_feature_dir_index(inode->i_sb)) + if (!ext4_has_feature_dir_index(inode->i_sb)) { + /* ext4_iget() should have caught this... */ + WARN_ON_ONCE(ext4_has_feature_metadata_csum(inode->i_sb)); ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); + } } static const unsigned char ext4_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK @@ -2586,8 +2595,19 @@ int do_journal_get_write_access(handle_t *handle, #define FALL_BACK_TO_NONDELALLOC 1 #define CONVERT_INLINE_DATA 2 -extern struct inode *ext4_iget(struct super_block *, unsigned long); -extern struct inode *ext4_iget_normal(struct super_block *, unsigned long); +typedef enum { + EXT4_IGET_NORMAL = 0, + EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */ + EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */ +} ext4_iget_flags; + +extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, + ext4_iget_flags flags, const char *function, + unsigned int line); + +#define ext4_iget(sb, ino, flags) \ + __ext4_iget((sb), (ino), (flags), __func__, __LINE__) + extern int ext4_write_inode(struct inode *, struct writeback_control *); extern int ext4_setattr(struct dentry *, struct iattr *); extern int ext4_getattr(const struct path *, struct kstat *, u32, unsigned int); @@ -2663,6 +2683,7 @@ extern int ext4_generic_delete_entry(handle_t *handle, extern bool ext4_empty_dir(struct inode *inode); /* resize.c */ +extern void ext4_kvfree_array_rcu(void *to_free); extern int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input); extern int ext4_group_extend(struct super_block *sb, @@ -2908,13 +2929,13 @@ static inline struct ext4_group_info *ext4_get_group_info(struct super_block *sb, ext4_group_t group) { - struct ext4_group_info ***grp_info; + struct ext4_group_info **grp_info; long indexv, indexh; BUG_ON(group >= EXT4_SB(sb)->s_groups_count); - grp_info = EXT4_SB(sb)->s_group_info; indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb)); indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1); - return grp_info[indexv][indexh]; + grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv); + return grp_info[indexh]; } /* @@ -2964,7 +2985,7 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize) !inode_is_locked(inode)); down_write(&EXT4_I(inode)->i_data_sem); if (newsize > EXT4_I(inode)->i_disksize) - EXT4_I(inode)->i_disksize = newsize; + WRITE_ONCE(EXT4_I(inode)->i_disksize, newsize); up_write(&EXT4_I(inode)->i_data_sem); } @@ -3205,7 +3226,7 @@ static inline void ext4_set_de_type(struct super_block *sb, /* readpages.c */ extern int ext4_mpage_readpages(struct address_space *mapping, struct list_head *pages, struct page *page, - unsigned nr_pages); + unsigned nr_pages, bool is_readahead); extern int __init ext4_init_post_read_processing(void); extern void ext4_exit_post_read_processing(void); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index ceddff15e548f7415ef02dd4a02b42c4e1af567a..2824b5c6518744783abb9181de31dc3633161b95 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -510,6 +510,30 @@ int ext4_ext_check_inode(struct inode *inode) return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode), 0); } +static void ext4_cache_extents(struct inode *inode, + struct ext4_extent_header *eh) +{ + struct ext4_extent *ex = EXT_FIRST_EXTENT(eh); + ext4_lblk_t prev = 0; + int i; + + for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) { + unsigned int status = EXTENT_STATUS_WRITTEN; + ext4_lblk_t lblk = le32_to_cpu(ex->ee_block); + int len = ext4_ext_get_actual_len(ex); + + if (prev && (prev != lblk)) + ext4_es_cache_extent(inode, prev, lblk - prev, ~0, + EXTENT_STATUS_HOLE); + + if (ext4_ext_is_unwritten(ex)) + status = EXTENT_STATUS_UNWRITTEN; + ext4_es_cache_extent(inode, lblk, len, + ext4_ext_pblock(ex), status); + prev = lblk + len; + } +} + static struct buffer_head * __read_extent_tree_block(const char *function, unsigned int line, struct inode *inode, ext4_fsblk_t pblk, int depth, @@ -530,36 +554,21 @@ __read_extent_tree_block(const char *function, unsigned int line, } if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE)) return bh; - err = __ext4_ext_check(function, line, inode, - ext_block_hdr(bh), depth, pblk); - if (err) - goto errout; + if (!ext4_has_feature_journal(inode->i_sb) || + (inode->i_ino != + le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) { + err = __ext4_ext_check(function, line, inode, + ext_block_hdr(bh), depth, pblk); + if (err) + goto errout; + } set_buffer_verified(bh); /* * If this is a leaf block, cache all of its entries */ if (!(flags & EXT4_EX_NOCACHE) && depth == 0) { struct ext4_extent_header *eh = ext_block_hdr(bh); - struct ext4_extent *ex = EXT_FIRST_EXTENT(eh); - ext4_lblk_t prev = 0; - int i; - - for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) { - unsigned int status = EXTENT_STATUS_WRITTEN; - ext4_lblk_t lblk = le32_to_cpu(ex->ee_block); - int len = ext4_ext_get_actual_len(ex); - - if (prev && (prev != lblk)) - ext4_es_cache_extent(inode, prev, - lblk - prev, ~0, - EXTENT_STATUS_HOLE); - - if (ext4_ext_is_unwritten(ex)) - status = EXTENT_STATUS_UNWRITTEN; - ext4_es_cache_extent(inode, lblk, len, - ext4_ext_pblock(ex), status); - prev = lblk + len; - } + ext4_cache_extents(inode, eh); } return bh; errout: @@ -907,6 +916,8 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block, path[0].p_bh = NULL; i = depth; + if (!(flags & EXT4_EX_NOCACHE) && depth == 0) + ext4_cache_extents(inode, eh); /* walk through the tree */ while (i) { ext_debug("depth %d: num %d, max %d\n", @@ -3446,8 +3457,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, (unsigned long long)map->m_lblk, map_len); sbi = EXT4_SB(inode->i_sb); - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> - inode->i_sb->s_blocksize_bits; + eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1) + >> inode->i_sb->s_blocksize_bits; if (eof_block < map->m_lblk + map_len) eof_block = map->m_lblk + map_len; @@ -3702,8 +3713,8 @@ static int ext4_split_convert_extents(handle_t *handle, __func__, inode->i_ino, (unsigned long long)map->m_lblk, map->m_len); - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> - inode->i_sb->s_blocksize_bits; + eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1) + >> inode->i_sb->s_blocksize_bits; if (eof_block < map->m_lblk + map->m_len) eof_block = map->m_lblk + map->m_len; /* diff --git a/fs/ext4/file.c b/fs/ext4/file.c index e6c864668d0775d1f17e8fedc4bd8925e9f547bb..32a0f04d8517fd899b881d00045c5583cd5198ea 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -38,9 +38,10 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to) struct inode *inode = file_inode(iocb->ki_filp); ssize_t ret; - if (!inode_trylock_shared(inode)) { - if (iocb->ki_flags & IOCB_NOWAIT) + if (iocb->ki_flags & IOCB_NOWAIT) { + if (!inode_trylock_shared(inode)) return -EAGAIN; + } else { inode_lock_shared(inode); } /* @@ -188,9 +189,10 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) struct inode *inode = file_inode(iocb->ki_filp); ssize_t ret; - if (!inode_trylock(inode)) { - if (iocb->ki_flags & IOCB_NOWAIT) + if (iocb->ki_flags & IOCB_NOWAIT) { + if (!inode_trylock(inode)) return -EAGAIN; + } else { inode_lock(inode); } ret = ext4_write_checks(iocb, from); diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index ed76a6d7a2d89c75a4c5a193ffe9c7c6d910aeef..f3bc69b8d4e5351c5caad61d6f3ece89a8899258 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -277,7 +277,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len, struct dx_hash_info *hinfo) { #ifdef CONFIG_UNICODE - const struct unicode_map *um = EXT4_SB(dir->i_sb)->s_encoding; + const struct unicode_map *um = dir->i_sb->s_encoding; int r, dlen; unsigned char *buff; struct qstr qstr = {.name = name, .len = len }; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 6f9355227dc81ce62dedc771ddb220bbf382bd32..b9d4cb194462e50b41e683ac0db74232ba2f8092 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -333,11 +333,13 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) percpu_counter_inc(&sbi->s_freeinodes_counter); if (sbi->s_log_groups_per_flex) { - ext4_group_t f = ext4_flex_group(sbi, block_group); + struct flex_groups *fg; - atomic_inc(&sbi->s_flex_groups[f].free_inodes); + fg = sbi_array_rcu_deref(sbi, s_flex_groups, + ext4_flex_group(sbi, block_group)); + atomic_inc(&fg->free_inodes); if (is_directory) - atomic_dec(&sbi->s_flex_groups[f].used_dirs); + atomic_dec(&fg->used_dirs); } BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); fatal = ext4_handle_dirty_metadata(handle, NULL, bh2); @@ -378,12 +380,13 @@ static void get_orlov_stats(struct super_block *sb, ext4_group_t g, int flex_size, struct orlov_stats *stats) { struct ext4_group_desc *desc; - struct flex_groups *flex_group = EXT4_SB(sb)->s_flex_groups; if (flex_size > 1) { - stats->free_inodes = atomic_read(&flex_group[g].free_inodes); - stats->free_clusters = atomic64_read(&flex_group[g].free_clusters); - stats->used_dirs = atomic_read(&flex_group[g].used_dirs); + struct flex_groups *fg = sbi_array_rcu_deref(EXT4_SB(sb), + s_flex_groups, g); + stats->free_inodes = atomic_read(&fg->free_inodes); + stats->free_clusters = atomic64_read(&fg->free_clusters); + stats->used_dirs = atomic_read(&fg->used_dirs); return; } @@ -670,7 +673,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent, * block has been written back to disk. (Yes, these values are * somewhat arbitrary...) */ -#define RECENTCY_MIN 5 +#define RECENTCY_MIN 60 #define RECENTCY_DIRTY 300 static int recently_deleted(struct super_block *sb, ext4_group_t group, int ino) @@ -1062,7 +1065,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, if (sbi->s_log_groups_per_flex) { ext4_group_t f = ext4_flex_group(sbi, group); - atomic_inc(&sbi->s_flex_groups[f].used_dirs); + atomic_inc(&sbi_array_rcu_deref(sbi, s_flex_groups, + f)->used_dirs); } } if (ext4_has_group_desc_csum(sb)) { @@ -1085,7 +1089,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, if (sbi->s_log_groups_per_flex) { flex_group = ext4_flex_group(sbi, group); - atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes); + atomic_dec(&sbi_array_rcu_deref(sbi, s_flex_groups, + flex_group)->free_inodes); } inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); @@ -1234,7 +1239,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) if (!ext4_test_bit(bit, bitmap_bh->b_data)) goto bad_orphan; - inode = ext4_iget(sb, ino); + inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL); if (IS_ERR(inode)) { err = PTR_ERR(inode); ext4_error(sb, "couldn't read orphan inode %lu (err %d)", diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 48660fbb21a9a6dd14685de67f04efa6eca25582..fe84dd8a74bc0845a92e849a55810208c9db3432 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -408,6 +408,10 @@ static int __check_block_validity(struct inode *inode, const char *func, unsigned int line, struct ext4_map_blocks *map) { + if (ext4_has_feature_journal(inode->i_sb) && + (inode->i_ino == + le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) + return 0; if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk, map->m_len)) { ext4_error_inode(inode, func, line, map->m_pblk, @@ -1230,12 +1234,9 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh) && (block_start < from || block_end > to)) { - decrypt = IS_ENCRYPTED(inode) && - S_ISREG(inode->i_mode) && - !fscrypt_using_hardware_encryption(inode); - ll_rw_block(REQ_OP_READ, (decrypt ? REQ_NOENCRYPT : 0), - 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); *wait_bh++ = bh; + decrypt = fscrypt_inode_uses_fs_layer_crypto(inode); } } /* @@ -2147,7 +2148,7 @@ static int ext4_writepage(struct page *page, bool keep_towrite = false; if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) { - ext4_invalidatepage(page, 0, PAGE_SIZE); + inode->i_mapping->a_ops->invalidatepage(page, 0, PAGE_SIZE); unlock_page(page); return -EIO; } @@ -2593,7 +2594,7 @@ static int mpage_map_and_submit_extent(handle_t *handle, * truncate are avoided by checking i_size under i_data_sem. */ disksize = ((loff_t)mpd->first_page) << PAGE_SHIFT; - if (disksize > EXT4_I(inode)->i_disksize) { + if (disksize > READ_ONCE(EXT4_I(inode)->i_disksize)) { int err2; loff_t i_size; @@ -2763,7 +2764,7 @@ static int ext4_writepages(struct address_space *mapping, if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) return -EIO; - percpu_down_read(&sbi->s_journal_flag_rwsem); + percpu_down_read(&sbi->s_writepages_rwsem); trace_ext4_writepages(inode, wbc); if (dax_mapping(mapping)) { @@ -2993,7 +2994,7 @@ static int ext4_writepages(struct address_space *mapping, out_writepages: trace_ext4_writepages_result(inode, wbc, ret, nr_to_write - wbc->nr_to_write); - percpu_up_read(&sbi->s_journal_flag_rwsem); + percpu_up_read(&sbi->s_writepages_rwsem); return ret; } @@ -3378,7 +3379,8 @@ static int ext4_readpage(struct file *file, struct page *page) ret = ext4_readpage_inline(inode, page); if (ret == -EAGAIN) - return ext4_mpage_readpages(page->mapping, NULL, page, 1); + return ext4_mpage_readpages(page->mapping, NULL, page, 1, + false); return ret; } @@ -3393,7 +3395,7 @@ ext4_readpages(struct file *file, struct address_space *mapping, if (ext4_has_inline_data(inode)) return 0; - return ext4_mpage_readpages(mapping, pages, NULL, nr_pages); + return ext4_mpage_readpages(mapping, pages, NULL, nr_pages, true); } static void ext4_invalidatepage(struct page *page, unsigned int offset, @@ -3739,14 +3741,9 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) get_block_func = ext4_dio_get_block_unwritten_async; dio_flags = DIO_LOCKING; } -#if defined(CONFIG_EXT4_FS_ENCRYPTION) - WARN_ON(IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) - && !fscrypt_using_hardware_encryption(inode)); -#endif - ret = __blockdev_direct_IO(iocb, inode, - inode->i_sb->s_bdev, iter, - get_block_func, - ext4_end_io_dio, NULL, dio_flags); + ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, + get_block_func, ext4_end_io_dio, NULL, + dio_flags); if (ret > 0 && !overwrite && ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN)) { @@ -3858,11 +3855,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#if defined(CONFIG_FS_ENCRYPTION) - if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) - && !fscrypt_using_hardware_encryption(inode)) + if (!fscrypt_dio_supported(iocb, iter)) return 0; -#endif + if (fsverity_active(inode)) return 0; @@ -4023,7 +4018,6 @@ static int __ext4_block_zero_page_range(handle_t *handle, struct inode *inode = mapping->host; struct buffer_head *bh; struct page *page; - bool decrypt; int err = 0; page = find_or_create_page(mapping, from >> PAGE_SHIFT, @@ -4066,15 +4060,12 @@ static int __ext4_block_zero_page_range(handle_t *handle, if (!buffer_uptodate(bh)) { err = -EIO; - decrypt = S_ISREG(inode->i_mode) && - IS_ENCRYPTED(inode) && - !fscrypt_using_hardware_encryption(inode); - ll_rw_block(REQ_OP_READ, (decrypt ? REQ_NOENCRYPT : 0), 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) goto unlock; - if (decrypt) { + if (fscrypt_inode_uses_fs_layer_crypto(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); @@ -4672,7 +4663,7 @@ static int __ext4_get_inode_loc(struct inode *inode, if (end > table) end = table; while (b <= end) - sb_breadahead(sb, b++); + sb_breadahead_unmovable(sb, b++); } /* @@ -4781,7 +4772,9 @@ int ext4_get_projid(struct inode *inode, kprojid_t *projid) return 0; } -struct inode *ext4_iget(struct super_block *sb, unsigned long ino) +struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, + ext4_iget_flags flags, const char *function, + unsigned int line) { struct ext4_iloc iloc; struct ext4_inode *raw_inode; @@ -4795,6 +4788,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) gid_t i_gid; projid_t i_projid; + if ((!(flags & EXT4_IGET_SPECIAL) && + (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)) || + (ino < EXT4_ROOT_INO) || + (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) { + if (flags & EXT4_IGET_HANDLE) + return ERR_PTR(-ESTALE); + __ext4_error(sb, function, line, + "inode #%lu: comm %s: iget: illegal inode #", + ino, current->comm); + return ERR_PTR(-EFSCORRUPTED); + } + inode = iget_locked(sb, ino); if (!inode) return ERR_PTR(-ENOMEM); @@ -4810,18 +4815,26 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) raw_inode = ext4_raw_inode(&iloc); if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) { - EXT4_ERROR_INODE(inode, "root inode unallocated"); + ext4_error_inode(inode, function, line, 0, + "iget: root inode unallocated"); ret = -EFSCORRUPTED; goto bad_inode; } + if ((flags & EXT4_IGET_HANDLE) && + (raw_inode->i_links_count == 0) && (raw_inode->i_mode == 0)) { + ret = -ESTALE; + goto bad_inode; + } + if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > EXT4_INODE_SIZE(inode->i_sb) || (ei->i_extra_isize & 3)) { - EXT4_ERROR_INODE(inode, - "bad extra_isize %u (inode size %u)", + ext4_error_inode(inode, function, line, 0, + "iget: bad extra_isize %u " + "(inode size %u)", ei->i_extra_isize, EXT4_INODE_SIZE(inode->i_sb)); ret = -EFSCORRUPTED; @@ -4843,7 +4856,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) } if (!ext4_inode_csum_verify(inode, raw_inode, ei)) { - EXT4_ERROR_INODE(inode, "checksum invalid"); + ext4_error_inode(inode, function, line, 0, + "iget: checksum invalid"); ret = -EFSBADCRC; goto bad_inode; } @@ -4900,7 +4914,20 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; inode->i_size = ext4_isize(sb, raw_inode); if ((size = i_size_read(inode)) < 0) { - EXT4_ERROR_INODE(inode, "bad i_size value: %lld", size); + ext4_error_inode(inode, function, line, 0, + "iget: bad i_size value: %lld", size); + ret = -EFSCORRUPTED; + goto bad_inode; + } + /* + * If dir_index is not enabled but there's dir with INDEX flag set, + * we'd normally treat htree data as empty space. But with metadata + * checksumming that corrupts checksums so forbid that. + */ + if (!ext4_has_feature_dir_index(sb) && ext4_has_metadata_csum(sb) && + ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) { + EXT4_ERROR_INODE(inode, + "iget: Dir with htree data on filesystem without dir_index feature."); ret = -EFSCORRUPTED; goto bad_inode; } @@ -4974,7 +5001,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) ret = 0; if (ei->i_file_acl && !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) { - EXT4_ERROR_INODE(inode, "bad extended attribute block %llu", + ext4_error_inode(inode, function, line, 0, + "iget: bad extended attribute block %llu", ei->i_file_acl); ret = -EFSCORRUPTED; goto bad_inode; @@ -5029,7 +5057,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) make_bad_inode(inode); } else { ret = -EFSCORRUPTED; - EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode); + ext4_error_inode(inode, function, line, 0, + "iget: bogus i_mode (%o)", inode->i_mode); goto bad_inode; } if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) @@ -5046,19 +5075,12 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) return ERR_PTR(ret); } -struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino) -{ - if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) - return ERR_PTR(-EFSCORRUPTED); - return ext4_iget(sb, ino); -} - static int ext4_inode_blocks_set(handle_t *handle, struct ext4_inode *raw_inode, struct ext4_inode_info *ei) { struct inode *inode = &(ei->vfs_inode); - u64 i_blocks = inode->i_blocks; + u64 i_blocks = READ_ONCE(inode->i_blocks); struct super_block *sb = inode->i_sb; if (i_blocks <= ~0U) { @@ -6130,7 +6152,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) } } - percpu_down_write(&sbi->s_journal_flag_rwsem); + percpu_down_write(&sbi->s_writepages_rwsem); jbd2_journal_lock_updates(journal); /* @@ -6147,7 +6169,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) err = jbd2_journal_flush(journal); if (err < 0) { jbd2_journal_unlock_updates(journal); - percpu_up_write(&sbi->s_journal_flag_rwsem); + percpu_up_write(&sbi->s_writepages_rwsem); ext4_inode_resume_unlocked_dio(inode); return err; } @@ -6156,7 +6178,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) ext4_set_aops(inode); jbd2_journal_unlock_updates(journal); - percpu_up_write(&sbi->s_journal_flag_rwsem); + percpu_up_write(&sbi->s_writepages_rwsem); if (val) up_write(&EXT4_I(inode)->i_mmap_sem); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index f852d90a15629b2dfe061c7ff3978cd667481596..3e5ca2107998a778705ca21cc66c9fc91dc3b368 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -111,7 +111,7 @@ static long swap_inode_boot_loader(struct super_block *sb, if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) return -EPERM; - inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO); + inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL); if (IS_ERR(inode_bl)) return PTR_ERR(inode_bl); ei_bl = EXT4_I(inode_bl); @@ -1100,6 +1100,11 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -EOPNOTSUPP; return fscrypt_ioctl_get_key_status(filp, (void __user *)arg); + case FS_IOC_GET_ENCRYPTION_NONCE: + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; + return fscrypt_ioctl_get_nonce(filp, (void __user *)arg); + case EXT4_IOC_FSGETXATTR: { struct fsxattr fa; @@ -1243,6 +1248,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case FS_IOC_REMOVE_ENCRYPTION_KEY: case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: case FS_IOC_GET_ENCRYPTION_KEY_STATUS: + case FS_IOC_GET_ENCRYPTION_NONCE: case EXT4_IOC_SHUTDOWN: case FS_IOC_GETFSMAP: case FS_IOC_ENABLE_VERITY: diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 3ba9a4ae4eacdd079684386658884e196ca7daad..d7cedfaa1cc08b7ef239b67e268c8634345caebb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1952,7 +1952,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, int free; free = e4b->bd_info->bb_free; - BUG_ON(free <= 0); + if (WARN_ON(free <= 0)) + return; i = e4b->bd_info->bb_first_free; @@ -1973,7 +1974,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, } mb_find_extent(e4b, i, ac->ac_g_ex.fe_len, &ex); - BUG_ON(ex.fe_len <= 0); + if (WARN_ON(ex.fe_len <= 0)) + break; if (free < ex.fe_len) { ext4_grp_locked_error(sb, e4b->bd_group, 0, 0, "%d free clusters as per " @@ -2389,7 +2391,7 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups) { struct ext4_sb_info *sbi = EXT4_SB(sb); unsigned size; - struct ext4_group_info ***new_groupinfo; + struct ext4_group_info ***old_groupinfo, ***new_groupinfo; size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >> EXT4_DESC_PER_BLOCK_BITS(sb); @@ -2402,13 +2404,16 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups) ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group"); return -ENOMEM; } - if (sbi->s_group_info) { - memcpy(new_groupinfo, sbi->s_group_info, + rcu_read_lock(); + old_groupinfo = rcu_dereference(sbi->s_group_info); + if (old_groupinfo) + memcpy(new_groupinfo, old_groupinfo, sbi->s_group_info_size * sizeof(*sbi->s_group_info)); - kvfree(sbi->s_group_info); - } - sbi->s_group_info = new_groupinfo; + rcu_read_unlock(); + rcu_assign_pointer(sbi->s_group_info, new_groupinfo); sbi->s_group_info_size = size / sizeof(*sbi->s_group_info); + if (old_groupinfo) + ext4_kvfree_array_rcu(old_groupinfo); ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", sbi->s_group_info_size); return 0; @@ -2420,6 +2425,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, { int i; int metalen = 0; + int idx = group >> EXT4_DESC_PER_BLOCK_BITS(sb); struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_group_info **meta_group_info; struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); @@ -2438,12 +2444,12 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, "for a buddy group"); goto exit_meta_group_info; } - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = - meta_group_info; + rcu_read_lock(); + rcu_dereference(sbi->s_group_info)[idx] = meta_group_info; + rcu_read_unlock(); } - meta_group_info = - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]; + meta_group_info = sbi_array_rcu_deref(sbi, s_group_info, idx); i = group & (EXT4_DESC_PER_BLOCK(sb) - 1); meta_group_info[i] = kmem_cache_zalloc(cachep, GFP_NOFS); @@ -2491,8 +2497,13 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, exit_group_info: /* If a meta_group_info table has been allocated, release it now */ if (group % EXT4_DESC_PER_BLOCK(sb) == 0) { - kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]); - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = NULL; + struct ext4_group_info ***group_info; + + rcu_read_lock(); + group_info = rcu_dereference(sbi->s_group_info); + kfree(group_info[idx]); + group_info[idx] = NULL; + rcu_read_unlock(); } exit_meta_group_info: return -ENOMEM; @@ -2505,6 +2516,7 @@ static int ext4_mb_init_backend(struct super_block *sb) struct ext4_sb_info *sbi = EXT4_SB(sb); int err; struct ext4_group_desc *desc; + struct ext4_group_info ***group_info; struct kmem_cache *cachep; err = ext4_mb_alloc_groupinfo(sb, ngroups); @@ -2539,11 +2551,16 @@ static int ext4_mb_init_backend(struct super_block *sb) while (i-- > 0) kmem_cache_free(cachep, ext4_get_group_info(sb, i)); i = sbi->s_group_info_size; + rcu_read_lock(); + group_info = rcu_dereference(sbi->s_group_info); while (i-- > 0) - kfree(sbi->s_group_info[i]); + kfree(group_info[i]); + rcu_read_unlock(); iput(sbi->s_buddy_cache); err_freesgi: - kvfree(sbi->s_group_info); + rcu_read_lock(); + kvfree(rcu_dereference(sbi->s_group_info)); + rcu_read_unlock(); return -ENOMEM; } @@ -2733,7 +2750,7 @@ int ext4_mb_release(struct super_block *sb) ext4_group_t ngroups = ext4_get_groups_count(sb); ext4_group_t i; int num_meta_group_infos; - struct ext4_group_info *grinfo; + struct ext4_group_info *grinfo, ***group_info; struct ext4_sb_info *sbi = EXT4_SB(sb); struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); @@ -2751,9 +2768,12 @@ int ext4_mb_release(struct super_block *sb) num_meta_group_infos = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >> EXT4_DESC_PER_BLOCK_BITS(sb); + rcu_read_lock(); + group_info = rcu_dereference(sbi->s_group_info); for (i = 0; i < num_meta_group_infos; i++) - kfree(sbi->s_group_info[i]); - kvfree(sbi->s_group_info); + kfree(group_info[i]); + kvfree(group_info); + rcu_read_unlock(); } kfree(sbi->s_mb_offsets); kfree(sbi->s_mb_maxs); @@ -3052,7 +3072,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ext4_group_t flex_group = ext4_flex_group(sbi, ac->ac_b_ex.fe_group); atomic64_sub(ac->ac_b_ex.fe_len, - &sbi->s_flex_groups[flex_group].free_clusters); + &sbi_array_rcu_deref(sbi, s_flex_groups, + flex_group)->free_clusters); } err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); @@ -4947,7 +4968,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, if (sbi->s_log_groups_per_flex) { ext4_group_t flex_group = ext4_flex_group(sbi, block_group); atomic64_add(count_clusters, - &sbi->s_flex_groups[flex_group].free_clusters); + &sbi_array_rcu_deref(sbi, s_flex_groups, + flex_group)->free_clusters); } if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) @@ -5092,7 +5114,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, if (sbi->s_log_groups_per_flex) { ext4_group_t flex_group = ext4_flex_group(sbi, block_group); atomic64_add(EXT4_NUM_B2C(sbi, blocks_freed), - &sbi->s_flex_groups[flex_group].free_clusters); + &sbi_array_rcu_deref(sbi, s_flex_groups, + flex_group)->free_clusters); } ext4_mb_unload_buddy(&e4b); diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 78d45c7d3fa7382d3374916ddbcee4739504dffa..0d785868cc503e82042294eec95462f673143890 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -434,6 +434,7 @@ static int free_ext_block(handle_t *handle, struct inode *inode) int ext4_ext_migrate(struct inode *inode) { + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); handle_t *handle; int retval = 0, i; __le32 *i_data; @@ -458,6 +459,8 @@ int ext4_ext_migrate(struct inode *inode) */ return retval; + percpu_down_write(&sbi->s_writepages_rwsem); + /* * Worst case we can touch the allocation bitmaps, a bgd * block, and a block to link in the orphan list. We do need @@ -468,7 +471,7 @@ int ext4_ext_migrate(struct inode *inode) if (IS_ERR(handle)) { retval = PTR_ERR(handle); - return retval; + goto out_unlock; } goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; @@ -479,7 +482,7 @@ int ext4_ext_migrate(struct inode *inode) if (IS_ERR(tmp_inode)) { retval = PTR_ERR(tmp_inode); ext4_journal_stop(handle); - return retval; + goto out_unlock; } i_size_write(tmp_inode, i_size_read(inode)); /* @@ -521,7 +524,7 @@ int ext4_ext_migrate(struct inode *inode) */ ext4_orphan_del(NULL, tmp_inode); retval = PTR_ERR(handle); - goto out; + goto out_tmp_inode; } ei = EXT4_I(inode); @@ -602,10 +605,11 @@ int ext4_ext_migrate(struct inode *inode) /* Reset the extent details */ ext4_ext_tree_init(handle, tmp_inode); ext4_journal_stop(handle); -out: +out_tmp_inode: unlock_new_inode(tmp_inode); iput(tmp_inode); - +out_unlock: + percpu_up_write(&sbi->s_writepages_rwsem); return retval; } @@ -615,7 +619,8 @@ int ext4_ext_migrate(struct inode *inode) int ext4_ind_migrate(struct inode *inode) { struct ext4_extent_header *eh; - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_super_block *es = sbi->s_es; struct ext4_inode_info *ei = EXT4_I(inode); struct ext4_extent *ex; unsigned int i, len; @@ -639,9 +644,13 @@ int ext4_ind_migrate(struct inode *inode) if (test_opt(inode->i_sb, DELALLOC)) ext4_alloc_da_blocks(inode); + percpu_down_write(&sbi->s_writepages_rwsem); + handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out_unlock; + } down_write(&EXT4_I(inode)->i_data_sem); ret = ext4_ext_check_inode(inode); @@ -676,5 +685,7 @@ int ext4_ind_migrate(struct inode *inode) errout: ext4_journal_stop(handle); up_write(&EXT4_I(inode)->i_data_sem); +out_unlock: + percpu_up_write(&sbi->s_writepages_rwsem); return ret; } diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c index 38e6a846aac16a463249dddba9d0cd7eb36ccff6..0c042bd43246e43992b35ec4153bcbbdf71253db 100644 --- a/fs/ext4/mmp.c +++ b/fs/ext4/mmp.c @@ -120,10 +120,10 @@ void __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp, { __ext4_warning(sb, function, line, "%s", msg); __ext4_warning(sb, function, line, - "MMP failure info: last update time: %llu, last update " - "node: %s, last update device: %s", - (long long unsigned int) le64_to_cpu(mmp->mmp_time), - mmp->mmp_nodename, mmp->mmp_bdevname); + "MMP failure info: last update time: %llu, last update node: %.*s, last update device: %.*s", + (unsigned long long)le64_to_cpu(mmp->mmp_time), + (int)sizeof(mmp->mmp_nodename), mmp->mmp_nodename, + (int)sizeof(mmp->mmp_bdevname), mmp->mmp_bdevname); } /* @@ -154,6 +154,7 @@ static int kmmpd(void *data) mmp_check_interval = max(EXT4_MMP_CHECK_MULT * mmp_update_interval, EXT4_MMP_MIN_CHECK_INTERVAL); mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval); + BUILD_BUG_ON(sizeof(mmp->mmp_bdevname) < BDEVNAME_SIZE); bdevname(bh->b_bdev, mmp->mmp_bdevname); memcpy(mmp->mmp_nodename, init_utsname()->nodename, @@ -375,7 +376,8 @@ int ext4_multi_mount_protect(struct super_block *sb, /* * Start a kernel thread to update the MMP block periodically. */ - EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, mmpd_data, "kmmpd-%s", + EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, mmpd_data, "kmmpd-%.*s", + (int)sizeof(mmp->mmp_bdevname), bdevname(bh->b_bdev, mmp->mmp_bdevname)); if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) { diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 4935c146bbc7cafc394a4c9f9511ef25fbd0c2ac..ced39d449fd08092bfaf97c85cef401453aef24e 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -603,13 +603,10 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, return -EOPNOTSUPP; } - if (!fscrypt_using_hardware_encryption(orig_inode) || - !fscrypt_using_hardware_encryption(donor_inode)) { - if (IS_ENCRYPTED(orig_inode) || IS_ENCRYPTED(donor_inode)) { - ext4_msg(orig_inode->i_sb, KERN_ERR, - "Online defrag not supported for encrypted files"); - return -EOPNOTSUPP; - } + if (IS_ENCRYPTED(orig_inode) || IS_ENCRYPTED(donor_inode)) { + ext4_msg(orig_inode->i_sb, KERN_ERR, + "Online defrag not supported for encrypted files"); + return -EOPNOTSUPP; } /* Protect orig and donor inodes against a truncate */ diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 42177a426ca901388ef206f506262748fccbc0f5..b134add5a5add673b10b387e69fbed086866521b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1280,8 +1280,8 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) int ext4_ci_compare(const struct inode *parent, const struct qstr *name, const struct qstr *entry, bool quick) { - const struct ext4_sb_info *sbi = EXT4_SB(parent->i_sb); - const struct unicode_map *um = sbi->s_encoding; + const struct super_block *sb = parent->i_sb; + const struct unicode_map *um = sb->s_encoding; int ret; if (quick) @@ -1293,7 +1293,7 @@ int ext4_ci_compare(const struct inode *parent, const struct qstr *name, /* Handle invalid character sequence as either an error * or as an opaque byte sequence. */ - if (ext4_has_strict_mode(sbi)) + if (sb_has_enc_strict_mode(sb)) return -EINVAL; if (name->len != entry->len) @@ -1310,7 +1310,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, { int len; - if (!IS_CASEFOLDED(dir) || !EXT4_SB(dir->i_sb)->s_encoding) { + if (!needs_casefold(dir)) { cf_name->name = NULL; return; } @@ -1319,7 +1319,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, if (!cf_name->name) return; - len = utf8_casefold(EXT4_SB(dir->i_sb)->s_encoding, + len = utf8_casefold(dir->i_sb->s_encoding, iname, cf_name->name, EXT4_NAME_LEN); if (len <= 0) { @@ -1356,7 +1356,7 @@ static inline bool ext4_match(const struct inode *parent, #endif #ifdef CONFIG_UNICODE - if (EXT4_SB(parent->i_sb)->s_encoding && IS_CASEFOLDED(parent)) { + if (needs_casefold(parent)) { if (fname->cf_name.name) { struct qstr cf = {.name = fname->cf_name.name, .len = fname->cf_name.len}; @@ -1505,6 +1505,7 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir, /* * We deal with the read-ahead logic here. */ + cond_resched(); if (ra_ptr >= ra_max) { /* Refill the readahead buffer */ ra_ptr = 0; @@ -1607,6 +1608,7 @@ static struct buffer_head *ext4_lookup_entry(struct inode *dir, struct buffer_head *bh; err = ext4_fname_prepare_lookup(dir, dentry, &fname); + generic_set_encrypted_ci_d_ops(dir, dentry); if (err == -ENOENT) return NULL; if (err) @@ -1696,7 +1698,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi dentry); return ERR_PTR(-EFSCORRUPTED); } - inode = ext4_iget_normal(dir->i_sb, ino); + inode = ext4_iget(dir->i_sb, ino, EXT4_IGET_NORMAL); if (inode == ERR_PTR(-ESTALE)) { EXT4_ERROR_INODE(dir, "deleted inode referenced: %u", @@ -1749,7 +1751,7 @@ struct dentry *ext4_get_parent(struct dentry *child) return ERR_PTR(-EFSCORRUPTED); } - return d_obtain_alias(ext4_iget_normal(child->d_sb, ino)); + return d_obtain_alias(ext4_iget(child->d_sb, ino, EXT4_IGET_NORMAL)); } /* @@ -2172,7 +2174,6 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, struct ext4_dir_entry_2 *de; struct ext4_dir_entry_tail *t; struct super_block *sb; - struct ext4_sb_info *sbi; struct ext4_filename fname; int retval; int dx_fallback=0; @@ -2184,14 +2185,13 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, csum_size = sizeof(struct ext4_dir_entry_tail); sb = dir->i_sb; - sbi = EXT4_SB(sb); blocksize = sb->s_blocksize; if (!dentry->d_name.len) return -EINVAL; #ifdef CONFIG_UNICODE - if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) && - sbi->s_encoding && utf8_validate(sbi->s_encoding, &dentry->d_name)) + if (sb_has_enc_strict_mode(sb) && IS_CASEFOLDED(dir) && + sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name)) return -EINVAL; #endif @@ -2213,6 +2213,13 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, retval = ext4_dx_add_entry(handle, &fname, dir, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) goto out; + /* Can we just ignore htree data? */ + if (ext4_has_metadata_csum(sb)) { + EXT4_ERROR_INODE(dir, + "Directory has corrupted htree index."); + retval = -EFSCORRUPTED; + goto out; + } ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); dx_fallback++; ext4_mark_inode_dirty(handle, dir); diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 12b57973c5cfc1621e93685f54c09111c3d86c03..6481742d666d1a8eaa65b562f82339c36f534599 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -344,8 +344,6 @@ void ext4_io_submit(struct ext4_io_submit *io) int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ? REQ_SYNC : 0; io->io_bio->bi_write_hint = io->io_end->inode->i_write_hint; - if (io->io_flags & EXT4_IO_ENCRYPTED) - io_op_flags |= REQ_NOENCRYPT; bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags); submit_bio(io->io_bio); } @@ -355,7 +353,6 @@ void ext4_io_submit(struct ext4_io_submit *io) void ext4_io_submit_init(struct ext4_io_submit *io, struct writeback_control *wbc) { - io->io_flags = 0; io->io_wbc = wbc; io->io_bio = NULL; io->io_end = NULL; @@ -369,6 +366,7 @@ static int io_submit_init_bio(struct ext4_io_submit *io, bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES); if (!bio) return -ENOMEM; + fscrypt_set_bio_crypt_ctx_bh(bio, bh, GFP_NOIO); wbc_init_bio(io->io_wbc, bio); bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio_set_dev(bio, bh->b_bdev); @@ -386,7 +384,8 @@ static int io_submit_add_bh(struct ext4_io_submit *io, { int ret; - if (io->io_bio && bh->b_blocknr != io->io_next_block) { + if (io->io_bio && (bh->b_blocknr != io->io_next_block || + !fscrypt_mergeable_bio_bh(io->io_bio, bh))) { submit_and_retry: ext4_io_submit(io); } @@ -472,28 +471,33 @@ int ext4_bio_write_page(struct ext4_io_submit *io, bh = head = page_buffers(page); - if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) && nr_to_submit) { + if (fscrypt_inode_uses_fs_layer_crypto(inode) && nr_to_submit) { gfp_t gfp_flags = GFP_NOFS; + /* + * Since bounce page allocation uses a mempool, we can only use + * a waiting mask (i.e. request guaranteed allocation) on the + * first page of the bio. Otherwise it can deadlock. + */ + if (io->io_bio) + gfp_flags = GFP_NOWAIT | __GFP_NOWARN; retry_encrypt: - if (!fscrypt_using_hardware_encryption(inode)) { - bounce_page = fscrypt_encrypt_pagecache_blocks(page, - PAGE_SIZE, 0, gfp_flags); - if (IS_ERR(bounce_page)) { - ret = PTR_ERR(bounce_page); - if (ret == -ENOMEM && wbc->sync_mode == - WB_SYNC_ALL) { - if (io->io_bio) { - ext4_io_submit(io); - congestion_wait(BLK_RW_ASYNC, - HZ/50); - } + bounce_page = fscrypt_encrypt_pagecache_blocks(page, + PAGE_SIZE, 0, gfp_flags); + if (IS_ERR(bounce_page)) { + ret = PTR_ERR(bounce_page); + if (ret == -ENOMEM && (io->io_bio || + wbc->sync_mode == WB_SYNC_ALL)) { + gfp_flags = GFP_NOFS; + if (io->io_bio) + ext4_io_submit(io); + else gfp_flags |= __GFP_NOFAIL; - goto retry_encrypt; - } - bounce_page = NULL; - goto out; + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry_encrypt; } + bounce_page = NULL; + goto out; } } @@ -501,8 +505,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io, do { if (!buffer_async_write(bh)) continue; - if (bounce_page) - io->io_flags |= EXT4_IO_ENCRYPTED; ret = io_submit_add_bh(io, inode, bounce_page ?: page, bh); if (ret) { /* diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index a98156dca3df3b8c42e2d6e898f0d0e2d3126f91..e4f684a71002640714b8e10d36e5530bd2a4f340 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -198,7 +198,7 @@ static struct bio_post_read_ctx *get_bio_post_read_ctx(struct inode *inode, unsigned int post_read_steps = 0; struct bio_post_read_ctx *ctx = NULL; - if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) + if (fscrypt_inode_uses_fs_layer_crypto(inode)) post_read_steps |= 1 << STEP_DECRYPT; if (ext4_need_verity(inode, first_idx)) @@ -250,7 +250,7 @@ ext4_submit_bio_read(struct bio *bio) int ext4_mpage_readpages(struct address_space *mapping, struct list_head *pages, struct page *page, - unsigned nr_pages) + unsigned nr_pages, bool is_readahead) { struct bio *bio = NULL; sector_t last_block_in_bio = 0; @@ -259,6 +259,7 @@ int ext4_mpage_readpages(struct address_space *mapping, const unsigned blkbits = inode->i_blkbits; const unsigned blocks_per_page = PAGE_SIZE >> blkbits; const unsigned blocksize = 1 << blkbits; + sector_t next_block; sector_t block_in_file; sector_t last_block; sector_t last_block_in_file; @@ -290,7 +291,8 @@ int ext4_mpage_readpages(struct address_space *mapping, if (page_has_buffers(page)) goto confused; - block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); + block_in_file = next_block = + (sector_t)page->index << (PAGE_SHIFT - blkbits); last_block = block_in_file + nr_pages * blocks_per_page; last_block_in_file = (ext4_readpage_limit(inode) + blocksize - 1) >> blkbits; @@ -390,7 +392,8 @@ int ext4_mpage_readpages(struct address_space *mapping, * This page will go to BIO. Do we need to send this * BIO off first? */ - if (bio && (last_block_in_bio != blocks[0] - 1)) { + if (bio && (last_block_in_bio != blocks[0] - 1 || + !fscrypt_mergeable_bio(bio, inode, next_block))) { submit_and_realloc: ext4_submit_bio_read(bio); bio = NULL; @@ -402,6 +405,8 @@ int ext4_mpage_readpages(struct address_space *mapping, min_t(int, nr_pages, BIO_MAX_PAGES)); if (!bio) goto set_error_page; + fscrypt_set_bio_crypt_ctx(bio, inode, next_block, + GFP_KERNEL); ctx = get_bio_post_read_ctx(inode, bio, page->index); if (IS_ERR(ctx)) { bio_put(bio); @@ -412,8 +417,7 @@ int ext4_mpage_readpages(struct address_space *mapping, bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9); bio->bi_end_io = mpage_end_io; bio->bi_private = ctx; - bio_set_op_attrs(bio, REQ_OP_READ, - ctx ? REQ_NOENCRYPT : 0); + bio_set_op_attrs(bio, REQ_OP_READ, 0); } length = first_hole << blkbits; diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 4f7cd78d0364730d268a608f47142c039976ecfd..19af346a66514d51ff05d9d1659d4bf700fb02db 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -17,6 +17,33 @@ #include "ext4_jbd2.h" +struct ext4_rcu_ptr { + struct rcu_head rcu; + void *ptr; +}; + +static void ext4_rcu_ptr_callback(struct rcu_head *head) +{ + struct ext4_rcu_ptr *ptr; + + ptr = container_of(head, struct ext4_rcu_ptr, rcu); + kvfree(ptr->ptr); + kfree(ptr); +} + +void ext4_kvfree_array_rcu(void *to_free) +{ + struct ext4_rcu_ptr *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + + if (ptr) { + ptr->ptr = to_free; + call_rcu(&ptr->rcu, ext4_rcu_ptr_callback); + return; + } + synchronize_rcu(); + kvfree(to_free); +} + int ext4_resize_begin(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -545,8 +572,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb, brelse(gdb); goto out; } - memcpy(gdb->b_data, sbi->s_group_desc[j]->b_data, - gdb->b_size); + memcpy(gdb->b_data, sbi_array_rcu_deref(sbi, + s_group_desc, j)->b_data, gdb->b_size); set_buffer_uptodate(gdb); err = ext4_handle_dirty_metadata(handle, NULL, gdb); @@ -854,13 +881,15 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, } brelse(dind); - o_group_desc = EXT4_SB(sb)->s_group_desc; + rcu_read_lock(); + o_group_desc = rcu_dereference(EXT4_SB(sb)->s_group_desc); memcpy(n_group_desc, o_group_desc, EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); + rcu_read_unlock(); n_group_desc[gdb_num] = gdb_bh; - EXT4_SB(sb)->s_group_desc = n_group_desc; + rcu_assign_pointer(EXT4_SB(sb)->s_group_desc, n_group_desc); EXT4_SB(sb)->s_gdb_count++; - kvfree(o_group_desc); + ext4_kvfree_array_rcu(o_group_desc); le16_add_cpu(&es->s_reserved_gdt_blocks, -1); err = ext4_handle_dirty_super(handle, sb); @@ -904,9 +933,11 @@ static int add_new_gdb_meta_bg(struct super_block *sb, return err; } - o_group_desc = EXT4_SB(sb)->s_group_desc; + rcu_read_lock(); + o_group_desc = rcu_dereference(EXT4_SB(sb)->s_group_desc); memcpy(n_group_desc, o_group_desc, EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); + rcu_read_unlock(); n_group_desc[gdb_num] = gdb_bh; BUFFER_TRACE(gdb_bh, "get_write_access"); @@ -917,9 +948,9 @@ static int add_new_gdb_meta_bg(struct super_block *sb, return err; } - EXT4_SB(sb)->s_group_desc = n_group_desc; + rcu_assign_pointer(EXT4_SB(sb)->s_group_desc, n_group_desc); EXT4_SB(sb)->s_gdb_count++; - kvfree(o_group_desc); + ext4_kvfree_array_rcu(o_group_desc); return err; } @@ -1183,7 +1214,8 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, * use non-sparse filesystems anymore. This is already checked above. */ if (gdb_off) { - gdb_bh = sbi->s_group_desc[gdb_num]; + gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, + gdb_num); BUFFER_TRACE(gdb_bh, "get_write_access"); err = ext4_journal_get_write_access(handle, gdb_bh); @@ -1265,7 +1297,7 @@ static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb, /* * get_write_access() has been called on gdb_bh by ext4_add_new_desc(). */ - gdb_bh = sbi->s_group_desc[gdb_num]; + gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, gdb_num); /* Update group descriptor block for new group */ gdp = (struct ext4_group_desc *)(gdb_bh->b_data + gdb_off * EXT4_DESC_SIZE(sb)); @@ -1393,11 +1425,14 @@ static void ext4_update_super(struct super_block *sb, percpu_counter_read(&sbi->s_freeclusters_counter)); if (ext4_has_feature_flex_bg(sb) && sbi->s_log_groups_per_flex) { ext4_group_t flex_group; + struct flex_groups *fg; + flex_group = ext4_flex_group(sbi, group_data[0].group); + fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group); atomic64_add(EXT4_NUM_B2C(sbi, free_blocks), - &sbi->s_flex_groups[flex_group].free_clusters); + &fg->free_clusters); atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count, - &sbi->s_flex_groups[flex_group].free_inodes); + &fg->free_inodes); } /* @@ -1492,7 +1527,8 @@ static int ext4_flex_group_add(struct super_block *sb, for (; gdb_num <= gdb_num_end; gdb_num++) { struct buffer_head *gdb_bh; - gdb_bh = sbi->s_group_desc[gdb_num]; + gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, + gdb_num); if (old_gdb == gdb_bh->b_blocknr) continue; update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, @@ -1616,7 +1652,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) "No reserved GDT blocks, can't resize"); return -EPERM; } - inode = ext4_iget(sb, EXT4_RESIZE_INO); + inode = ext4_iget(sb, EXT4_RESIZE_INO, EXT4_IGET_SPECIAL); if (IS_ERR(inode)) { ext4_warning(sb, "Error opening resize inode"); return PTR_ERR(inode); @@ -1944,7 +1980,8 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) } if (!resize_inode) - resize_inode = ext4_iget(sb, EXT4_RESIZE_INO); + resize_inode = ext4_iget(sb, EXT4_RESIZE_INO, + EXT4_IGET_SPECIAL); if (IS_ERR(resize_inode)) { ext4_warning(sb, "Error opening resize inode"); return PTR_ERR(resize_inode); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e889ae6bd23953383291095856df347850103a32..8731f693513699a556f1cf4c6b3d1b13e7311bd7 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -371,7 +371,8 @@ static void save_error_info(struct super_block *sb, const char *func, unsigned int line) { __save_error_info(sb, func, line); - ext4_commit_super(sb, 1); + if (!bdev_read_only(sb->s_bdev)) + ext4_commit_super(sb, 1); } /* @@ -902,6 +903,8 @@ static void ext4_put_super(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; + struct buffer_head **group_desc; + struct flex_groups **flex_groups; int aborted = 0; int i, err; @@ -933,15 +936,23 @@ static void ext4_put_super(struct super_block *sb) if (!sb_rdonly(sb)) ext4_commit_super(sb, 1); + rcu_read_lock(); + group_desc = rcu_dereference(sbi->s_group_desc); for (i = 0; i < sbi->s_gdb_count; i++) - brelse(sbi->s_group_desc[i]); - kvfree(sbi->s_group_desc); - kvfree(sbi->s_flex_groups); + brelse(group_desc[i]); + kvfree(group_desc); + flex_groups = rcu_dereference(sbi->s_flex_groups); + if (flex_groups) { + for (i = 0; i < sbi->s_flex_groups_allocated; i++) + kvfree(flex_groups[i]); + kvfree(flex_groups); + } + rcu_read_unlock(); percpu_counter_destroy(&sbi->s_freeclusters_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_dirs_counter); percpu_counter_destroy(&sbi->s_dirtyclusters_counter); - percpu_free_rwsem(&sbi->s_journal_flag_rwsem); + percpu_free_rwsem(&sbi->s_writepages_rwsem); #ifdef CONFIG_QUOTA for (i = 0; i < EXT4_MAXQUOTAS; i++) kfree(get_qf_name(sb, sbi, i)); @@ -990,7 +1001,7 @@ static void ext4_put_super(struct super_block *sb) kfree(sbi->s_blockgroup_lock); fs_put_dax(sbi->s_daxdev); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif kfree(sbi); } @@ -1125,20 +1136,11 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb, { struct inode *inode; - if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) - return ERR_PTR(-ESTALE); - if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) - return ERR_PTR(-ESTALE); - - /* iget isn't really right if the inode is currently unallocated!! - * - * ext4_read_inode will return a bad_inode if the inode had been - * deleted, so we should be safe. - * + /* * Currently we don't know the generation for parent directory, so * a generation of 0 means "accept any" */ - inode = ext4_iget_normal(sb, ino); + inode = ext4_iget(sb, ino, EXT4_IGET_HANDLE); if (IS_ERR(inode)) return ERR_CAST(inode); if (generation && inode->i_generation != generation) { @@ -1298,6 +1300,11 @@ static void ext4_get_ino_and_lblk_bits(struct super_block *sb, *lblk_bits_ret = 8 * sizeof(ext4_lblk_t); } +static bool ext4_inline_crypt_enabled(struct super_block *sb) +{ + return test_opt(sb, INLINECRYPT); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1307,6 +1314,7 @@ static const struct fscrypt_operations ext4_cryptops = { .max_namelen = EXT4_NAME_LEN, .has_stable_inodes = ext4_has_stable_inodes, .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, + .inline_crypt_enabled = ext4_inline_crypt_enabled, }; #endif @@ -1402,6 +1410,7 @@ enum { Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption, + Opt_inlinecrypt, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, @@ -1495,6 +1504,7 @@ static const match_table_t tokens = { {Opt_noinit_itable, "noinit_itable"}, {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_test_dummy_encryption, "test_dummy_encryption"}, + {Opt_inlinecrypt, "inlinecrypt"}, {Opt_nombcache, "nombcache"}, {Opt_nombcache, "no_mbcache"}, /* for backward compatibility */ {Opt_removed, "check=none"}, /* mount option from ext2/3 */ @@ -1704,6 +1714,11 @@ static const struct mount_opts { {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, {Opt_max_dir_size_kb, 0, MOPT_GTE0}, {Opt_test_dummy_encryption, 0, MOPT_GTE0}, +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT + {Opt_inlinecrypt, EXT4_MOUNT_INLINECRYPT, MOPT_SET}, +#else + {Opt_inlinecrypt, EXT4_MOUNT_INLINECRYPT, MOPT_NOSUPPORT}, +#endif {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET}, {Opt_err, 0, 0} }; @@ -2275,8 +2290,8 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup) { struct ext4_sb_info *sbi = EXT4_SB(sb); - struct flex_groups *new_groups; - int size; + struct flex_groups **old_groups, **new_groups; + int size, i, j; if (!sbi->s_log_groups_per_flex) return 0; @@ -2285,22 +2300,37 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup) if (size <= sbi->s_flex_groups_allocated) return 0; - size = roundup_pow_of_two(size * sizeof(struct flex_groups)); - new_groups = kvzalloc(size, GFP_KERNEL); + new_groups = kvzalloc(roundup_pow_of_two(size * + sizeof(*sbi->s_flex_groups)), GFP_KERNEL); if (!new_groups) { - ext4_msg(sb, KERN_ERR, "not enough memory for %d flex groups", - size / (int) sizeof(struct flex_groups)); + ext4_msg(sb, KERN_ERR, + "not enough memory for %d flex group pointers", size); return -ENOMEM; } - - if (sbi->s_flex_groups) { - memcpy(new_groups, sbi->s_flex_groups, - (sbi->s_flex_groups_allocated * - sizeof(struct flex_groups))); - kvfree(sbi->s_flex_groups); + for (i = sbi->s_flex_groups_allocated; i < size; i++) { + new_groups[i] = kvzalloc(roundup_pow_of_two( + sizeof(struct flex_groups)), + GFP_KERNEL); + if (!new_groups[i]) { + for (j = sbi->s_flex_groups_allocated; j < i; j++) + kvfree(new_groups[j]); + kvfree(new_groups); + ext4_msg(sb, KERN_ERR, + "not enough memory for %d flex groups", size); + return -ENOMEM; + } } - sbi->s_flex_groups = new_groups; - sbi->s_flex_groups_allocated = size / sizeof(struct flex_groups); + rcu_read_lock(); + old_groups = rcu_dereference(sbi->s_flex_groups); + if (old_groups) + memcpy(new_groups, old_groups, + (sbi->s_flex_groups_allocated * + sizeof(struct flex_groups *))); + rcu_read_unlock(); + rcu_assign_pointer(sbi->s_flex_groups, new_groups); + sbi->s_flex_groups_allocated = size; + if (old_groups) + ext4_kvfree_array_rcu(old_groups); return 0; } @@ -2308,6 +2338,7 @@ static int ext4_fill_flex_info(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_group_desc *gdp = NULL; + struct flex_groups *fg; ext4_group_t flex_group; int i, err; @@ -2325,12 +2356,11 @@ static int ext4_fill_flex_info(struct super_block *sb) gdp = ext4_get_group_desc(sb, i, NULL); flex_group = ext4_flex_group(sbi, i); - atomic_add(ext4_free_inodes_count(sb, gdp), - &sbi->s_flex_groups[flex_group].free_inodes); + fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group); + atomic_add(ext4_free_inodes_count(sb, gdp), &fg->free_inodes); atomic64_add(ext4_free_group_clusters(sb, gdp), - &sbi->s_flex_groups[flex_group].free_clusters); - atomic_add(ext4_used_dirs_count(sb, gdp), - &sbi->s_flex_groups[flex_group].used_dirs); + &fg->free_clusters); + atomic_add(ext4_used_dirs_count(sb, gdp), &fg->used_dirs); } return 1; @@ -2920,17 +2950,11 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly) return 0; } -#ifndef CONFIG_QUOTA - if (ext4_has_feature_quota(sb) && !readonly) { +#if !IS_ENABLED(CONFIG_QUOTA) || !IS_ENABLED(CONFIG_QFMT_V2) + if (!readonly && (ext4_has_feature_quota(sb) || + ext4_has_feature_project(sb))) { ext4_msg(sb, KERN_ERR, - "Filesystem with quota feature cannot be mounted RDWR " - "without CONFIG_QUOTA"); - return 0; - } - if (ext4_has_feature_project(sb) && !readonly) { - ext4_msg(sb, KERN_ERR, - "Filesystem with project quota feature cannot be mounted RDWR " - "without CONFIG_QUOTA"); + "The kernel was not built with CONFIG_QUOTA and CONFIG_QFMT_V2"); return 0; } #endif /* CONFIG_QUOTA */ @@ -3502,7 +3526,8 @@ int ext4_calculate_overhead(struct super_block *sb) */ if (sbi->s_journal && !sbi->journal_bdev) overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_maxlen); - else if (ext4_has_feature_journal(sb) && !sbi->s_journal) { + else if (ext4_has_feature_journal(sb) && !sbi->s_journal && j_inum) { + /* j_inum for internal journal is non-zero */ j_inode = ext4_get_journal_inode(sb, j_inum); if (j_inode) { j_blocks = j_inode->i_size >> sb->s_blocksize_bits; @@ -3552,9 +3577,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) { struct dax_device *dax_dev = fs_dax_get_by_bdev(sb->s_bdev); char *orig_data = kstrdup(data, GFP_KERNEL); - struct buffer_head *bh; + struct buffer_head *bh, **group_desc; struct ext4_super_block *es = NULL; struct ext4_sb_info *sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); + struct flex_groups **flex_groups; ext4_fsblk_t block; ext4_fsblk_t sb_block = get_sb_block(&data); ext4_fsblk_t logical_sb_block; @@ -3725,6 +3751,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) */ sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; + blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); + if (blocksize < EXT4_MIN_BLOCK_SIZE || + blocksize > EXT4_MAX_BLOCK_SIZE) { + ext4_msg(sb, KERN_ERR, + "Unsupported filesystem blocksize %d (%d log_block_size)", + blocksize, le32_to_cpu(es->s_log_block_size)); + goto failed_mount; + } + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; @@ -3742,6 +3777,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_msg(sb, KERN_ERR, "unsupported inode size: %d", sbi->s_inode_size); + ext4_msg(sb, KERN_ERR, "blocksize: %d", blocksize); goto failed_mount; } /* @@ -3804,7 +3840,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; #ifdef CONFIG_UNICODE - if (ext4_has_feature_casefold(sb) && !sbi->s_encoding) { + if (ext4_has_feature_casefold(sb) && !sb->s_encoding) { const struct ext4_sb_encodings *encoding_info; struct unicode_map *encoding; __u16 encoding_flags; @@ -3835,8 +3871,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) "%s-%s with flags 0x%hx", encoding_info->name, encoding_info->version?:"\b", encoding_flags); - sbi->s_encoding = encoding; - sbi->s_encoding_flags = encoding_flags; + sb->s_encoding = encoding; + sb->s_encoding_flags = encoding_flags; } #endif @@ -3942,14 +3978,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (!ext4_feature_set_ok(sb, (sb_rdonly(sb)))) goto failed_mount; - blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); - if (blocksize < EXT4_MIN_BLOCK_SIZE || - blocksize > EXT4_MAX_BLOCK_SIZE) { - ext4_msg(sb, KERN_ERR, - "Unsupported filesystem blocksize %d (%d log_block_size)", - blocksize, le32_to_cpu(es->s_log_block_size)); - goto failed_mount; - } if (le32_to_cpu(es->s_log_block_size) > (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { ext4_msg(sb, KERN_ERR, @@ -4041,7 +4069,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (sbi->s_inodes_per_group < sbi->s_inodes_per_block || sbi->s_inodes_per_group > blocksize * 8) { ext4_msg(sb, KERN_ERR, "invalid inodes per group: %lu\n", - sbi->s_blocks_per_group); + sbi->s_inodes_per_group); goto failed_mount; } sbi->s_itb_per_group = sbi->s_inodes_per_group / @@ -4172,9 +4200,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) EXT4_BLOCKS_PER_GROUP(sb) - 1); do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) { - ext4_msg(sb, KERN_WARNING, "groups count too large: %u " + ext4_msg(sb, KERN_WARNING, "groups count too large: %llu " "(block count %llu, first data block %u, " - "blocks per group %lu)", sbi->s_groups_count, + "blocks per group %lu)", blocks_count, ext4_blocks_count(es), le32_to_cpu(es->s_first_data_block), EXT4_BLOCKS_PER_GROUP(sb)); @@ -4202,9 +4230,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; } } - sbi->s_group_desc = kvmalloc(db_count * + rcu_assign_pointer(sbi->s_group_desc, + kvmalloc_array(db_count, sizeof(struct buffer_head *), - GFP_KERNEL); + GFP_KERNEL)); if (sbi->s_group_desc == NULL) { ext4_msg(sb, KERN_ERR, "not enough memory"); ret = -ENOMEM; @@ -4216,18 +4245,23 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) /* Pre-read the descriptors into the buffer cache */ for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logical_sb_block, i); - sb_breadahead(sb, block); + sb_breadahead_unmovable(sb, block); } for (i = 0; i < db_count; i++) { + struct buffer_head *bh; + block = descriptor_loc(sb, logical_sb_block, i); - sbi->s_group_desc[i] = sb_bread_unmovable(sb, block); - if (!sbi->s_group_desc[i]) { + bh = sb_bread_unmovable(sb, block); + if (!bh) { ext4_msg(sb, KERN_ERR, "can't read group descriptor %d", i); db_count = i; goto failed_mount2; } + rcu_read_lock(); + rcu_dereference(sbi->s_group_desc)[i] = bh; + rcu_read_unlock(); } sbi->s_gdb_count = db_count; if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { @@ -4445,7 +4479,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) * so we can safely mount the rest of the filesystem now. */ - root = ext4_iget(sb, EXT4_ROOT_INO); + root = ext4_iget(sb, EXT4_ROOT_INO, EXT4_IGET_SPECIAL); if (IS_ERR(root)) { ext4_msg(sb, KERN_ERR, "get root inode failed"); ret = PTR_ERR(root); @@ -4458,11 +4492,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount4; } -#ifdef CONFIG_UNICODE - if (sbi->s_encoding) - sb->s_d_op = &ext4_dentry_ops; -#endif - sb->s_root = d_make_root(root); if (!sb->s_root) { ext4_msg(sb, KERN_ERR, "get root dentry failed"); @@ -4510,7 +4539,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0, GFP_KERNEL); if (!err) - err = percpu_init_rwsem(&sbi->s_journal_flag_rwsem); + err = percpu_init_rwsem(&sbi->s_writepages_rwsem); if (err) { ext4_msg(sb, KERN_ERR, "insufficient memory"); @@ -4598,13 +4627,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_unregister_li_request(sb); failed_mount6: ext4_mb_release(sb); - if (sbi->s_flex_groups) - kvfree(sbi->s_flex_groups); + rcu_read_lock(); + flex_groups = rcu_dereference(sbi->s_flex_groups); + if (flex_groups) { + for (i = 0; i < sbi->s_flex_groups_allocated; i++) + kvfree(flex_groups[i]); + kvfree(flex_groups); + } + rcu_read_unlock(); percpu_counter_destroy(&sbi->s_freeclusters_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_dirs_counter); percpu_counter_destroy(&sbi->s_dirtyclusters_counter); - percpu_free_rwsem(&sbi->s_journal_flag_rwsem); + percpu_free_rwsem(&sbi->s_writepages_rwsem); failed_mount5: ext4_ext_release(sb); ext4_release_system_zone(sb); @@ -4635,15 +4670,18 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (sbi->s_mmp_tsk) kthread_stop(sbi->s_mmp_tsk); failed_mount2: + rcu_read_lock(); + group_desc = rcu_dereference(sbi->s_group_desc); for (i = 0; i < db_count; i++) - brelse(sbi->s_group_desc[i]); - kvfree(sbi->s_group_desc); + brelse(group_desc[i]); + kvfree(group_desc); + rcu_read_unlock(); failed_mount: if (sbi->s_chksum_driver) crypto_free_shash(sbi->s_chksum_driver); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif #ifdef CONFIG_QUOTA @@ -4697,7 +4735,7 @@ static struct inode *ext4_get_journal_inode(struct super_block *sb, * happen if we iget() an unused inode, as the subsequent iput() * will try to delete it. */ - journal_inode = ext4_iget(sb, journal_inum); + journal_inode = ext4_iget(sb, journal_inum, EXT4_IGET_SPECIAL); if (IS_ERR(journal_inode)) { ext4_msg(sb, KERN_ERR, "no journal found"); return NULL; @@ -5789,7 +5827,7 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id, if (!qf_inums[type]) return -EPERM; - qf_inode = ext4_iget(sb, qf_inums[type]); + qf_inode = ext4_iget(sb, qf_inums[type], EXT4_IGET_SPECIAL); if (IS_ERR(qf_inode)) { ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]); return PTR_ERR(qf_inode); diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c index d0d8a9795dd627c517acca997d083b002ff3a1e0..bd717248a4bcbea8d1ef2b9fd58971dc14db4afa 100644 --- a/fs/ext4/verity.c +++ b/fs/ext4/verity.c @@ -342,12 +342,57 @@ static int ext4_get_verity_descriptor(struct inode *inode, void *buf, return desc_size; } +/* + * Prefetch some pages from the file's Merkle tree. + * + * This is basically a stripped-down version of __do_page_cache_readahead() + * which works on pages past i_size. + */ +static void ext4_merkle_tree_readahead(struct address_space *mapping, + pgoff_t start_index, unsigned long count) +{ + LIST_HEAD(pages); + unsigned int nr_pages = 0; + struct page *page; + pgoff_t index; + struct blk_plug plug; + + for (index = start_index; index < start_index + count; index++) { + rcu_read_lock(); + page = radix_tree_lookup(&mapping->page_tree, index); + rcu_read_unlock(); + if (!page || radix_tree_exceptional_entry(page)) { + page = __page_cache_alloc(readahead_gfp_mask(mapping)); + if (!page) + break; + page->index = index; + list_add(&page->lru, &pages); + nr_pages++; + } + } + blk_start_plug(&plug); + ext4_mpage_readpages(mapping, &pages, NULL, nr_pages, true); + blk_finish_plug(&plug); +} + static struct page *ext4_read_merkle_tree_page(struct inode *inode, - pgoff_t index) + pgoff_t index, + unsigned long num_ra_pages) { + struct page *page; + index += ext4_verity_metadata_pos(inode) >> PAGE_SHIFT; - return read_mapping_page(inode->i_mapping, index, NULL); + page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED); + if (!page || !PageUptodate(page)) { + if (page) + put_page(page); + else if (num_ra_pages > 1) + ext4_merkle_tree_readahead(inode->i_mapping, index, + num_ra_pages); + page = read_mapping_page(inode->i_mapping, index, NULL); + } + return page; } static int ext4_write_merkle_tree_block(struct inode *inode, const void *buf, diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index f2fde3ac8698943fddeaf7a4c7b75eede099346f..b0873b89dc879ff695c3dd93ca4d22a2404029f7 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -383,7 +383,7 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, struct inode *inode; int err; - inode = ext4_iget(parent->i_sb, ea_ino); + inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_NORMAL); if (IS_ERR(inode)) { err = PTR_ERR(inode); ext4_error(parent->i_sb, @@ -1486,7 +1486,8 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value, } while (ce) { - ea_inode = ext4_iget(inode->i_sb, ce->e_value); + ea_inode = ext4_iget(inode->i_sb, ce->e_value, + EXT4_IGET_NORMAL); if (!IS_ERR(ea_inode) && !is_bad_inode(ea_inode) && (EXT4_I(ea_inode)->i_flags & EXT4_EA_INODE_FL) && diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index d4519801745e562459ffc5ad215180f17b794e6e..1940a6574b66e82543771934adb0749ab0438f05 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -5,6 +5,7 @@ config F2FS_FS select CRYPTO select CRYPTO_CRC32 select F2FS_FS_XATTR if FS_ENCRYPTION + select FS_ENCRYPTION_ALGS if FS_ENCRYPTION help F2FS is based on Log-structured File System (LFS), which supports versatile "flash-friendly" features. The design has been focused on @@ -20,7 +21,7 @@ config F2FS_FS config F2FS_STAT_FS bool "F2FS Status Information" - depends on F2FS_FS && DEBUG_FS + depends on F2FS_FS default y help /sys/kernel/debug/f2fs/ contains information about all the partitions @@ -104,3 +105,37 @@ config F2FS_FAULT_INJECTION Test F2FS to inject faults such as ENOMEM, ENOSPC, and so on. If unsure, say N. + +config F2FS_FS_COMPRESSION + bool "F2FS compression feature" + depends on F2FS_FS + help + Enable filesystem-level compression on f2fs regular files, + multiple back-end compression algorithms are supported. + +config F2FS_FS_LZO + bool "LZO compression support" + depends on F2FS_FS_COMPRESSION + select LZO_COMPRESS + select LZO_DECOMPRESS + default y + help + Support LZO compress algorithm, if unsure, say Y. + +config F2FS_FS_LZ4 + bool "LZ4 compression support" + depends on F2FS_FS_COMPRESSION + select LZ4_COMPRESS + select LZ4_DECOMPRESS + default y + help + Support LZ4 compress algorithm, if unsure, say Y. + +config F2FS_FS_ZSTD + bool "ZSTD compression support" + depends on F2FS_FS_COMPRESSION + select ZSTD_COMPRESS + select ZSTD_DECOMPRESS + default y + help + Support ZSTD compress algorithm, if unsure, say Y. diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile index 2aaecc63834fc857891d60f6d3ee94ece1da4983..ee7316b42f69d9cefa0b9141a7a6496c6f839c83 100644 --- a/fs/f2fs/Makefile +++ b/fs/f2fs/Makefile @@ -9,3 +9,4 @@ f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o f2fs-$(CONFIG_FS_VERITY) += verity.o +f2fs-$(CONFIG_F2FS_FS_COMPRESSION) += compress.o diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 3299ee97f220858239c7d1c581e85adb22bb4294..1b0d57b0d00cfb68d4d5784ed2a0090d9ff11cc0 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -50,9 +50,6 @@ struct page *f2fs_grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) return page; } -/* - * We guarantee no failure on the returned page. - */ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, bool is_meta) { @@ -89,6 +86,8 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, return ERR_PTR(err); } + f2fs_update_iostat(sbi, FS_META_READ_IO, F2FS_BLKSIZE); + lock_page(page); if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); @@ -206,7 +205,7 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, } /* - * Readahead CP/NAT/SIT/SSA pages + * Readahead CP/NAT/SIT/SSA/POR pages */ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type, bool sync) @@ -223,6 +222,7 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, .is_por = (type == META_POR), }; struct blk_plug plug; + int err; if (unlikely(type == META_POR)) fio.op_flags &= ~REQ_META; @@ -266,8 +266,11 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, } fio.page = page; - f2fs_submit_page_bio(&fio); - f2fs_put_page(page, 0); + err = f2fs_submit_page_bio(&fio); + f2fs_put_page(page, err ? 1 : 0); + + if (!err) + f2fs_update_iostat(sbi, FS_META_READ_IO, F2FS_BLKSIZE); } out: blk_finish_plug(&plug); @@ -898,7 +901,7 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi) return -ENOMEM; /* * Finding out valid cp block involves read both - * sets( cp pack1 and cp pack 2) + * sets( cp pack 1 and cp pack 2) */ cp_start_blk_no = le32_to_cpu(fsb->cp_blkaddr); cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); @@ -1163,11 +1166,8 @@ static int block_operations(struct f2fs_sb_info *sbi) .nr_to_write = LONG_MAX, .for_reclaim = 0, }; - struct blk_plug plug; int err = 0, cnt = 0; - blk_start_plug(&plug); - retry_flush_quotas: f2fs_lock_all(sbi); if (__need_flush_quota(sbi)) { @@ -1195,7 +1195,7 @@ static int block_operations(struct f2fs_sb_info *sbi) f2fs_unlock_all(sbi); err = f2fs_sync_dirty_inodes(sbi, DIR_INODE); if (err) - goto out; + return err; cond_resched(); goto retry_flush_quotas; } @@ -1211,7 +1211,7 @@ static int block_operations(struct f2fs_sb_info *sbi) f2fs_unlock_all(sbi); err = f2fs_sync_inode_meta(sbi); if (err) - goto out; + return err; cond_resched(); goto retry_flush_quotas; } @@ -1227,7 +1227,7 @@ static int block_operations(struct f2fs_sb_info *sbi) if (err) { up_write(&sbi->node_change); f2fs_unlock_all(sbi); - goto out; + return err; } cond_resched(); goto retry_flush_nodes; @@ -1239,8 +1239,6 @@ static int block_operations(struct f2fs_sb_info *sbi) */ __prepare_cp_block(sbi); up_write(&sbi->node_change); -out: - blk_finish_plug(&plug); return err; } @@ -1250,20 +1248,20 @@ static void unblock_operations(struct f2fs_sb_info *sbi) f2fs_unlock_all(sbi); } -void f2fs_wait_on_all_pages_writeback(struct f2fs_sb_info *sbi) +void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type) { DEFINE_WAIT(wait); for (;;) { prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); - if (!get_pages(sbi, F2FS_WB_CP_DATA)) + if (!get_pages(sbi, type)) break; if (unlikely(f2fs_cp_error(sbi))) break; - io_schedule_timeout(5*HZ); + io_schedule_timeout(DEFAULT_IO_TIMEOUT); } finish_wait(&sbi->cp_wait, &wait); } @@ -1301,10 +1299,14 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) else __clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); - if (is_sbi_flag_set(sbi, SBI_NEED_FSCK) || - is_sbi_flag_set(sbi, SBI_IS_RESIZEFS)) + if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) __set_ckpt_flags(ckpt, CP_FSCK_FLAG); + if (is_sbi_flag_set(sbi, SBI_IS_RESIZEFS)) + __set_ckpt_flags(ckpt, CP_RESIZEFS_FLAG); + else + __clear_ckpt_flags(ckpt, CP_RESIZEFS_FLAG); + if (is_sbi_flag_set(sbi, SBI_CP_DISABLED)) __set_ckpt_flags(ckpt, CP_DISABLED_FLAG); else @@ -1384,13 +1386,8 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* Flush all the NAT/SIT pages */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); - f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_META) && - !f2fs_cp_error(sbi)); - /* - * modify checkpoint - * version number is already updated - */ + /* start to update checkpoint, cp ver is already updated previously */ ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true)); ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { @@ -1493,11 +1490,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* Here, we have one bio having CP pack except cp pack 2 page */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); - f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_META) && - !f2fs_cp_error(sbi)); + /* Wait for all dirty meta pages to be submitted for IO */ + f2fs_wait_on_all_pages(sbi, F2FS_DIRTY_META); /* wait for previous submitted meta pages writeback */ - f2fs_wait_on_all_pages_writeback(sbi); + f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); /* flush all device cache */ err = f2fs_flush_device_cache(sbi); @@ -1506,13 +1503,13 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* barrier and flush checkpoint cp pack 2 page if it can */ commit_checkpoint(sbi, ckpt, start_blk); - f2fs_wait_on_all_pages_writeback(sbi); + f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); /* - * invalidate intermediate page cache borrowed from meta inode - * which are used for migration of encrypted inode's blocks. + * invalidate intermediate page cache borrowed from meta inode which are + * used for migration of encrypted or verity inode's blocks. */ - if (f2fs_sb_has_encrypt(sbi)) + if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi)) invalidate_mapping_pages(META_MAPPING(sbi), MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1); @@ -1543,9 +1540,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) return unlikely(f2fs_cp_error(sbi)) ? -EIO : 0; } -/* - * We guarantee that this checkpoint procedure will not fail. - */ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); @@ -1613,7 +1607,6 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) f2fs_flush_sit_entries(sbi, cpc); - /* unlock all the fs_lock[] in do_checkpoint() */ err = do_checkpoint(sbi, cpc); if (err) f2fs_release_discard_addrs(sbi); @@ -1626,7 +1619,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (cpc->reason & CP_RECOVERY) f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver); - /* do checkpoint periodically */ + /* update CP_TIME to trigger checkpoint periodically */ f2fs_update_time(sbi, CP_TIME); trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); out: diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c new file mode 100644 index 0000000000000000000000000000000000000000..f5a747d8b044bbd881650dce1d96875afd609953 --- /dev/null +++ b/fs/f2fs/compress.c @@ -0,0 +1,1389 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * f2fs compress support + * + * Copyright (c) 2019 Chao Yu + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include + +/* Some architectures don't have PAGE_KERNEL_RO */ +#ifndef PAGE_KERNEL_RO +#define PAGE_KERNEL_RO PAGE_KERNEL +#endif + +struct f2fs_compress_ops { + int (*init_compress_ctx)(struct compress_ctx *cc); + void (*destroy_compress_ctx)(struct compress_ctx *cc); + int (*compress_pages)(struct compress_ctx *cc); + int (*init_decompress_ctx)(struct decompress_io_ctx *dic); + void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic); + int (*decompress_pages)(struct decompress_io_ctx *dic); +}; + +static unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index) +{ + return index & (cc->cluster_size - 1); +} + +static pgoff_t cluster_idx(struct compress_ctx *cc, pgoff_t index) +{ + return index >> cc->log_cluster_size; +} + +static pgoff_t start_idx_of_cluster(struct compress_ctx *cc) +{ + return cc->cluster_idx << cc->log_cluster_size; +} + +bool f2fs_is_compressed_page(struct page *page) +{ + if (!PagePrivate(page)) + return false; + if (!page_private(page)) + return false; + if (IS_ATOMIC_WRITTEN_PAGE(page) || IS_DUMMY_WRITTEN_PAGE(page)) + return false; + f2fs_bug_on(F2FS_M_SB(page->mapping), + *((u32 *)page_private(page)) != F2FS_COMPRESSED_PAGE_MAGIC); + return true; +} + +static void f2fs_set_compressed_page(struct page *page, + struct inode *inode, pgoff_t index, void *data) +{ + SetPagePrivate(page); + set_page_private(page, (unsigned long)data); + + /* i_crypto_info and iv index */ + page->index = index; + page->mapping = inode->i_mapping; +} + +static void f2fs_put_compressed_page(struct page *page) +{ + set_page_private(page, (unsigned long)NULL); + ClearPagePrivate(page); + page->mapping = NULL; + unlock_page(page); + put_page(page); +} + +static void f2fs_drop_rpages(struct compress_ctx *cc, int len, bool unlock) +{ + int i; + + for (i = 0; i < len; i++) { + if (!cc->rpages[i]) + continue; + if (unlock) + unlock_page(cc->rpages[i]); + else + put_page(cc->rpages[i]); + } +} + +static void f2fs_put_rpages(struct compress_ctx *cc) +{ + f2fs_drop_rpages(cc, cc->cluster_size, false); +} + +static void f2fs_unlock_rpages(struct compress_ctx *cc, int len) +{ + f2fs_drop_rpages(cc, len, true); +} + +static void f2fs_put_rpages_mapping(struct compress_ctx *cc, + struct address_space *mapping, + pgoff_t start, int len) +{ + int i; + + for (i = 0; i < len; i++) { + struct page *page = find_get_page(mapping, start + i); + + put_page(page); + put_page(page); + } +} + +static void f2fs_put_rpages_wbc(struct compress_ctx *cc, + struct writeback_control *wbc, bool redirty, int unlock) +{ + unsigned int i; + + for (i = 0; i < cc->cluster_size; i++) { + if (!cc->rpages[i]) + continue; + if (redirty) + redirty_page_for_writepage(wbc, cc->rpages[i]); + f2fs_put_page(cc->rpages[i], unlock); + } +} + +struct page *f2fs_compress_control_page(struct page *page) +{ + return ((struct compress_io_ctx *)page_private(page))->rpages[0]; +} + +int f2fs_init_compress_ctx(struct compress_ctx *cc) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); + + if (cc->nr_rpages) + return 0; + + cc->rpages = f2fs_kzalloc(sbi, sizeof(struct page *) << + cc->log_cluster_size, GFP_NOFS); + return cc->rpages ? 0 : -ENOMEM; +} + +void f2fs_destroy_compress_ctx(struct compress_ctx *cc) +{ + kfree(cc->rpages); + cc->rpages = NULL; + cc->nr_rpages = 0; + cc->nr_cpages = 0; + cc->cluster_idx = NULL_CLUSTER; +} + +void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page) +{ + unsigned int cluster_ofs; + + if (!f2fs_cluster_can_merge_page(cc, page->index)) + f2fs_bug_on(F2FS_I_SB(cc->inode), 1); + + cluster_ofs = offset_in_cluster(cc, page->index); + cc->rpages[cluster_ofs] = page; + cc->nr_rpages++; + cc->cluster_idx = cluster_idx(cc, page->index); +} + +#ifdef CONFIG_F2FS_FS_LZO +static int lzo_init_compress_ctx(struct compress_ctx *cc) +{ + cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), + LZO1X_MEM_COMPRESS, GFP_NOFS); + if (!cc->private) + return -ENOMEM; + + cc->clen = lzo1x_worst_compress(PAGE_SIZE << cc->log_cluster_size); + return 0; +} + +static void lzo_destroy_compress_ctx(struct compress_ctx *cc) +{ + kvfree(cc->private); + cc->private = NULL; +} + +static int lzo_compress_pages(struct compress_ctx *cc) +{ + int ret; + + ret = lzo1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, + &cc->clen, cc->private); + if (ret != LZO_E_OK) { + printk_ratelimited("%sF2FS-fs (%s): lzo compress failed, ret:%d\n", + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); + return -EIO; + } + return 0; +} + +static int lzo_decompress_pages(struct decompress_io_ctx *dic) +{ + int ret; + + ret = lzo1x_decompress_safe(dic->cbuf->cdata, dic->clen, + dic->rbuf, &dic->rlen); + if (ret != LZO_E_OK) { + printk_ratelimited("%sF2FS-fs (%s): lzo decompress failed, ret:%d\n", + KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); + return -EIO; + } + + if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) { + printk_ratelimited("%sF2FS-fs (%s): lzo invalid rlen:%zu, " + "expected:%lu\n", KERN_ERR, + F2FS_I_SB(dic->inode)->sb->s_id, + dic->rlen, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; + } + return 0; +} + +static const struct f2fs_compress_ops f2fs_lzo_ops = { + .init_compress_ctx = lzo_init_compress_ctx, + .destroy_compress_ctx = lzo_destroy_compress_ctx, + .compress_pages = lzo_compress_pages, + .decompress_pages = lzo_decompress_pages, +}; +#endif + +#ifdef CONFIG_F2FS_FS_LZ4 +static int lz4_init_compress_ctx(struct compress_ctx *cc) +{ + cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), + LZ4_MEM_COMPRESS, GFP_NOFS); + if (!cc->private) + return -ENOMEM; + + cc->clen = LZ4_compressBound(PAGE_SIZE << cc->log_cluster_size); + return 0; +} + +static void lz4_destroy_compress_ctx(struct compress_ctx *cc) +{ + kvfree(cc->private); + cc->private = NULL; +} + +static int lz4_compress_pages(struct compress_ctx *cc) +{ + int len; + + len = LZ4_compress_default(cc->rbuf, cc->cbuf->cdata, cc->rlen, + cc->clen, cc->private); + if (!len) { + printk_ratelimited("%sF2FS-fs (%s): lz4 compress failed\n", + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id); + return -EIO; + } + cc->clen = len; + return 0; +} + +static int lz4_decompress_pages(struct decompress_io_ctx *dic) +{ + int ret; + + ret = LZ4_decompress_safe(dic->cbuf->cdata, dic->rbuf, + dic->clen, dic->rlen); + if (ret < 0) { + printk_ratelimited("%sF2FS-fs (%s): lz4 decompress failed, ret:%d\n", + KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); + return -EIO; + } + + if (ret != PAGE_SIZE << dic->log_cluster_size) { + printk_ratelimited("%sF2FS-fs (%s): lz4 invalid rlen:%zu, " + "expected:%lu\n", KERN_ERR, + F2FS_I_SB(dic->inode)->sb->s_id, + dic->rlen, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; + } + return 0; +} + +static const struct f2fs_compress_ops f2fs_lz4_ops = { + .init_compress_ctx = lz4_init_compress_ctx, + .destroy_compress_ctx = lz4_destroy_compress_ctx, + .compress_pages = lz4_compress_pages, + .decompress_pages = lz4_decompress_pages, +}; +#endif + +#ifdef CONFIG_F2FS_FS_ZSTD +#define F2FS_ZSTD_DEFAULT_CLEVEL 1 + +static int zstd_init_compress_ctx(struct compress_ctx *cc) +{ + ZSTD_parameters params; + ZSTD_CStream *stream; + void *workspace; + unsigned int workspace_size; + + params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0); + workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams); + + workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode), + workspace_size, GFP_NOFS); + if (!workspace) + return -ENOMEM; + + stream = ZSTD_initCStream(params, 0, workspace, workspace_size); + if (!stream) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n", + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, + __func__); + kvfree(workspace); + return -EIO; + } + + cc->private = workspace; + cc->private2 = stream; + + cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE; + return 0; +} + +static void zstd_destroy_compress_ctx(struct compress_ctx *cc) +{ + kvfree(cc->private); + cc->private = NULL; + cc->private2 = NULL; +} + +static int zstd_compress_pages(struct compress_ctx *cc) +{ + ZSTD_CStream *stream = cc->private2; + ZSTD_inBuffer inbuf; + ZSTD_outBuffer outbuf; + int src_size = cc->rlen; + int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE; + int ret; + + inbuf.pos = 0; + inbuf.src = cc->rbuf; + inbuf.size = src_size; + + outbuf.pos = 0; + outbuf.dst = cc->cbuf->cdata; + outbuf.size = dst_size; + + ret = ZSTD_compressStream(stream, &outbuf, &inbuf); + if (ZSTD_isError(ret)) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n", + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, + __func__, ZSTD_getErrorCode(ret)); + return -EIO; + } + + ret = ZSTD_endStream(stream, &outbuf); + if (ZSTD_isError(ret)) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n", + KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, + __func__, ZSTD_getErrorCode(ret)); + return -EIO; + } + + cc->clen = outbuf.pos; + return 0; +} + +static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) +{ + ZSTD_DStream *stream; + void *workspace; + unsigned int workspace_size; + + workspace_size = ZSTD_DStreamWorkspaceBound(MAX_COMPRESS_WINDOW_SIZE); + + workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode), + workspace_size, GFP_NOFS); + if (!workspace) + return -ENOMEM; + + stream = ZSTD_initDStream(MAX_COMPRESS_WINDOW_SIZE, + workspace, workspace_size); + if (!stream) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n", + KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, + __func__); + kvfree(workspace); + return -EIO; + } + + dic->private = workspace; + dic->private2 = stream; + + return 0; +} + +static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic) +{ + kvfree(dic->private); + dic->private = NULL; + dic->private2 = NULL; +} + +static int zstd_decompress_pages(struct decompress_io_ctx *dic) +{ + ZSTD_DStream *stream = dic->private2; + ZSTD_inBuffer inbuf; + ZSTD_outBuffer outbuf; + int ret; + + inbuf.pos = 0; + inbuf.src = dic->cbuf->cdata; + inbuf.size = dic->clen; + + outbuf.pos = 0; + outbuf.dst = dic->rbuf; + outbuf.size = dic->rlen; + + ret = ZSTD_decompressStream(stream, &outbuf, &inbuf); + if (ZSTD_isError(ret)) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n", + KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, + __func__, ZSTD_getErrorCode(ret)); + return -EIO; + } + + if (dic->rlen != outbuf.pos) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, " + "expected:%lu\n", KERN_ERR, + F2FS_I_SB(dic->inode)->sb->s_id, + __func__, dic->rlen, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; + } + + return 0; +} + +static const struct f2fs_compress_ops f2fs_zstd_ops = { + .init_compress_ctx = zstd_init_compress_ctx, + .destroy_compress_ctx = zstd_destroy_compress_ctx, + .compress_pages = zstd_compress_pages, + .init_decompress_ctx = zstd_init_decompress_ctx, + .destroy_decompress_ctx = zstd_destroy_decompress_ctx, + .decompress_pages = zstd_decompress_pages, +}; +#endif + +static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = { +#ifdef CONFIG_F2FS_FS_LZO + &f2fs_lzo_ops, +#else + NULL, +#endif +#ifdef CONFIG_F2FS_FS_LZ4 + &f2fs_lz4_ops, +#else + NULL, +#endif +#ifdef CONFIG_F2FS_FS_ZSTD + &f2fs_zstd_ops, +#else + NULL, +#endif +}; + +bool f2fs_is_compress_backend_ready(struct inode *inode) +{ + if (!f2fs_compressed_file(inode)) + return true; + return f2fs_cops[F2FS_I(inode)->i_compress_algorithm]; +} + +static struct page *f2fs_grab_page(void) +{ + struct page *page; + + page = alloc_page(GFP_NOFS); + if (!page) + return NULL; + lock_page(page); + return page; +} + +static int f2fs_compress_pages(struct compress_ctx *cc) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); + struct f2fs_inode_info *fi = F2FS_I(cc->inode); + const struct f2fs_compress_ops *cops = + f2fs_cops[fi->i_compress_algorithm]; + unsigned int max_len, nr_cpages; + int i, ret; + + trace_f2fs_compress_pages_start(cc->inode, cc->cluster_idx, + cc->cluster_size, fi->i_compress_algorithm); + + if (cops->init_compress_ctx) { + ret = cops->init_compress_ctx(cc); + if (ret) + goto out; + } + + max_len = COMPRESS_HEADER_SIZE + cc->clen; + cc->nr_cpages = DIV_ROUND_UP(max_len, PAGE_SIZE); + + cc->cpages = f2fs_kzalloc(sbi, sizeof(struct page *) * + cc->nr_cpages, GFP_NOFS); + if (!cc->cpages) { + ret = -ENOMEM; + goto destroy_compress_ctx; + } + + for (i = 0; i < cc->nr_cpages; i++) { + cc->cpages[i] = f2fs_grab_page(); + if (!cc->cpages[i]) { + ret = -ENOMEM; + goto out_free_cpages; + } + } + + cc->rbuf = vmap(cc->rpages, cc->cluster_size, VM_MAP, PAGE_KERNEL_RO); + if (!cc->rbuf) { + ret = -ENOMEM; + goto out_free_cpages; + } + + cc->cbuf = vmap(cc->cpages, cc->nr_cpages, VM_MAP, PAGE_KERNEL); + if (!cc->cbuf) { + ret = -ENOMEM; + goto out_vunmap_rbuf; + } + + ret = cops->compress_pages(cc); + if (ret) + goto out_vunmap_cbuf; + + max_len = PAGE_SIZE * (cc->cluster_size - 1) - COMPRESS_HEADER_SIZE; + + if (cc->clen > max_len) { + ret = -EAGAIN; + goto out_vunmap_cbuf; + } + + cc->cbuf->clen = cpu_to_le32(cc->clen); + + for (i = 0; i < COMPRESS_DATA_RESERVED_SIZE; i++) + cc->cbuf->reserved[i] = cpu_to_le32(0); + + nr_cpages = DIV_ROUND_UP(cc->clen + COMPRESS_HEADER_SIZE, PAGE_SIZE); + + /* zero out any unused part of the last page */ + memset(&cc->cbuf->cdata[cc->clen], 0, + (nr_cpages * PAGE_SIZE) - (cc->clen + COMPRESS_HEADER_SIZE)); + + vunmap(cc->cbuf); + vunmap(cc->rbuf); + + for (i = nr_cpages; i < cc->nr_cpages; i++) { + f2fs_put_compressed_page(cc->cpages[i]); + cc->cpages[i] = NULL; + } + + if (cops->destroy_compress_ctx) + cops->destroy_compress_ctx(cc); + + cc->nr_cpages = nr_cpages; + + trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx, + cc->clen, ret); + return 0; + +out_vunmap_cbuf: + vunmap(cc->cbuf); +out_vunmap_rbuf: + vunmap(cc->rbuf); +out_free_cpages: + for (i = 0; i < cc->nr_cpages; i++) { + if (cc->cpages[i]) + f2fs_put_compressed_page(cc->cpages[i]); + } + kfree(cc->cpages); + cc->cpages = NULL; +destroy_compress_ctx: + if (cops->destroy_compress_ctx) + cops->destroy_compress_ctx(cc); +out: + trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx, + cc->clen, ret); + return ret; +} + +void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity) +{ + struct decompress_io_ctx *dic = + (struct decompress_io_ctx *)page_private(page); + struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); + struct f2fs_inode_info *fi= F2FS_I(dic->inode); + const struct f2fs_compress_ops *cops = + f2fs_cops[fi->i_compress_algorithm]; + int ret; + + dec_page_count(sbi, F2FS_RD_DATA); + + if (bio->bi_status || PageError(page)) + dic->failed = true; + + if (refcount_dec_not_one(&dic->ref)) + return; + + trace_f2fs_decompress_pages_start(dic->inode, dic->cluster_idx, + dic->cluster_size, fi->i_compress_algorithm); + + /* submit partial compressed pages */ + if (dic->failed) { + ret = -EIO; + goto out_free_dic; + } + + if (cops->init_decompress_ctx) { + ret = cops->init_decompress_ctx(dic); + if (ret) + goto out_free_dic; + } + + dic->rbuf = vmap(dic->tpages, dic->cluster_size, VM_MAP, PAGE_KERNEL); + if (!dic->rbuf) { + ret = -ENOMEM; + goto destroy_decompress_ctx; + } + + dic->cbuf = vmap(dic->cpages, dic->nr_cpages, VM_MAP, PAGE_KERNEL_RO); + if (!dic->cbuf) { + ret = -ENOMEM; + goto out_vunmap_rbuf; + } + + dic->clen = le32_to_cpu(dic->cbuf->clen); + dic->rlen = PAGE_SIZE << dic->log_cluster_size; + + if (dic->clen > PAGE_SIZE * dic->nr_cpages - COMPRESS_HEADER_SIZE) { + ret = -EFSCORRUPTED; + goto out_vunmap_cbuf; + } + + ret = cops->decompress_pages(dic); + +out_vunmap_cbuf: + vunmap(dic->cbuf); +out_vunmap_rbuf: + vunmap(dic->rbuf); +destroy_decompress_ctx: + if (cops->destroy_decompress_ctx) + cops->destroy_decompress_ctx(dic); +out_free_dic: + if (verity) + refcount_set(&dic->ref, dic->nr_cpages); + if (!verity) + f2fs_decompress_end_io(dic->rpages, dic->cluster_size, + ret, false); + + trace_f2fs_decompress_pages_end(dic->inode, dic->cluster_idx, + dic->clen, ret); + if (!verity) + f2fs_free_dic(dic); +} + +static bool is_page_in_cluster(struct compress_ctx *cc, pgoff_t index) +{ + if (cc->cluster_idx == NULL_CLUSTER) + return true; + return cc->cluster_idx == cluster_idx(cc, index); +} + +bool f2fs_cluster_is_empty(struct compress_ctx *cc) +{ + return cc->nr_rpages == 0; +} + +static bool f2fs_cluster_is_full(struct compress_ctx *cc) +{ + return cc->cluster_size == cc->nr_rpages; +} + +bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index) +{ + if (f2fs_cluster_is_empty(cc)) + return true; + return is_page_in_cluster(cc, index); +} + +static bool __cluster_may_compress(struct compress_ctx *cc) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); + loff_t i_size = i_size_read(cc->inode); + unsigned nr_pages = DIV_ROUND_UP(i_size, PAGE_SIZE); + int i; + + for (i = 0; i < cc->cluster_size; i++) { + struct page *page = cc->rpages[i]; + + f2fs_bug_on(sbi, !page); + + if (unlikely(f2fs_cp_error(sbi))) + return false; + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + return false; + + /* beyond EOF */ + if (page->index >= nr_pages) + return false; + } + return true; +} + +static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) +{ + struct dnode_of_data dn; + int ret; + + set_new_dnode(&dn, cc->inode, NULL, NULL, 0); + ret = f2fs_get_dnode_of_data(&dn, start_idx_of_cluster(cc), + LOOKUP_NODE); + if (ret) { + if (ret == -ENOENT) + ret = 0; + goto fail; + } + + if (dn.data_blkaddr == COMPRESS_ADDR) { + int i; + + ret = 1; + for (i = 1; i < cc->cluster_size; i++) { + block_t blkaddr; + + blkaddr = data_blkaddr(dn.inode, + dn.node_page, dn.ofs_in_node + i); + if (compr) { + if (__is_valid_data_blkaddr(blkaddr)) + ret++; + } else { + if (blkaddr != NULL_ADDR) + ret++; + } + } + } +fail: + f2fs_put_dnode(&dn); + return ret; +} + +/* return # of compressed blocks in compressed cluster */ +static int f2fs_compressed_blocks(struct compress_ctx *cc) +{ + return __f2fs_cluster_blocks(cc, true); +} + +/* return # of valid blocks in compressed cluster */ +static int f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) +{ + return __f2fs_cluster_blocks(cc, false); +} + +int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index) +{ + struct compress_ctx cc = { + .inode = inode, + .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, + .cluster_size = F2FS_I(inode)->i_cluster_size, + .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size, + }; + + return f2fs_cluster_blocks(&cc, false); +} + +static bool cluster_may_compress(struct compress_ctx *cc) +{ + if (!f2fs_compressed_file(cc->inode)) + return false; + if (f2fs_is_atomic_file(cc->inode)) + return false; + if (f2fs_is_mmap_file(cc->inode)) + return false; + if (!f2fs_cluster_is_full(cc)) + return false; + return __cluster_may_compress(cc); +} + +static void set_cluster_writeback(struct compress_ctx *cc) +{ + int i; + + for (i = 0; i < cc->cluster_size; i++) { + if (cc->rpages[i]) + set_page_writeback(cc->rpages[i]); + } +} + +static void set_cluster_dirty(struct compress_ctx *cc) +{ + int i; + + for (i = 0; i < cc->cluster_size; i++) + if (cc->rpages[i]) + set_page_dirty(cc->rpages[i]); +} + +static int prepare_compress_overwrite(struct compress_ctx *cc, + struct page **pagep, pgoff_t index, void **fsdata) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); + struct address_space *mapping = cc->inode->i_mapping; + struct page *page; + struct dnode_of_data dn; + sector_t last_block_in_bio; + unsigned fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT; + pgoff_t start_idx = start_idx_of_cluster(cc); + int i, ret; + bool prealloc; + +retry: + ret = f2fs_cluster_blocks(cc, false); + if (ret <= 0) + return ret; + + /* compressed case */ + prealloc = (ret < cc->cluster_size); + + ret = f2fs_init_compress_ctx(cc); + if (ret) + return ret; + + /* keep page reference to avoid page reclaim */ + for (i = 0; i < cc->cluster_size; i++) { + page = f2fs_pagecache_get_page(mapping, start_idx + i, + fgp_flag, GFP_NOFS); + if (!page) { + ret = -ENOMEM; + goto unlock_pages; + } + + if (PageUptodate(page)) + unlock_page(page); + else + f2fs_compress_ctx_add_page(cc, page); + } + + if (!f2fs_cluster_is_empty(cc)) { + struct bio *bio = NULL; + + ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size, + &last_block_in_bio, false, true); + f2fs_destroy_compress_ctx(cc); + if (ret) + goto release_pages; + if (bio) + f2fs_submit_bio(sbi, bio, DATA); + + ret = f2fs_init_compress_ctx(cc); + if (ret) + goto release_pages; + } + + for (i = 0; i < cc->cluster_size; i++) { + f2fs_bug_on(sbi, cc->rpages[i]); + + page = find_lock_page(mapping, start_idx + i); + f2fs_bug_on(sbi, !page); + + f2fs_wait_on_page_writeback(page, DATA, true, true); + + f2fs_compress_ctx_add_page(cc, page); + f2fs_put_page(page, 0); + + if (!PageUptodate(page)) { + f2fs_unlock_rpages(cc, i + 1); + f2fs_put_rpages_mapping(cc, mapping, start_idx, + cc->cluster_size); + f2fs_destroy_compress_ctx(cc); + goto retry; + } + } + + if (prealloc) { + __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + + set_new_dnode(&dn, cc->inode, NULL, NULL, 0); + + for (i = cc->cluster_size - 1; i > 0; i--) { + ret = f2fs_get_block(&dn, start_idx + i); + if (ret) { + i = cc->cluster_size; + break; + } + + if (dn.data_blkaddr != NEW_ADDR) + break; + } + + __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + } + + if (likely(!ret)) { + *fsdata = cc->rpages; + *pagep = cc->rpages[offset_in_cluster(cc, index)]; + return cc->cluster_size; + } + +unlock_pages: + f2fs_unlock_rpages(cc, i); +release_pages: + f2fs_put_rpages_mapping(cc, mapping, start_idx, i); + f2fs_destroy_compress_ctx(cc); + return ret; +} + +int f2fs_prepare_compress_overwrite(struct inode *inode, + struct page **pagep, pgoff_t index, void **fsdata) +{ + struct compress_ctx cc = { + .inode = inode, + .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, + .cluster_size = F2FS_I(inode)->i_cluster_size, + .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size, + .rpages = NULL, + .nr_rpages = 0, + }; + + return prepare_compress_overwrite(&cc, pagep, index, fsdata); +} + +bool f2fs_compress_write_end(struct inode *inode, void *fsdata, + pgoff_t index, unsigned copied) + +{ + struct compress_ctx cc = { + .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, + .cluster_size = F2FS_I(inode)->i_cluster_size, + .rpages = fsdata, + }; + bool first_index = (index == cc.rpages[0]->index); + + if (copied) + set_cluster_dirty(&cc); + + f2fs_put_rpages_wbc(&cc, NULL, false, 1); + f2fs_destroy_compress_ctx(&cc); + + return first_index; +} + +static int f2fs_write_compressed_pages(struct compress_ctx *cc, + int *submitted, + struct writeback_control *wbc, + enum iostat_type io_type) +{ + struct inode *inode = cc->inode; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_io_info fio = { + .sbi = sbi, + .ino = cc->inode->i_ino, + .type = DATA, + .op = REQ_OP_WRITE, + .op_flags = wbc_to_write_flags(wbc), + .old_blkaddr = NEW_ADDR, + .page = NULL, + .encrypted_page = NULL, + .compressed_page = NULL, + .submitted = false, + .io_type = io_type, + .io_wbc = wbc, + .encrypted = f2fs_encrypted_file(cc->inode), + }; + struct dnode_of_data dn; + struct node_info ni; + struct compress_io_ctx *cic; + pgoff_t start_idx = start_idx_of_cluster(cc); + unsigned int last_index = cc->cluster_size - 1; + loff_t psize; + int i, err; + + if (!IS_NOQUOTA(inode) && !f2fs_trylock_op(sbi)) + return -EAGAIN; + + set_new_dnode(&dn, cc->inode, NULL, NULL, 0); + + err = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE); + if (err) + goto out_unlock_op; + + for (i = 0; i < cc->cluster_size; i++) { + if (data_blkaddr(dn.inode, dn.node_page, + dn.ofs_in_node + i) == NULL_ADDR) + goto out_put_dnode; + } + + psize = (loff_t)(cc->rpages[last_index]->index + 1) << PAGE_SHIFT; + + err = f2fs_get_node_info(fio.sbi, dn.nid, &ni); + if (err) + goto out_put_dnode; + + fio.version = ni.version; + + cic = f2fs_kzalloc(sbi, sizeof(struct compress_io_ctx), GFP_NOFS); + if (!cic) + goto out_put_dnode; + + cic->magic = F2FS_COMPRESSED_PAGE_MAGIC; + cic->inode = inode; + refcount_set(&cic->ref, cc->nr_cpages); + cic->rpages = f2fs_kzalloc(sbi, sizeof(struct page *) << + cc->log_cluster_size, GFP_NOFS); + if (!cic->rpages) + goto out_put_cic; + + cic->nr_rpages = cc->cluster_size; + + for (i = 0; i < cc->nr_cpages; i++) { + f2fs_set_compressed_page(cc->cpages[i], inode, + cc->rpages[i + 1]->index, cic); + fio.compressed_page = cc->cpages[i]; + if (fio.encrypted) { + fio.page = cc->rpages[i + 1]; + err = f2fs_encrypt_one_page(&fio); + if (err) + goto out_destroy_crypt; + if (fscrypt_inode_uses_fs_layer_crypto(inode)) + cc->cpages[i] = fio.encrypted_page; + } + } + + set_cluster_writeback(cc); + + for (i = 0; i < cc->cluster_size; i++) + cic->rpages[i] = cc->rpages[i]; + + for (i = 0; i < cc->cluster_size; i++, dn.ofs_in_node++) { + block_t blkaddr; + + blkaddr = f2fs_data_blkaddr(&dn); + fio.page = cc->rpages[i]; + fio.old_blkaddr = blkaddr; + + /* cluster header */ + if (i == 0) { + if (blkaddr == COMPRESS_ADDR) + fio.compr_blocks++; + if (__is_valid_data_blkaddr(blkaddr)) + f2fs_invalidate_blocks(sbi, blkaddr); + f2fs_update_data_blkaddr(&dn, COMPRESS_ADDR); + goto unlock_continue; + } + + if (fio.compr_blocks && __is_valid_data_blkaddr(blkaddr)) + fio.compr_blocks++; + + if (i > cc->nr_cpages) { + if (__is_valid_data_blkaddr(blkaddr)) { + f2fs_invalidate_blocks(sbi, blkaddr); + f2fs_update_data_blkaddr(&dn, NEW_ADDR); + } + goto unlock_continue; + } + + f2fs_bug_on(fio.sbi, blkaddr == NULL_ADDR); + + if (fio.encrypted && fscrypt_inode_uses_fs_layer_crypto(inode)) + fio.encrypted_page = cc->cpages[i - 1]; + else + fio.compressed_page = cc->cpages[i - 1]; + + cc->cpages[i - 1] = NULL; + f2fs_outplace_write_data(&dn, &fio); + (*submitted)++; +unlock_continue: + inode_dec_dirty_pages(cc->inode); + unlock_page(fio.page); + } + + if (fio.compr_blocks) + f2fs_i_compr_blocks_update(inode, fio.compr_blocks - 1, false); + f2fs_i_compr_blocks_update(inode, cc->nr_cpages, true); + + set_inode_flag(cc->inode, FI_APPEND_WRITE); + if (cc->cluster_idx == 0) + set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); + + f2fs_put_dnode(&dn); + if (!IS_NOQUOTA(inode)) + f2fs_unlock_op(sbi); + + spin_lock(&fi->i_size_lock); + if (fi->last_disk_size < psize) + fi->last_disk_size = psize; + spin_unlock(&fi->i_size_lock); + + f2fs_put_rpages(cc); + f2fs_destroy_compress_ctx(cc); + return 0; + +out_destroy_crypt: + kfree(cic->rpages); + + for (--i; i >= 0; i--) + fscrypt_finalize_bounce_page(&cc->cpages[i]); + for (i = 0; i < cc->nr_cpages; i++) { + if (!cc->cpages[i]) + continue; + f2fs_put_page(cc->cpages[i], 1); + } +out_put_cic: + kfree(cic); +out_put_dnode: + f2fs_put_dnode(&dn); +out_unlock_op: + if (!IS_NOQUOTA(inode)) + f2fs_unlock_op(sbi); + return -EAGAIN; +} + +void f2fs_compress_write_end_io(struct bio *bio, struct page *page) +{ + struct f2fs_sb_info *sbi = bio->bi_private; + struct compress_io_ctx *cic = + (struct compress_io_ctx *)page_private(page); + int i; + + if (unlikely(bio->bi_status)) + mapping_set_error(cic->inode->i_mapping, -EIO); + + f2fs_put_compressed_page(page); + + dec_page_count(sbi, F2FS_WB_DATA); + + if (refcount_dec_not_one(&cic->ref)) + return; + + for (i = 0; i < cic->nr_rpages; i++) { + WARN_ON(!cic->rpages[i]); + clear_cold_data(cic->rpages[i]); + end_page_writeback(cic->rpages[i]); + } + + kfree(cic->rpages); + kfree(cic); +} + +static int f2fs_write_raw_pages(struct compress_ctx *cc, + int *submitted, + struct writeback_control *wbc, + enum iostat_type io_type) +{ + struct address_space *mapping = cc->inode->i_mapping; + int _submitted, compr_blocks, ret; + int i = -1, err = 0; + + compr_blocks = f2fs_compressed_blocks(cc); + if (compr_blocks < 0) { + err = compr_blocks; + goto out_err; + } + + for (i = 0; i < cc->cluster_size; i++) { + if (!cc->rpages[i]) + continue; +retry_write: + if (cc->rpages[i]->mapping != mapping) { + unlock_page(cc->rpages[i]); + continue; + } + + BUG_ON(!PageLocked(cc->rpages[i])); + + ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted, + NULL, NULL, wbc, io_type, + compr_blocks); + if (ret) { + if (ret == AOP_WRITEPAGE_ACTIVATE) { + unlock_page(cc->rpages[i]); + ret = 0; + } else if (ret == -EAGAIN) { + /* + * for quota file, just redirty left pages to + * avoid deadlock caused by cluster update race + * from foreground operation. + */ + if (IS_NOQUOTA(cc->inode)) { + err = 0; + goto out_err; + } + ret = 0; + cond_resched(); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); + lock_page(cc->rpages[i]); + clear_page_dirty_for_io(cc->rpages[i]); + goto retry_write; + } + err = ret; + goto out_err; + } + + *submitted += _submitted; + } + return 0; +out_err: + for (++i; i < cc->cluster_size; i++) { + if (!cc->rpages[i]) + continue; + redirty_page_for_writepage(wbc, cc->rpages[i]); + unlock_page(cc->rpages[i]); + } + return err; +} + +int f2fs_write_multi_pages(struct compress_ctx *cc, + int *submitted, + struct writeback_control *wbc, + enum iostat_type io_type) +{ + struct f2fs_inode_info *fi = F2FS_I(cc->inode); + const struct f2fs_compress_ops *cops = + f2fs_cops[fi->i_compress_algorithm]; + int err; + + *submitted = 0; + if (cluster_may_compress(cc)) { + err = f2fs_compress_pages(cc); + if (err == -EAGAIN) { + goto write; + } else if (err) { + f2fs_put_rpages_wbc(cc, wbc, true, 1); + goto destroy_out; + } + + err = f2fs_write_compressed_pages(cc, submitted, + wbc, io_type); + cops->destroy_compress_ctx(cc); + if (!err) + return 0; + f2fs_bug_on(F2FS_I_SB(cc->inode), err != -EAGAIN); + } +write: + f2fs_bug_on(F2FS_I_SB(cc->inode), *submitted); + + err = f2fs_write_raw_pages(cc, submitted, wbc, io_type); + f2fs_put_rpages_wbc(cc, wbc, false, 0); +destroy_out: + f2fs_destroy_compress_ctx(cc); + return err; +} + +struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); + struct decompress_io_ctx *dic; + pgoff_t start_idx = start_idx_of_cluster(cc); + int i; + + dic = f2fs_kzalloc(sbi, sizeof(struct decompress_io_ctx), GFP_NOFS); + if (!dic) + return ERR_PTR(-ENOMEM); + + dic->rpages = f2fs_kzalloc(sbi, sizeof(struct page *) << + cc->log_cluster_size, GFP_NOFS); + if (!dic->rpages) { + kfree(dic); + return ERR_PTR(-ENOMEM); + } + + dic->magic = F2FS_COMPRESSED_PAGE_MAGIC; + dic->inode = cc->inode; + refcount_set(&dic->ref, cc->nr_cpages); + dic->cluster_idx = cc->cluster_idx; + dic->cluster_size = cc->cluster_size; + dic->log_cluster_size = cc->log_cluster_size; + dic->nr_cpages = cc->nr_cpages; + dic->failed = false; + + for (i = 0; i < dic->cluster_size; i++) + dic->rpages[i] = cc->rpages[i]; + dic->nr_rpages = cc->cluster_size; + + dic->cpages = f2fs_kzalloc(sbi, sizeof(struct page *) * + dic->nr_cpages, GFP_NOFS); + if (!dic->cpages) + goto out_free; + + for (i = 0; i < dic->nr_cpages; i++) { + struct page *page; + + page = f2fs_grab_page(); + if (!page) + goto out_free; + + f2fs_set_compressed_page(page, cc->inode, + start_idx + i + 1, dic); + dic->cpages[i] = page; + } + + dic->tpages = f2fs_kzalloc(sbi, sizeof(struct page *) * + dic->cluster_size, GFP_NOFS); + if (!dic->tpages) + goto out_free; + + for (i = 0; i < dic->cluster_size; i++) { + if (cc->rpages[i]) { + dic->tpages[i] = cc->rpages[i]; + continue; + } + + dic->tpages[i] = f2fs_grab_page(); + if (!dic->tpages[i]) + goto out_free; + } + + return dic; + +out_free: + f2fs_free_dic(dic); + return ERR_PTR(-ENOMEM); +} + +void f2fs_free_dic(struct decompress_io_ctx *dic) +{ + int i; + + if (dic->tpages) { + for (i = 0; i < dic->cluster_size; i++) { + if (dic->rpages[i]) + continue; + if (!dic->tpages[i]) + continue; + unlock_page(dic->tpages[i]); + put_page(dic->tpages[i]); + } + kfree(dic->tpages); + } + + if (dic->cpages) { + for (i = 0; i < dic->nr_cpages; i++) { + if (!dic->cpages[i]) + continue; + f2fs_put_compressed_page(dic->cpages[i]); + } + kfree(dic->cpages); + } + + kfree(dic->rpages); + kfree(dic); +} + +void f2fs_decompress_end_io(struct page **rpages, + unsigned int cluster_size, bool err, bool verity) +{ + int i; + + for (i = 0; i < cluster_size; i++) { + struct page *rpage = rpages[i]; + + if (!rpage) + continue; + + if (err || PageError(rpage)) + goto clear_uptodate; + + if (!verity || fsverity_verify_page(rpage)) { + SetPageUptodate(rpage); + goto unlock; + } +clear_uptodate: + ClearPageUptodate(rpage); + ClearPageError(rpage); +unlock: + unlock_page(rpage); + } +} diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 1ae873be55591cacaf649a81481a9cf9c2577e26..19abef392da371e1fa01cefb9cb8afac49611e34 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -32,6 +32,44 @@ static struct kmem_cache *bio_post_read_ctx_cache; static struct kmem_cache *bio_entry_slab; static mempool_t *bio_post_read_ctx_pool; +static struct bio_set *f2fs_bioset; + +#define F2FS_BIO_POOL_SIZE NR_CURSEG_TYPE + +int __init f2fs_init_bioset(void) +{ + f2fs_bioset = bioset_create(F2FS_BIO_POOL_SIZE, + 0, BIOSET_NEED_BVECS); + if (!f2fs_bioset) + return -ENOMEM; + return 0; +} + +void f2fs_destroy_bioset(void) +{ + bioset_free(f2fs_bioset); +} + +static inline struct bio *__f2fs_bio_alloc(gfp_t gfp_mask, + unsigned int nr_iovecs) +{ + return bio_alloc_bioset(gfp_mask, nr_iovecs, f2fs_bioset); +} + +struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, int npages, bool noio) +{ + if (noio) { + /* No failure on bio allocation */ + return __f2fs_bio_alloc(GFP_NOIO, npages); + } + + if (time_to_inject(sbi, FAULT_ALLOC_BIO)) { + f2fs_show_injection_info(sbi, FAULT_ALLOC_BIO); + return NULL; + } + + return __f2fs_bio_alloc(GFP_KERNEL, npages); +} static bool __is_cp_guaranteed(struct page *page) { @@ -42,6 +80,9 @@ static bool __is_cp_guaranteed(struct page *page) if (!mapping) return false; + if (f2fs_is_compressed_page(page)) + return false; + inode = mapping->host; sbi = F2FS_I_SB(inode); @@ -74,19 +115,19 @@ static enum count_type __read_io_type(struct page *page) /* postprocessing steps for read bios */ enum bio_post_read_step { - STEP_INITIAL = 0, STEP_DECRYPT, + STEP_DECOMPRESS, STEP_VERITY, }; struct bio_post_read_ctx { struct bio *bio; + struct f2fs_sb_info *sbi; struct work_struct work; - unsigned int cur_step; unsigned int enabled_steps; }; -static void __read_end_io(struct bio *bio) +static void __read_end_io(struct bio *bio, bool compr, bool verity) { struct page *page; struct bio_vec *bv; @@ -95,6 +136,15 @@ static void __read_end_io(struct bio *bio) bio_for_each_segment_all(bv, bio, i) { page = bv->bv_page; +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (compr && f2fs_is_compressed_page(page)) { + f2fs_decompress_pages(bio, page, verity); + continue; + } + if (verity) + continue; +#endif + /* PG_error was set if any post_read step failed */ if (bio->bi_status || PageError(page)) { ClearPageUptodate(page); @@ -106,31 +156,133 @@ static void __read_end_io(struct bio *bio) dec_page_count(F2FS_P_SB(page), __read_io_type(page)); unlock_page(page); } - if (bio->bi_private) - mempool_free(bio->bi_private, bio_post_read_ctx_pool); - bio_put(bio); +} + +static void f2fs_release_read_bio(struct bio *bio); +static void __f2fs_read_end_io(struct bio *bio, bool compr, bool verity) +{ + if (!compr) + __read_end_io(bio, false, verity); + f2fs_release_read_bio(bio); +} + +static void f2fs_decompress_bio(struct bio *bio, bool verity) +{ + __read_end_io(bio, true, verity); } static void bio_post_read_processing(struct bio_post_read_ctx *ctx); -static void decrypt_work(struct work_struct *work) +static void f2fs_decrypt_work(struct bio_post_read_ctx *ctx) +{ + fscrypt_decrypt_bio(ctx->bio); +} + +static void f2fs_decompress_work(struct bio_post_read_ctx *ctx) +{ + f2fs_decompress_bio(ctx->bio, ctx->enabled_steps & (1 << STEP_VERITY)); +} + +#ifdef CONFIG_F2FS_FS_COMPRESSION +static void f2fs_verify_pages(struct page **rpages, unsigned int cluster_size) +{ + f2fs_decompress_end_io(rpages, cluster_size, false, true); +} + +static void f2fs_verify_bio(struct bio *bio) +{ + struct bio_vec *bv; + int i; + + bio_for_each_segment_all(bv, bio, i) { + struct page *page = bv->bv_page; + struct decompress_io_ctx *dic; + + dic = (struct decompress_io_ctx *)page_private(page); + + if (dic) { + if (refcount_dec_not_one(&dic->ref)) + continue; + f2fs_verify_pages(dic->rpages, + dic->cluster_size); + f2fs_free_dic(dic); + continue; + } + + if (bio->bi_status || PageError(page)) + goto clear_uptodate; + + if (fsverity_verify_page(page)) { + SetPageUptodate(page); + goto unlock; + } +clear_uptodate: + ClearPageUptodate(page); + ClearPageError(page); +unlock: + dec_page_count(F2FS_P_SB(page), __read_io_type(page)); + unlock_page(page); + } +} +#endif + +static void f2fs_verity_work(struct work_struct *work) { struct bio_post_read_ctx *ctx = container_of(work, struct bio_post_read_ctx, work); + struct bio *bio = ctx->bio; +#ifdef CONFIG_F2FS_FS_COMPRESSION + unsigned int enabled_steps = ctx->enabled_steps; +#endif - fscrypt_decrypt_bio(ctx->bio); + /* + * fsverity_verify_bio() may call readpages() again, and while verity + * will be disabled for this, decryption may still be needed, resulting + * in another bio_post_read_ctx being allocated. So to prevent + * deadlocks we need to release the current ctx to the mempool first. + * This assumes that verity is the last post-read step. + */ + mempool_free(ctx, bio_post_read_ctx_pool); + bio->bi_private = NULL; + +#ifdef CONFIG_F2FS_FS_COMPRESSION + /* previous step is decompression */ + if (enabled_steps & (1 << STEP_DECOMPRESS)) { + f2fs_verify_bio(bio); + f2fs_release_read_bio(bio); + return; + } +#endif - bio_post_read_processing(ctx); + fsverity_verify_bio(bio); + __f2fs_read_end_io(bio, false, false); } -static void verity_work(struct work_struct *work) +static void f2fs_post_read_work(struct work_struct *work) { struct bio_post_read_ctx *ctx = container_of(work, struct bio_post_read_ctx, work); - fsverity_verify_bio(ctx->bio); + if (ctx->enabled_steps & (1 << STEP_DECRYPT)) + f2fs_decrypt_work(ctx); + + if (ctx->enabled_steps & (1 << STEP_DECOMPRESS)) + f2fs_decompress_work(ctx); - bio_post_read_processing(ctx); + if (ctx->enabled_steps & (1 << STEP_VERITY)) { + INIT_WORK(&ctx->work, f2fs_verity_work); + fsverity_enqueue_verify_work(&ctx->work); + return; + } + + __f2fs_read_end_io(ctx->bio, + ctx->enabled_steps & (1 << STEP_DECOMPRESS), false); +} + +static void f2fs_enqueue_post_read_work(struct f2fs_sb_info *sbi, + struct work_struct *work) +{ + queue_work(sbi->post_read_wq, work); } static void bio_post_read_processing(struct bio_post_read_ctx *ctx) @@ -140,31 +292,26 @@ static void bio_post_read_processing(struct bio_post_read_ctx *ctx) * verity may require reading metadata pages that need decryption, and * we shouldn't recurse to the same workqueue. */ - switch (++ctx->cur_step) { - case STEP_DECRYPT: - if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { - INIT_WORK(&ctx->work, decrypt_work); - fscrypt_enqueue_decrypt_work(&ctx->work); - return; - } - ctx->cur_step++; - /* fall-through */ - case STEP_VERITY: - if (ctx->enabled_steps & (1 << STEP_VERITY)) { - INIT_WORK(&ctx->work, verity_work); - fsverity_enqueue_verify_work(&ctx->work); - return; - } - ctx->cur_step++; - /* fall-through */ - default: - __read_end_io(ctx->bio); + + if (ctx->enabled_steps & (1 << STEP_DECRYPT) || + ctx->enabled_steps & (1 << STEP_DECOMPRESS)) { + INIT_WORK(&ctx->work, f2fs_post_read_work); + f2fs_enqueue_post_read_work(ctx->sbi, &ctx->work); + return; } + + if (ctx->enabled_steps & (1 << STEP_VERITY)) { + INIT_WORK(&ctx->work, f2fs_verity_work); + fsverity_enqueue_verify_work(&ctx->work); + return; + } + + __f2fs_read_end_io(ctx->bio, false, false); } static bool f2fs_bio_post_read_required(struct bio *bio) { - return bio->bi_private && !bio->bi_status; + return bio->bi_private; } static void f2fs_read_end_io(struct bio *bio) @@ -180,7 +327,6 @@ static void f2fs_read_end_io(struct bio *bio) if (f2fs_bio_post_read_required(bio)) { struct bio_post_read_ctx *ctx = bio->bi_private; - ctx->cur_step = STEP_INITIAL; bio_post_read_processing(ctx); return; } @@ -192,7 +338,7 @@ static void f2fs_read_end_io(struct bio *bio) bio->bi_iter.bi_size); } - __read_end_io(bio); + __f2fs_read_end_io(bio, false, false); } static void f2fs_write_end_io(struct bio *bio) @@ -223,6 +369,13 @@ static void f2fs_write_end_io(struct bio *bio) fscrypt_finalize_bounce_page(&page); +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_is_compressed_page(page)) { + f2fs_compress_write_end_io(bio, page); + continue; + } +#endif + if (unlikely(bio->bi_status)) { mapping_set_error(page->mapping, -EIO); if (type == F2FS_WB_CP_DATA) @@ -245,9 +398,6 @@ static void f2fs_write_end_io(struct bio *bio) bio_put(bio); } -/* - * Return true, if pre_bio's bdev is same as its target device. - */ struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi, block_t blk_addr, struct bio *bio) { @@ -284,6 +434,9 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr) return 0; } +/* + * Return true, if pre_bio's bdev is same as its target device. + */ static bool __same_bdev(struct f2fs_sb_info *sbi, block_t blk_addr, struct bio *bio) { @@ -291,9 +444,6 @@ static bool __same_bdev(struct f2fs_sb_info *sbi, return bio->bi_disk == b->bd_disk && bio->bi_partno == b->bd_partno; } -/* - * Low-level block read/write IO operations. - */ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages) { struct f2fs_sb_info *sbi = fio->sbi; @@ -317,6 +467,37 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages) return bio; } +static void f2fs_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, + pgoff_t first_idx, + const struct f2fs_io_info *fio, + gfp_t gfp_mask) +{ + /* + * The f2fs garbage collector sets ->encrypted_page when it wants to + * read/write raw data without encryption. + */ + if (!fio || !fio->encrypted_page) + fscrypt_set_bio_crypt_ctx(bio, inode, first_idx, gfp_mask); + else if (fscrypt_inode_should_skip_dm_default_key(inode)) + bio_set_skip_dm_default_key(bio); +} + +static bool f2fs_crypt_mergeable_bio(struct bio *bio, const struct inode *inode, + pgoff_t next_idx, + const struct f2fs_io_info *fio) +{ + /* + * The f2fs garbage collector sets ->encrypted_page when it wants to + * read/write raw data without encryption. + */ + if (fio && fio->encrypted_page) + return !bio_has_crypt_ctx(bio) && + (bio_should_skip_dm_default_key(bio) == + fscrypt_inode_should_skip_dm_default_key(inode)); + + return fscrypt_mergeable_bio(bio, inode, next_idx); +} + static inline void __submit_bio(struct f2fs_sb_info *sbi, struct bio *bio, enum page_type type) { @@ -326,7 +507,7 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi, if (type != DATA && type != NODE) goto submit_io; - if (test_opt(sbi, LFS) && current->plug) + if (f2fs_lfs_mode(sbi) && current->plug) blk_finish_plug(current->plug); if (F2FS_IO_ALIGNED(sbi)) @@ -393,6 +574,34 @@ static void __f2fs_submit_read_bio(struct f2fs_sb_info *sbi, __submit_bio(sbi, bio, type); } +void f2fs_submit_bio(struct f2fs_sb_info *sbi, + struct bio *bio, enum page_type type) +{ + __submit_bio(sbi, bio, type); +} + +static void __attach_data_io_flag(struct f2fs_io_info *fio) +{ + struct f2fs_sb_info *sbi = fio->sbi; + unsigned int temp_mask = (1 << NR_TEMP_TYPE) - 1; + unsigned int fua_flag = sbi->data_io_flag & temp_mask; + unsigned int meta_flag = (sbi->data_io_flag >> NR_TEMP_TYPE) & + temp_mask; + /* + * data io flag bits per temp: + * REQ_META | REQ_FUA | + * 5 | 4 | 3 | 2 | 1 | 0 | + * Cold | Warm | Hot | Cold | Warm | Hot | + */ + if (fio->type != DATA) + return; + + if ((1 << fio->temp) & meta_flag) + fio->op_flags |= REQ_META; + if ((1 << fio->temp) & fua_flag) + fio->op_flags |= REQ_FUA; +} + static void __submit_merged_bio(struct f2fs_bio_info *io) { struct f2fs_io_info *fio = &io->fio; @@ -400,6 +609,7 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) if (!io->bio) return; + __attach_data_io_flag(fio); bio_set_op_attrs(io->bio, fio->op, fio->op_flags); if (is_read_io(fio->op)) @@ -415,7 +625,6 @@ static bool __has_merged_page(struct bio *bio, struct inode *inode, struct page *page, nid_t ino) { struct bio_vec *bvec; - struct page *target; int i; if (!bio) @@ -425,10 +634,18 @@ static bool __has_merged_page(struct bio *bio, struct inode *inode, return true; bio_for_each_segment_all(bvec, bio, i) { + struct page *target = bvec->bv_page; - target = bvec->bv_page; - if (fscrypt_is_bounce_page(target)) + if (fscrypt_is_bounce_page(target)) { target = fscrypt_pagecache_page(target); + if (IS_ERR(target)) + continue; + } + if (f2fs_is_compressed_page(target)) { + target = f2fs_compress_control_page(target); + if (IS_ERR(target)) + continue; + } if (inode && inode == target->mapping->host) return true; @@ -514,7 +731,6 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) struct bio *bio; struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; - struct inode *inode = fio->page->mapping->host; if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr, fio->is_por ? META_POR : (__is_meta_io(fio) ? @@ -527,15 +743,13 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) /* Allocate a new bio */ bio = __bio_alloc(fio, 1); - if (f2fs_may_encrypt_bio(inode, fio)) - fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page)); - fscrypt_set_ice_skip(bio, fio->encrypted_page ? 1 : 0); + f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host, + fio->page->index, fio, GFP_NOIO); if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; } - fio->op_flags |= fio->encrypted_page ? REQ_NOENCRYPT : 0; if (fio->io_wbc && !is_read_io(fio->op)) wbc_account_io(fio->io_wbc, page, PAGE_SIZE); @@ -632,7 +846,8 @@ static int add_ipu_page(struct f2fs_sb_info *sbi, struct bio **bio, found = true; - if (bio_add_page(*bio, page, PAGE_SIZE, 0) == PAGE_SIZE) { + if (bio_add_page(*bio, page, PAGE_SIZE, 0) == + PAGE_SIZE) { ret = 0; break; } @@ -714,10 +929,6 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio) struct bio *bio = *fio->bio; struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; - struct inode *inode; - bool bio_encrypted; - int bi_crypt_skip; - u64 dun; if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr, __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)) @@ -726,27 +937,18 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio) trace_f2fs_submit_page_bio(page, fio); f2fs_trace_ios(fio, 0); - inode = fio->page->mapping->host; - dun = PG_DUN(inode, fio->page); - bi_crypt_skip = fio->encrypted_page ? 1 : 0; - bio_encrypted = f2fs_may_encrypt_bio(inode, fio); - fio->op_flags |= fio->encrypted_page ? REQ_NOENCRYPT : 0; - - if (bio && !page_is_mergeable(fio->sbi, bio, *fio->last_block, - fio->new_blkaddr)) - f2fs_submit_merged_ipu_write(fio->sbi, &bio, NULL); - /* ICE support */ - if (bio && !fscrypt_mergeable_bio(bio, dun, - bio_encrypted, bi_crypt_skip)) { + if (bio && (!page_is_mergeable(fio->sbi, bio, *fio->last_block, + fio->new_blkaddr) || + !f2fs_crypt_mergeable_bio(bio, fio->page->mapping->host, + fio->page->index, fio))) f2fs_submit_merged_ipu_write(fio->sbi, &bio, NULL); - } alloc_new: if (!bio) { bio = __bio_alloc(fio, BIO_MAX_PAGES); + f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host, + fio->page->index, fio, + GFP_NOIO); bio_set_op_attrs(bio, fio->op, fio->op_flags); - if (bio_encrypted) - fscrypt_set_ice_dun(inode, bio, dun); - fscrypt_set_ice_skip(bio, bi_crypt_skip); add_bio_entry(fio->sbi, bio, page, fio->temp); } else { if (add_ipu_page(fio->sbi, &bio, page)) @@ -770,10 +972,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; struct page *bio_page; - struct inode *inode; - bool bio_encrypted; - int bi_crypt_skip; - u64 dun; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -793,26 +991,24 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) verify_fio_blkaddr(fio); - bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; - inode = fio->page->mapping->host; - dun = PG_DUN(inode, fio->page); - bi_crypt_skip = fio->encrypted_page ? 1 : 0; - bio_encrypted = f2fs_may_encrypt_bio(inode, fio); - fio->op_flags |= fio->encrypted_page ? REQ_NOENCRYPT : 0; + if (fio->encrypted_page) + bio_page = fio->encrypted_page; + else if (fio->compressed_page) + bio_page = fio->compressed_page; + else + bio_page = fio->page; /* set submitted = true as a return value */ fio->submitted = true; inc_page_count(sbi, WB_DATA_TYPE(bio_page)); - if (io->bio && !io_is_mergeable(sbi, io->bio, io, fio, - io->last_block_in_bio, fio->new_blkaddr)) + if (io->bio && + (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, + fio->new_blkaddr) || + !f2fs_crypt_mergeable_bio(io->bio, fio->page->mapping->host, + fio->page->index, fio))) __submit_merged_bio(io); - - /* ICE support */ - if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted, bi_crypt_skip)) - __submit_merged_bio(io); - alloc_new: if (io->bio == NULL) { if (F2FS_IO_ALIGNED(sbi) && @@ -823,9 +1019,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) goto skip; } io->bio = __bio_alloc(fio, BIO_MAX_PAGES); - if (bio_encrypted) - fscrypt_set_ice_dun(inode, io->bio, dun); - fscrypt_set_ice_skip(io->bio, bi_crypt_skip); + f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host, + fio->page->index, fio, + GFP_NOIO); io->fio = *fio; } @@ -859,37 +1055,36 @@ static inline bool f2fs_need_verity(const struct inode *inode, pgoff_t idx) static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, unsigned nr_pages, unsigned op_flag, - pgoff_t first_idx) + pgoff_t first_idx, bool for_write) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct bio *bio; struct bio_post_read_ctx *ctx; unsigned int post_read_steps = 0; - bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false); + bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), + for_write); if (!bio) return ERR_PTR(-ENOMEM); + + f2fs_set_bio_crypt_ctx(bio, inode, first_idx, NULL, GFP_NOFS); + f2fs_target_device(sbi, blkaddr, bio); bio->bi_end_io = f2fs_read_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, - (IS_ENCRYPTED(inode) ? - REQ_NOENCRYPT : - op_flag)); + bio_set_op_attrs(bio, REQ_OP_READ, op_flag); - if (f2fs_encrypted_file(inode) && - !fscrypt_using_hardware_encryption(inode)) + if (fscrypt_inode_uses_fs_layer_crypto(inode)) post_read_steps |= 1 << STEP_DECRYPT; - + if (f2fs_compressed_file(inode)) + post_read_steps |= 1 << STEP_DECOMPRESS; if (f2fs_need_verity(inode, first_idx)) post_read_steps |= 1 << STEP_VERITY; if (post_read_steps) { + /* Due to the mempool, this never fails. */ ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS); - if (!ctx) { - bio_put(bio); - return ERR_PTR(-ENOMEM); - } ctx->bio = bio; + ctx->sbi = sbi; ctx->enabled_steps = post_read_steps; bio->bi_private = ctx; } @@ -897,20 +1092,24 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, return bio; } +static void f2fs_release_read_bio(struct bio *bio) +{ + if (bio->bi_private) + mempool_free(bio->bi_private, bio_post_read_ctx_pool); + bio_put(bio); +} + /* This can handle encryption stuffs */ static int f2fs_submit_page_read(struct inode *inode, struct page *page, - block_t blkaddr) + block_t blkaddr, bool for_write) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct bio *bio; - bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0, page->index); + bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0, page->index, for_write); if (IS_ERR(bio)) return PTR_ERR(bio); - if (f2fs_may_encrypt_bio(inode, NULL)) - fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page)); - /* wait for GCed page writeback via META_MAPPING */ f2fs_wait_on_block_writeback(inode, blkaddr); @@ -920,6 +1119,7 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, } ClearPageError(page); inc_page_count(sbi, F2FS_RD_DATA); + f2fs_update_iostat(sbi, FS_DATA_READ_IO, F2FS_BLKSIZE); __f2fs_submit_read_bio(sbi, bio, DATA); return 0; } @@ -979,8 +1179,7 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count) f2fs_wait_on_page_writeback(dn->node_page, NODE, true, true); for (; count > 0; dn->ofs_in_node++) { - block_t blkaddr = datablock_addr(dn->inode, - dn->node_page, dn->ofs_in_node); + block_t blkaddr = f2fs_data_blkaddr(dn); if (blkaddr == NULL_ADDR) { dn->data_blkaddr = NEW_ADDR; __set_data_blkaddr(dn); @@ -1094,7 +1293,7 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index, return page; } - err = f2fs_submit_page_read(inode, page, dn.data_blkaddr); + err = f2fs_submit_page_read(inode, page, dn.data_blkaddr, for_write); if (err) goto put_err; return page; @@ -1232,8 +1431,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) if (err) return err; - dn->data_blkaddr = datablock_addr(dn->inode, - dn->node_page, dn->ofs_in_node); + dn->data_blkaddr = f2fs_data_blkaddr(dn); if (dn->data_blkaddr != NULL_ADDR) goto alloc; @@ -1265,19 +1463,6 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) int err = 0; bool direct_io = iocb->ki_flags & IOCB_DIRECT; - /* convert inline data for Direct I/O*/ - if (direct_io) { - err = f2fs_convert_inline_inode(inode); - if (err) - return err; - } - - if (direct_io && allow_outplace_dio(inode, iocb, from)) - return 0; - - if (is_inode_flag_set(inode, FI_NO_PREALLOC)) - return 0; - map.m_lblk = F2FS_BLK_ALIGN(iocb->ki_pos); map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from)); if (map.m_len > map.m_lblk) @@ -1333,13 +1518,9 @@ void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) } /* - * f2fs_map_blocks() now supported readahead/bmap/rw direct_IO with - * f2fs_map_blocks structure. - * If original data blocks are allocated, then give them to blockdev. - * Otherwise, - * a. preallocate requested block addresses - * b. do not use extent cache for better performance - * c. give the block addresses to blockdev + * f2fs_map_blocks() tries to find or build mapping relationship which + * maps continuous logical blocks to physical blocks, and return such + * info via f2fs_map_blocks structure. */ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int create, int flag) @@ -1367,7 +1548,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, end = pgofs + maxblocks; if (!create && f2fs_lookup_extent_cache(inode, pgofs, &ei)) { - if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO && + if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO && map->m_may_create) goto next_dnode; @@ -1412,7 +1593,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, end_offset = ADDRS_PER_PAGE(dn.node_page, inode); next_block: - blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node); + blkaddr = f2fs_data_blkaddr(&dn); if (__is_valid_data_blkaddr(blkaddr) && !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) { @@ -1422,7 +1603,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, if (__is_valid_data_blkaddr(blkaddr)) { /* use out-place-update for driect IO under LFS mode */ - if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO && + if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO && map->m_may_create) { err = __allocate_data_block(&dn, map->m_seg_type); if (err) @@ -1855,8 +2036,6 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, sector_t last_block_in_file; sector_t block_nr; int ret = 0; - bool bio_encrypted; - u64 dun; block_in_file = (sector_t)page_index(page); last_block = block_in_file + nr_pages; @@ -1920,32 +2099,24 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, * This page will go to BIO. Do we need to send this * BIO off first? */ - if (bio && !page_is_mergeable(F2FS_I_SB(inode), bio, - *last_block_in_bio, block_nr)) { + if (bio && (!page_is_mergeable(F2FS_I_SB(inode), bio, + *last_block_in_bio, block_nr) || + !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) { submit_and_realloc: __f2fs_submit_read_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } - dun = PG_DUN(inode, page); - bio_encrypted = f2fs_may_encrypt_bio(inode, NULL); - if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted, 0)) { - __submit_bio(F2FS_I_SB(inode), bio, DATA); - bio = NULL; - } - if (bio == NULL) { bio = f2fs_grab_read_bio(inode, block_nr, nr_pages, - is_readahead ? REQ_RAHEAD : 0, page->index); + is_readahead ? REQ_RAHEAD : 0, page->index, + false); if (IS_ERR(bio)) { ret = PTR_ERR(bio); bio = NULL; goto out; } - if (bio_encrypted) - fscrypt_set_ice_dun(inode, bio, dun); } - /* * If the page is under writeback, we need to wait for * its completion to see the correct decrypted data. @@ -1956,6 +2127,7 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, goto submit_and_realloc; inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA); + f2fs_update_iostat(F2FS_I_SB(inode), FS_DATA_READ_IO, F2FS_BLKSIZE); ClearPageError(page); *last_block_in_bio = block_nr; goto out; @@ -1970,6 +2142,147 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, return ret; } +#ifdef CONFIG_F2FS_FS_COMPRESSION +int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, + unsigned nr_pages, sector_t *last_block_in_bio, + bool is_readahead, bool for_write) +{ + struct dnode_of_data dn; + struct inode *inode = cc->inode; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct bio *bio = *bio_ret; + unsigned int start_idx = cc->cluster_idx << cc->log_cluster_size; + sector_t last_block_in_file; + const unsigned blkbits = inode->i_blkbits; + const unsigned blocksize = 1 << blkbits; + struct decompress_io_ctx *dic = NULL; + int i; + int ret = 0; + + f2fs_bug_on(sbi, f2fs_cluster_is_empty(cc)); + + last_block_in_file = (f2fs_readpage_limit(inode) + + blocksize - 1) >> blkbits; + + /* get rid of pages beyond EOF */ + for (i = 0; i < cc->cluster_size; i++) { + struct page *page = cc->rpages[i]; + + if (!page) + continue; + if ((sector_t)page->index >= last_block_in_file) { + zero_user_segment(page, 0, PAGE_SIZE); + if (!PageUptodate(page)) + SetPageUptodate(page); + } else if (!PageUptodate(page)) { + continue; + } + unlock_page(page); + cc->rpages[i] = NULL; + cc->nr_rpages--; + } + + /* we are done since all pages are beyond EOF */ + if (f2fs_cluster_is_empty(cc)) + goto out; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE); + if (ret) + goto out; + + /* cluster was overwritten as normal cluster */ + if (dn.data_blkaddr != COMPRESS_ADDR) + goto out; + + for (i = 1; i < cc->cluster_size; i++) { + block_t blkaddr; + + blkaddr = data_blkaddr(dn.inode, dn.node_page, + dn.ofs_in_node + i); + + if (!__is_valid_data_blkaddr(blkaddr)) + break; + + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) { + ret = -EFAULT; + goto out_put_dnode; + } + cc->nr_cpages++; + } + + /* nothing to decompress */ + if (cc->nr_cpages == 0) { + ret = 0; + goto out_put_dnode; + } + + dic = f2fs_alloc_dic(cc); + if (IS_ERR(dic)) { + ret = PTR_ERR(dic); + goto out_put_dnode; + } + + for (i = 0; i < dic->nr_cpages; i++) { + struct page *page = dic->cpages[i]; + block_t blkaddr; + + blkaddr = data_blkaddr(dn.inode, dn.node_page, + dn.ofs_in_node + i + 1); + + if (bio && (!page_is_mergeable(sbi, bio, + *last_block_in_bio, blkaddr) || + !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) { +submit_and_realloc: + __submit_bio(sbi, bio, DATA); + bio = NULL; + } + + if (!bio) { + bio = f2fs_grab_read_bio(inode, blkaddr, nr_pages, + is_readahead ? REQ_RAHEAD : 0, + page->index, for_write); + if (IS_ERR(bio)) { + ret = PTR_ERR(bio); + bio = NULL; + dic->failed = true; + if (refcount_sub_and_test(dic->nr_cpages - i, + &dic->ref)) + f2fs_decompress_end_io(dic->rpages, + cc->cluster_size, true, + false); + f2fs_free_dic(dic); + f2fs_put_dnode(&dn); + *bio_ret = bio; + return ret; + } + } + + f2fs_wait_on_block_writeback(inode, blkaddr); + + if (bio_add_page(bio, page, blocksize, 0) < blocksize) + goto submit_and_realloc; + + inc_page_count(sbi, F2FS_RD_DATA); + f2fs_update_iostat(sbi, FS_DATA_READ_IO, F2FS_BLKSIZE); + ClearPageError(page); + *last_block_in_bio = blkaddr; + } + + f2fs_put_dnode(&dn); + + *bio_ret = bio; + return 0; + +out_put_dnode: + f2fs_put_dnode(&dn); +out: + f2fs_decompress_end_io(cc->rpages, cc->cluster_size, true, false); + *bio_ret = bio; + return ret; +} +#endif + /* * This function was originally taken from fs/mpage.c, and customized for f2fs. * Major change was from block_size == page_size in f2fs by default. @@ -1979,7 +2292,7 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, * use ->readpage() or do the necessary surgery to decouple ->readpages() * from read-ahead. */ -static int f2fs_mpage_readpages(struct address_space *mapping, +int f2fs_mpage_readpages(struct address_space *mapping, struct list_head *pages, struct page *page, unsigned nr_pages, bool is_readahead) { @@ -1987,6 +2300,19 @@ static int f2fs_mpage_readpages(struct address_space *mapping, sector_t last_block_in_bio = 0; struct inode *inode = mapping->host; struct f2fs_map_blocks map; +#ifdef CONFIG_F2FS_FS_COMPRESSION + struct compress_ctx cc = { + .inode = inode, + .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, + .cluster_size = F2FS_I(inode)->i_cluster_size, + .cluster_idx = NULL_CLUSTER, + .rpages = NULL, + .cpages = NULL, + .nr_rpages = 0, + .nr_cpages = 0, + }; +#endif + unsigned max_nr_pages = nr_pages; int ret = 0; map.m_pblk = 0; @@ -2010,9 +2336,41 @@ static int f2fs_mpage_readpages(struct address_space *mapping, goto next_page; } - ret = f2fs_read_single_page(inode, page, nr_pages, &map, &bio, - &last_block_in_bio, is_readahead); +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_compressed_file(inode)) { + /* there are remained comressed pages, submit them */ + if (!f2fs_cluster_can_merge_page(&cc, page->index)) { + ret = f2fs_read_multi_pages(&cc, &bio, + max_nr_pages, + &last_block_in_bio, + is_readahead, false); + f2fs_destroy_compress_ctx(&cc); + if (ret) + goto set_error_page; + } + ret = f2fs_is_compressed_cluster(inode, page->index); + if (ret < 0) + goto set_error_page; + else if (!ret) + goto read_single_page; + + ret = f2fs_init_compress_ctx(&cc); + if (ret) + goto set_error_page; + + f2fs_compress_ctx_add_page(&cc, page); + + goto next_page; + } +read_single_page: +#endif + + ret = f2fs_read_single_page(inode, page, max_nr_pages, &map, + &bio, &last_block_in_bio, is_readahead); if (ret) { +#ifdef CONFIG_F2FS_FS_COMPRESSION +set_error_page: +#endif SetPageError(page); zero_user_segment(page, 0, PAGE_SIZE); unlock_page(page); @@ -2020,6 +2378,19 @@ static int f2fs_mpage_readpages(struct address_space *mapping, next_page: if (pages) put_page(page); + +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_compressed_file(inode)) { + /* last page */ + if (nr_pages == 1 && !f2fs_cluster_is_empty(&cc)) { + ret = f2fs_read_multi_pages(&cc, &bio, + max_nr_pages, + &last_block_in_bio, + is_readahead, false); + f2fs_destroy_compress_ctx(&cc); + } + } +#endif } BUG_ON(pages && !list_empty(pages)); if (bio) @@ -2034,6 +2405,11 @@ static int f2fs_read_data_page(struct file *file, struct page *page) trace_f2fs_readpage(page, DATA); + if (!f2fs_is_compress_backend_ready(inode)) { + unlock_page(page); + return -EOPNOTSUPP; + } + /* If the file has inline data, try to read it directly */ if (f2fs_has_inline_data(inode)) ret = f2fs_read_inline_data(inode, page); @@ -2052,6 +2428,9 @@ static int f2fs_read_data_pages(struct file *file, trace_f2fs_readpages(inode, page, nr_pages); + if (!f2fs_is_compress_backend_ready(inode)) + return 0; + /* If the file has inline data, skip readpages */ if (f2fs_has_inline_data(inode)) return 0; @@ -2059,30 +2438,31 @@ static int f2fs_read_data_pages(struct file *file, return f2fs_mpage_readpages(mapping, pages, NULL, nr_pages, true); } -static int encrypt_one_page(struct f2fs_io_info *fio) +int f2fs_encrypt_one_page(struct f2fs_io_info *fio) { struct inode *inode = fio->page->mapping->host; - struct page *mpage; + struct page *mpage, *page; gfp_t gfp_flags = GFP_NOFS; if (!f2fs_encrypted_file(inode)) return 0; + page = fio->compressed_page ? fio->compressed_page : fio->page; + /* wait for GCed page writeback via META_MAPPING */ f2fs_wait_on_block_writeback(inode, fio->old_blkaddr); -retry_encrypt: - if (fscrypt_using_hardware_encryption(inode)) + if (fscrypt_inode_uses_inline_crypto(inode)) return 0; - fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(fio->page, - PAGE_SIZE, 0, - gfp_flags); +retry_encrypt: + fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(page, + PAGE_SIZE, 0, gfp_flags); if (IS_ERR(fio->encrypted_page)) { /* flush pending IOs and wait for a while in the ENOMEM case */ if (PTR_ERR(fio->encrypted_page) == -ENOMEM) { f2fs_flush_merged_writes(fio->sbi); - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); gfp_flags |= __GFP_NOFAIL; goto retry_encrypt; } @@ -2153,7 +2533,7 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - if (test_opt(sbi, LFS)) + if (f2fs_lfs_mode(sbi)) return true; if (S_ISDIR(inode->i_mode)) return true; @@ -2237,7 +2617,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) if (ipu_force || (__is_valid_data_blkaddr(fio->old_blkaddr) && need_inplace_update(fio))) { - err = encrypt_one_page(fio); + err = f2fs_encrypt_one_page(fio); if (err) goto out_writepage; @@ -2248,7 +2628,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) f2fs_unlock_op(fio->sbi); err = f2fs_inplace_write_data(fio); if (err) { - if (f2fs_encrypted_file(inode)) + if (fscrypt_inode_uses_fs_layer_crypto(inode)) fscrypt_finalize_bounce_page(&fio->encrypted_page); if (PageWriteback(page)) end_page_writeback(page); @@ -2273,13 +2653,16 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) fio->version = ni.version; - err = encrypt_one_page(fio); + err = f2fs_encrypt_one_page(fio); if (err) goto out_writepage; set_page_writeback(page); ClearPageError(page); + if (fio->compr_blocks && fio->old_blkaddr == COMPRESS_ADDR) + f2fs_i_compr_blocks_update(inode, fio->compr_blocks - 1, false); + /* LFS mode write path */ f2fs_outplace_write_data(&dn, fio); trace_f2fs_do_write_data_page(page, OPU); @@ -2294,16 +2677,17 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) return err; } -static int __write_data_page(struct page *page, bool *submitted, +int f2fs_write_single_data_page(struct page *page, int *submitted, struct bio **bio, sector_t *last_block, struct writeback_control *wbc, - enum iostat_type io_type) + enum iostat_type io_type, + int compr_blocks) { struct inode *inode = page->mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); loff_t i_size = i_size_read(inode); - const pgoff_t end_index = ((unsigned long long) i_size) + const pgoff_t end_index = ((unsigned long long)i_size) >> PAGE_SHIFT; loff_t psize = (loff_t)(page->index + 1) << PAGE_SHIFT; unsigned offset = 0; @@ -2319,6 +2703,7 @@ static int __write_data_page(struct page *page, bool *submitted, .page = page, .encrypted_page = NULL, .submitted = false, + .compr_blocks = compr_blocks, .need_lock = LOCK_RETRY, .io_type = io_type, .io_wbc = wbc, @@ -2343,7 +2728,9 @@ static int __write_data_page(struct page *page, bool *submitted, if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) goto redirty_out; - if (page->index < end_index || f2fs_verity_in_progress(inode)) + if (page->index < end_index || + f2fs_verity_in_progress(inode) || + compr_blocks) goto write; /* @@ -2364,8 +2751,8 @@ static int __write_data_page(struct page *page, bool *submitted, f2fs_available_free_memory(sbi, BASE_CHECK)))) goto redirty_out; - /* Dentry blocks are controlled by checkpoint */ - if (S_ISDIR(inode->i_mode)) { + /* Dentry/quota blocks are controlled by checkpoint */ + if (S_ISDIR(inode->i_mode) || IS_NOQUOTA(inode)) { fio.need_lock = LOCK_DONE; err = f2fs_do_write_data_page(&fio); goto done; @@ -2396,10 +2783,10 @@ static int __write_data_page(struct page *page, bool *submitted, if (err) { file_set_keep_isize(inode); } else { - down_write(&F2FS_I(inode)->i_sem); + spin_lock(&F2FS_I(inode)->i_size_lock); if (F2FS_I(inode)->last_disk_size < psize) F2FS_I(inode)->last_disk_size = psize; - up_write(&F2FS_I(inode)->i_sem); + spin_unlock(&F2FS_I(inode)->i_size_lock); } done: @@ -2419,7 +2806,6 @@ static int __write_data_page(struct page *page, bool *submitted, f2fs_remove_dirty_inode(inode); submitted = NULL; } - unlock_page(page); if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode) && !F2FS_I(inode)->cp_task) @@ -2432,7 +2818,7 @@ static int __write_data_page(struct page *page, bool *submitted, } if (submitted) - *submitted = fio.submitted; + *submitted = fio.submitted ? 1 : 0; return 0; @@ -2453,7 +2839,23 @@ static int __write_data_page(struct page *page, bool *submitted, static int f2fs_write_data_page(struct page *page, struct writeback_control *wbc) { - return __write_data_page(page, NULL, NULL, NULL, wbc, FS_DATA_IO); +#ifdef CONFIG_F2FS_FS_COMPRESSION + struct inode *inode = page->mapping->host; + + if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) + goto out; + + if (f2fs_compressed_file(inode)) { + if (f2fs_is_compressed_cluster(inode, page->index)) { + redirty_page_for_writepage(wbc, page); + return AOP_WRITEPAGE_ACTIVATE; + } + } +out: +#endif + + return f2fs_write_single_data_page(page, NULL, NULL, NULL, + wbc, FS_DATA_IO, 0); } /* @@ -2466,11 +2868,27 @@ static int f2fs_write_cache_pages(struct address_space *mapping, enum iostat_type io_type) { int ret = 0; - int done = 0; + int done = 0, retry = 0; struct pagevec pvec; struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); struct bio *bio = NULL; sector_t last_block; +#ifdef CONFIG_F2FS_FS_COMPRESSION + struct inode *inode = mapping->host; + struct compress_ctx cc = { + .inode = inode, + .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, + .cluster_size = F2FS_I(inode)->i_cluster_size, + .cluster_idx = NULL_CLUSTER, + .rpages = NULL, + .nr_rpages = 0, + .cpages = NULL, + .rbuf = NULL, + .cbuf = NULL, + .rlen = PAGE_SIZE * F2FS_I(inode)->i_cluster_size, + .private = NULL, + }; +#endif int nr_pages; pgoff_t uninitialized_var(writeback_index); pgoff_t index; @@ -2480,6 +2898,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping, int range_whole = 0; int tag; int nwritten = 0; + int submitted = 0; + int i; pagevec_init(&pvec, 0); @@ -2509,12 +2929,11 @@ static int f2fs_write_cache_pages(struct address_space *mapping, else tag = PAGECACHE_TAG_DIRTY; retry: + retry = 0; if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) tag_pages_for_writeback(mapping, index, end); done_index = index; - while (!done && (index <= end)) { - int i; - + while (!done && !retry && (index <= end)) { nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end, tag); if (nr_pages == 0) @@ -2522,15 +2941,62 @@ static int f2fs_write_cache_pages(struct address_space *mapping, for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; - bool submitted = false; + bool need_readd; +readd: + need_readd = false; +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_compressed_file(inode)) { + ret = f2fs_init_compress_ctx(&cc); + if (ret) { + done = 1; + break; + } + + if (!f2fs_cluster_can_merge_page(&cc, + page->index)) { + ret = f2fs_write_multi_pages(&cc, + &submitted, wbc, io_type); + if (!ret) + need_readd = true; + goto result; + } + if (unlikely(f2fs_cp_error(sbi))) + goto lock_page; + + if (f2fs_cluster_is_empty(&cc)) { + void *fsdata = NULL; + struct page *pagep; + int ret2; + + ret2 = f2fs_prepare_compress_overwrite( + inode, &pagep, + page->index, &fsdata); + if (ret2 < 0) { + ret = ret2; + done = 1; + break; + } else if (ret2 && + !f2fs_compress_write_end(inode, + fsdata, page->index, + 1)) { + retry = 1; + break; + } + } else { + goto lock_page; + } + } +#endif /* give a priority to WB_SYNC threads */ if (atomic_read(&sbi->wb_sync_req[DATA]) && wbc->sync_mode == WB_SYNC_NONE) { done = 1; break; } - +#ifdef CONFIG_F2FS_FS_COMPRESSION +lock_page: +#endif done_index = page->index; retry_write: lock_page(page); @@ -2557,45 +3023,71 @@ static int f2fs_write_cache_pages(struct address_space *mapping, if (!clear_page_dirty_for_io(page)) goto continue_unlock; - ret = __write_data_page(page, &submitted, &bio, - &last_block, wbc, io_type); +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_compressed_file(inode)) { + get_page(page); + f2fs_compress_ctx_add_page(&cc, page); + continue; + } +#endif + ret = f2fs_write_single_data_page(page, &submitted, + &bio, &last_block, wbc, io_type, 0); + if (ret == AOP_WRITEPAGE_ACTIVATE) + unlock_page(page); +#ifdef CONFIG_F2FS_FS_COMPRESSION +result: +#endif + nwritten += submitted; + wbc->nr_to_write -= submitted; + if (unlikely(ret)) { /* * keep nr_to_write, since vfs uses this to * get # of written pages. */ if (ret == AOP_WRITEPAGE_ACTIVATE) { - unlock_page(page); ret = 0; - continue; + goto next; } else if (ret == -EAGAIN) { ret = 0; if (wbc->sync_mode == WB_SYNC_ALL) { cond_resched(); congestion_wait(BLK_RW_ASYNC, - HZ/50); + DEFAULT_IO_TIMEOUT); goto retry_write; } - continue; + goto next; } done_index = page->index + 1; done = 1; break; - } else if (submitted) { - nwritten++; } - if (--wbc->nr_to_write <= 0 && + if (wbc->nr_to_write <= 0 && wbc->sync_mode == WB_SYNC_NONE) { done = 1; break; } +next: + if (need_readd) + goto readd; } pagevec_release(&pvec); cond_resched(); } - - if (!cycled && !done) { +#ifdef CONFIG_F2FS_FS_COMPRESSION + /* flush remained pages in compress cluster */ + if (f2fs_compressed_file(inode) && !f2fs_cluster_is_empty(&cc)) { + ret = f2fs_write_multi_pages(&cc, &submitted, wbc, io_type); + nwritten += submitted; + wbc->nr_to_write -= submitted; + if (ret) { + done = 1; + retry = 0; + } + } +#endif + if ((!cycled && !done) || retry) { cycled = 1; index = 0; end = writeback_index - 1; @@ -2617,13 +3109,17 @@ static int f2fs_write_cache_pages(struct address_space *mapping, static inline bool __should_serialize_io(struct inode *inode, struct writeback_control *wbc) { + /* to avoid deadlock in path of data flush */ + if (F2FS_I(inode)->cp_task) + return false; + if (!S_ISREG(inode->i_mode)) return false; if (IS_NOQUOTA(inode)) return false; - /* to avoid deadlock in path of data flush */ - if (F2FS_I(inode)->cp_task) - return false; + + if (f2fs_compressed_file(inode)) + return true; if (wbc->sync_mode != WB_SYNC_ALL) return true; if (get_dirty_pages(inode) >= SM_I(F2FS_I_SB(inode))->min_seq_blocks) @@ -2714,14 +3210,16 @@ static void f2fs_write_failed(struct address_space *mapping, loff_t to) struct inode *inode = mapping->host; loff_t i_size = i_size_read(inode); + if (IS_NOQUOTA(inode)) + return; + /* In the fs-verity case, f2fs_end_enable_verity() does the truncate */ if (to > i_size && !f2fs_verity_in_progress(inode)) { down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); down_write(&F2FS_I(inode)->i_mmap_sem); truncate_pagecache(inode, i_size); - if (!IS_NOQUOTA(inode)) - f2fs_truncate_blocks(inode, i_size, true); + f2fs_truncate_blocks(inode, i_size, true); up_write(&F2FS_I(inode)->i_mmap_sem); up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); @@ -2761,6 +3259,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, __do_map_lock(sbi, flag, true); locked = true; } + restart: /* check inline_data */ ipage = f2fs_get_node_page(sbi, inode->i_ino); @@ -2861,6 +3360,24 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, if (err) goto fail; } + +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_compressed_file(inode)) { + int ret; + + *fsdata = NULL; + + ret = f2fs_prepare_compress_overwrite(inode, pagep, + index, fsdata); + if (ret < 0) { + err = ret; + goto fail; + } else if (ret) { + return 0; + } + } +#endif + repeat: /* * Do not use grab_cache_page_write_begin() to avoid deadlock due to @@ -2873,6 +3390,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, goto fail; } + /* TODO: cluster can be compressed due to race with .writepage */ + *pagep = page; err = prepare_write_begin(sbi, page, pos, len, @@ -2912,7 +3431,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, err = -EFSCORRUPTED; goto fail; } - err = f2fs_submit_page_read(inode, page, blkaddr); + err = f2fs_submit_page_read(inode, page, blkaddr, true); if (err) goto fail; @@ -2957,6 +3476,16 @@ static int f2fs_write_end(struct file *file, else SetPageUptodate(page); } + +#ifdef CONFIG_F2FS_FS_COMPRESSION + /* overwrite compressed file */ + if (f2fs_compressed_file(inode) && fsdata) { + f2fs_compress_write_end(inode, fsdata, page->index, copied); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); + return copied; + } +#endif + if (!copied) goto unlock_out; @@ -3106,7 +3635,8 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) err = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, rw == WRITE ? get_data_block_dio_write : get_data_block_dio, NULL, f2fs_dio_submit_bio, - DIO_LOCKING | DIO_SKIP_HOLES); + rw == WRITE ? DIO_LOCKING | DIO_SKIP_HOLES : + DIO_SKIP_HOLES); if (do_opu) up_read(&fi->i_gc_rwsem[READ]); @@ -3124,6 +3654,9 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) } else if (err < 0) { f2fs_write_failed(mapping, offset + count); } + } else { + if (err > 0) + f2fs_update_iostat(sbi, APP_DIRECT_READ_IO, err); } out: if (trace_android_fs_dataread_start_enabled() && @@ -3285,7 +3818,8 @@ int f2fs_migrate_page(struct address_space *mapping, #ifdef CONFIG_SWAP /* Copied from generic_swapfile_activate() to check any holes */ -static int check_swap_activate(struct file *swap_file, unsigned int max) +static int check_swap_activate(struct swap_info_struct *sis, + struct file *swap_file, sector_t *span) { struct address_space *mapping = swap_file->f_mapping; struct inode *inode = mapping->host; @@ -3296,6 +3830,8 @@ static int check_swap_activate(struct file *swap_file, unsigned int max) sector_t last_block; sector_t lowest_block = -1; sector_t highest_block = 0; + int nr_extents = 0; + int ret; blkbits = inode->i_blkbits; blocks_per_page = PAGE_SIZE >> blkbits; @@ -3307,7 +3843,8 @@ static int check_swap_activate(struct file *swap_file, unsigned int max) probe_block = 0; page_no = 0; last_block = i_size_read(inode) >> blkbits; - while ((probe_block + blocks_per_page) <= last_block && page_no < max) { + while ((probe_block + blocks_per_page) <= last_block && + page_no < sis->max) { unsigned block_in_page; sector_t first_block; @@ -3347,13 +3884,27 @@ static int check_swap_activate(struct file *swap_file, unsigned int max) highest_block = first_block; } + /* + * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks + */ + ret = add_swap_extent(sis, page_no, 1, first_block); + if (ret < 0) + goto out; + nr_extents += ret; page_no++; probe_block += blocks_per_page; reprobe: continue; } - return 0; - + ret = nr_extents; + *span = 1 + highest_block - lowest_block; + if (page_no == 0) + page_no = 1; /* force Empty message */ + sis->max = page_no; + sis->pages = page_no - 1; + sis->highest_bit = page_no - 1; +out: + return ret; bad_bmap: pr_err("swapon: swapfile has holes\n"); return -EINVAL; @@ -3375,14 +3926,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file, if (ret) return ret; - ret = check_swap_activate(file, sis->max); - if (ret) + if (f2fs_disable_compressed_file(inode)) + return -EINVAL; + + ret = check_swap_activate(sis, file, span); + if (ret < 0) return ret; set_inode_flag(inode, FI_PIN_FILE); f2fs_precache_extents(inode); f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); - return 0; + return ret; } static void f2fs_swap_deactivate(struct file *file) @@ -3459,16 +4013,37 @@ void f2fs_destroy_post_read_processing(void) kmem_cache_destroy(bio_post_read_ctx_cache); } +int f2fs_init_post_read_wq(struct f2fs_sb_info *sbi) +{ + if (!f2fs_sb_has_encrypt(sbi) && + !f2fs_sb_has_verity(sbi) && + !f2fs_sb_has_compression(sbi)) + return 0; + + sbi->post_read_wq = alloc_workqueue("f2fs_post_read_wq", + WQ_UNBOUND | WQ_HIGHPRI, + num_online_cpus()); + if (!sbi->post_read_wq) + return -ENOMEM; + return 0; +} + +void f2fs_destroy_post_read_wq(struct f2fs_sb_info *sbi) +{ + if (sbi->post_read_wq) + destroy_workqueue(sbi->post_read_wq); +} + int __init f2fs_init_bio_entry_cache(void) { - bio_entry_slab = f2fs_kmem_cache_create("bio_entry_slab", + bio_entry_slab = f2fs_kmem_cache_create("f2fs_bio_entry_slab", sizeof(struct bio_entry)); if (!bio_entry_slab) return -ENOMEM; return 0; } -void __exit f2fs_destroy_bio_entry_cache(void) +void f2fs_destroy_bio_entry_cache(void) { kmem_cache_destroy(bio_entry_slab); } diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 244c5bb23fe2dc8fa75067a2db0d8ed65697d6d4..05e9ad91167ed793b3417d92ce9e518af9b3a8d1 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -21,9 +21,45 @@ #include "gc.h" static LIST_HEAD(f2fs_stat_list); -static struct dentry *f2fs_debugfs_root; static DEFINE_MUTEX(f2fs_stat_mutex); +#ifdef CONFIG_DEBUG_FS +static struct dentry *f2fs_debugfs_root; +#endif + +/* + * This function calculates BDF of every segments + */ +void f2fs_update_sit_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_stat_info *si = F2FS_STAT(sbi); + unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; + unsigned long long bimodal, dist; + unsigned int segno, vblocks; + int ndirty = 0; + + bimodal = 0; + total_vblocks = 0; + blks_per_sec = BLKS_PER_SEC(sbi); + hblks_per_sec = blks_per_sec / 2; + for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { + vblocks = get_valid_blocks(sbi, segno, true); + dist = abs(vblocks - hblks_per_sec); + bimodal += dist * dist; + + if (vblocks > 0 && vblocks < blks_per_sec) { + total_vblocks += vblocks; + ndirty++; + } + } + dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100); + si->bimodal = div64_u64(bimodal, dist); + if (si->dirty_count) + si->avg_vblocks = div_u64(total_vblocks, ndirty); + else + si->avg_vblocks = 0; +} +#ifdef CONFIG_DEBUG_FS static void update_general_status(struct f2fs_sb_info *sbi) { struct f2fs_stat_info *si = F2FS_STAT(sbi); @@ -56,7 +92,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->nquota_files = sbi->nquota_files; si->ndirty_all = sbi->ndirty_inode[DIRTY_META]; si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); - si->aw_cnt = atomic_read(&sbi->aw_cnt); + si->aw_cnt = sbi->atomic_files; si->vw_cnt = atomic_read(&sbi->vw_cnt); si->max_aw_cnt = atomic_read(&sbi->max_aw_cnt); si->max_vw_cnt = atomic_read(&sbi->max_vw_cnt); @@ -94,6 +130,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->inline_xattr = atomic_read(&sbi->inline_xattr); si->inline_inode = atomic_read(&sbi->inline_inode); si->inline_dir = atomic_read(&sbi->inline_dir); + si->compr_inode = atomic_read(&sbi->compr_inode); + si->compr_blocks = atomic_read(&sbi->compr_blocks); si->append = sbi->im[APPEND_INO].ino_num; si->update = sbi->im[UPDATE_INO].ino_num; si->orphans = sbi->im[ORPHAN_INO].ino_num; @@ -114,7 +152,6 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID]; si->avail_nids = NM_I(sbi)->available_nids; si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID]; - si->bg_gc = sbi->bg_gc; si->io_skip_bggc = sbi->io_skip_bggc; si->other_skip_bggc = sbi->other_skip_bggc; si->skipped_atomic_files[BG_GC] = sbi->skipped_atomic_files[BG_GC]; @@ -145,39 +182,6 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->inplace_count = atomic_read(&sbi->inplace_count); } -/* - * This function calculates BDF of every segments - */ -static void update_sit_info(struct f2fs_sb_info *sbi) -{ - struct f2fs_stat_info *si = F2FS_STAT(sbi); - unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; - unsigned long long bimodal, dist; - unsigned int segno, vblocks; - int ndirty = 0; - - bimodal = 0; - total_vblocks = 0; - blks_per_sec = BLKS_PER_SEC(sbi); - hblks_per_sec = blks_per_sec / 2; - for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { - vblocks = get_valid_blocks(sbi, segno, true); - dist = abs(vblocks - hblks_per_sec); - bimodal += dist * dist; - - if (vblocks > 0 && vblocks < blks_per_sec) { - total_vblocks += vblocks; - ndirty++; - } - } - dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100); - si->bimodal = div64_u64(bimodal, dist); - if (si->dirty_count) - si->avg_vblocks = div_u64(total_vblocks, ndirty); - else - si->avg_vblocks = 0; -} - /* * This function calculates memory footprint. */ @@ -297,6 +301,9 @@ static int stat_show(struct seq_file *s, void *v) si->ssa_area_segs, si->main_area_segs); seq_printf(s, "(OverProv:%d Resv:%d)]\n\n", si->overp_segs, si->rsvd_segs); + seq_printf(s, "Current Time Sec: %llu / Mounted Time Sec: %llu\n\n", + ktime_get_boottime_seconds(), + SIT_I(si->sbi)->mounted_time); if (test_opt(si->sbi, DISCARD)) seq_printf(s, "Utilization: %u%% (%u valid blocks, %u discard blocks)\n", si->utilization, si->valid_count, si->discard_blks); @@ -315,6 +322,8 @@ static int stat_show(struct seq_file *s, void *v) si->inline_inode); seq_printf(s, " - Inline_dentry Inode: %u\n", si->inline_dir); + seq_printf(s, " - Compressed Inode: %u, Blocks: %u\n", + si->compr_inode, si->compr_blocks); seq_printf(s, " - Orphan/Append/Update Inode: %u, %u, %u\n", si->orphans, si->append, si->update); seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", @@ -441,7 +450,7 @@ static int stat_show(struct seq_file *s, void *v) si->block_count[LFS], si->segment_count[LFS]); /* segment usage info */ - update_sit_info(si->sbi); + f2fs_update_sit_info(si->sbi); seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n", si->bimodal, si->avg_vblocks); @@ -472,6 +481,7 @@ static const struct file_operations stat_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif int f2fs_build_stats(struct f2fs_sb_info *sbi) { @@ -502,11 +512,12 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) atomic_set(&sbi->inline_xattr, 0); atomic_set(&sbi->inline_inode, 0); atomic_set(&sbi->inline_dir, 0); + atomic_set(&sbi->compr_inode, 0); + atomic_set(&sbi->compr_blocks, 0); atomic_set(&sbi->inplace_count, 0); for (i = META_CP; i < META_MAX; i++) atomic_set(&sbi->meta_count[i], 0); - atomic_set(&sbi->aw_cnt, 0); atomic_set(&sbi->vw_cnt, 0); atomic_set(&sbi->max_aw_cnt, 0); atomic_set(&sbi->max_vw_cnt, 0); @@ -531,14 +542,18 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi) void __init f2fs_create_root_stats(void) { +#ifdef CONFIG_DEBUG_FS f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL); debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, NULL, &stat_fops); +#endif } void f2fs_destroy_root_stats(void) { +#ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(f2fs_debugfs_root); f2fs_debugfs_root = NULL; +#endif } diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index dbb9f5a4d7a6e98d1efcefc8f67dde64842dd8eb..7fd0b08d75189aaa69795f2f67fa9435eb0e5185 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -108,34 +108,52 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir, * Test whether a case-insensitive directory entry matches the filename * being searched for. * + * Only called for encrypted names if the key is available. + * * Returns: 0 if the directory entry matches, more than 0 if it * doesn't match or less than zero on error. */ -int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, - const struct qstr *entry, bool quick) +static int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, + u8 *de_name, size_t de_name_len, bool quick) { - const struct f2fs_sb_info *sbi = F2FS_SB(parent->i_sb); - const struct unicode_map *um = sbi->s_encoding; + const struct super_block *sb = parent->i_sb; + const struct unicode_map *um = sb->s_encoding; + struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len); + struct qstr entry = QSTR_INIT(de_name, de_name_len); int ret; + if (IS_ENCRYPTED(parent)) { + const struct fscrypt_str encrypted_name = + FSTR_INIT(de_name, de_name_len); + + decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL); + if (!decrypted_name.name) + return -ENOMEM; + ret = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name, + &decrypted_name); + if (ret < 0) + goto out; + entry.name = decrypted_name.name; + entry.len = decrypted_name.len; + } + if (quick) - ret = utf8_strncasecmp_folded(um, name, entry); + ret = utf8_strncasecmp_folded(um, name, &entry); else - ret = utf8_strncasecmp(um, name, entry); - + ret = utf8_strncasecmp(um, name, &entry); if (ret < 0) { /* Handle invalid character sequence as either an error * or as an opaque byte sequence. */ - if (f2fs_has_strict_mode(sbi)) - return -EINVAL; - - if (name->len != entry->len) - return 1; - - return !!memcmp(name->name, entry->name, name->len); + if (sb_has_enc_strict_mode(sb)) + ret = -EINVAL; + else if (name->len != entry.len) + ret = 1; + else + ret = !!memcmp(name->name, entry.name, entry.len); } - +out: + kfree(decrypted_name.name); return ret; } @@ -154,7 +172,7 @@ static void f2fs_fname_setup_ci_filename(struct inode *dir, if (!cf_name->name) return; - cf_name->len = utf8_casefold(sbi->s_encoding, + cf_name->len = utf8_casefold(dir->i_sb->s_encoding, iname, cf_name->name, F2FS_NAME_LEN); if ((int)cf_name->len <= 0) { @@ -173,24 +191,24 @@ static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d, { #ifdef CONFIG_UNICODE struct inode *parent = d->inode; - struct f2fs_sb_info *sbi = F2FS_I_SB(parent); - struct qstr entry; + u8 *name; + int len; #endif if (de->hash_code != namehash) return false; #ifdef CONFIG_UNICODE - entry.name = d->filename[bit_pos]; - entry.len = de->name_len; + name = d->filename[bit_pos]; + len = le16_to_cpu(de->name_len); - if (sbi->s_encoding && IS_CASEFOLDED(parent)) { + if (needs_casefold(parent)) { if (cf_str->name) { struct qstr cf = {.name = cf_str->name, .len = cf_str->len}; - return !f2fs_ci_compare(parent, &cf, &entry, true); + return !f2fs_ci_compare(parent, &cf, name, len, true); } - return !f2fs_ci_compare(parent, fname->usr_fname, &entry, + return !f2fs_ci_compare(parent, fname->usr_fname, name, len, false); } #endif @@ -357,8 +375,8 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, int err; #ifdef CONFIG_UNICODE - if (f2fs_has_strict_mode(F2FS_I_SB(dir)) && IS_CASEFOLDED(dir) && - utf8_validate(F2FS_I_SB(dir)->s_encoding, child)) { + if (sb_has_enc_strict_mode(dir->i_sb) && IS_CASEFOLDED(dir) && + utf8_validate(dir->i_sb->s_encoding, child)) { *res_page = ERR_PTR(-EINVAL); return NULL; } @@ -471,7 +489,6 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir, struct page *dpage) { struct page *page; - int dummy_encrypt = DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(dir)); int err; if (is_inode_flag_set(inode, FI_NEW_INODE)) { @@ -498,8 +515,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir, if (err) goto put_error; - if ((IS_ENCRYPTED(dir) || dummy_encrypt) && - f2fs_may_encrypt(inode)) { + if (IS_ENCRYPTED(inode)) { err = fscrypt_inherit_context(dir, inode, page, false); if (err) goto put_error; @@ -578,6 +594,20 @@ int f2fs_room_for_filename(const void *bitmap, int slots, int max_slots) goto next; } +bool f2fs_has_enough_room(struct inode *dir, struct page *ipage, + struct fscrypt_name *fname) +{ + struct f2fs_dentry_ptr d; + unsigned int bit_pos; + int slots = GET_DENTRY_SLOTS(fname_len(fname)); + + make_dentry_ptr_inline(dir, &d, inline_data_addr(dir, ipage)); + + bit_pos = f2fs_room_for_filename(d.bitmap, slots, d.max); + + return bit_pos < d.max; +} + void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, const struct qstr *name, f2fs_hash_t name_hash, unsigned int bit_pos) @@ -602,13 +632,13 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, const struct qstr *orig_name, + f2fs_hash_t dentry_hash, struct inode *inode, nid_t ino, umode_t mode) { unsigned int bit_pos; unsigned int level; unsigned int current_depth; unsigned long bidx, block; - f2fs_hash_t dentry_hash; unsigned int nbucket, nblock; struct page *dentry_page = NULL; struct f2fs_dentry_block *dentry_blk = NULL; @@ -618,7 +648,6 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, level = 0; slots = GET_DENTRY_SLOTS(new_name->len); - dentry_hash = f2fs_dentry_hash(dir, new_name, NULL); current_depth = F2FS_I(dir)->i_current_depth; if (F2FS_I(dir)->chash == dentry_hash) { @@ -704,17 +733,19 @@ int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname, struct inode *inode, nid_t ino, umode_t mode) { struct qstr new_name; + f2fs_hash_t dentry_hash; int err = -EAGAIN; new_name.name = fname_name(fname); new_name.len = fname_len(fname); if (f2fs_has_inline_dentry(dir)) - err = f2fs_add_inline_entry(dir, &new_name, fname->usr_fname, + err = f2fs_add_inline_entry(dir, &new_name, fname, inode, ino, mode); + dentry_hash = f2fs_dentry_hash(dir, &new_name, fname); if (err == -EAGAIN) err = f2fs_add_regular_entry(dir, &new_name, fname->usr_fname, - inode, ino, mode); + dentry_hash, inode, ino, mode); f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); return err; @@ -836,12 +867,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, 0); set_page_dirty(page); - dir->i_ctime = dir->i_mtime = current_time(dir); - f2fs_mark_inode_dirty_sync(dir, false); - - if (inode) - f2fs_drop_nlink(dir, inode); - if (bit_pos == NR_DENTRY_IN_BLOCK && !f2fs_truncate_hole(dir, page->index, page->index + 1)) { f2fs_clear_radix_tree_dirty_tag(page); @@ -853,6 +878,12 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, f2fs_remove_dirty_inode(dir); } f2fs_put_page(page, 1); + + dir->i_ctime = dir->i_mtime = current_time(dir); + f2fs_mark_inode_dirty_sync(dir, false); + + if (inode) + f2fs_drop_nlink(dir, inode); } bool f2fs_empty_dir(struct inode *dir) @@ -987,7 +1018,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) if (IS_ENCRYPTED(inode)) { err = fscrypt_get_encryption_info(inode); - if (err && err != -ENOKEY) + if (err) goto out; err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr); @@ -1063,50 +1094,3 @@ const struct file_operations f2fs_dir_operations = { .compat_ioctl = f2fs_compat_ioctl, #endif }; - -#ifdef CONFIG_UNICODE -static int f2fs_d_compare(const struct dentry *dentry, unsigned int len, - const char *str, const struct qstr *name) -{ - struct qstr qstr = {.name = str, .len = len }; - - if (!IS_CASEFOLDED(dentry->d_parent->d_inode)) { - if (len != name->len) - return -1; - return memcmp(str, name, len); - } - - return f2fs_ci_compare(dentry->d_parent->d_inode, name, &qstr, false); -} - -static int f2fs_d_hash(const struct dentry *dentry, struct qstr *str) -{ - struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - const struct unicode_map *um = sbi->s_encoding; - unsigned char *norm; - int len, ret = 0; - - if (!IS_CASEFOLDED(dentry->d_inode)) - return 0; - - norm = f2fs_kmalloc(sbi, PATH_MAX, GFP_ATOMIC); - if (!norm) - return -ENOMEM; - - len = utf8_casefold(um, str, norm, PATH_MAX); - if (len < 0) { - if (f2fs_has_strict_mode(sbi)) - ret = -EINVAL; - goto out; - } - str->hash = full_name_hash(dentry, norm, len); -out: - kvfree(norm); - return ret; -} - -const struct dentry_operations f2fs_dentry_ops = { - .d_hash = f2fs_d_hash, - .d_compare = f2fs_d_compare, -}; -#endif diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a595f451c6d356b4712bb7be196b7c62552a4037..f55818a8c263ef0f198880b64c9b79413228f6d5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -75,7 +75,6 @@ extern const char *f2fs_fault_name[FAULT_MAX]; /* * For mount options */ -#define F2FS_MOUNT_BG_GC 0x00000001 #define F2FS_MOUNT_DISABLE_ROLL_FORWARD 0x00000002 #define F2FS_MOUNT_DISCARD 0x00000004 #define F2FS_MOUNT_NOHEAP 0x00000008 @@ -89,11 +88,8 @@ extern const char *f2fs_fault_name[FAULT_MAX]; #define F2FS_MOUNT_NOBARRIER 0x00000800 #define F2FS_MOUNT_FASTBOOT 0x00001000 #define F2FS_MOUNT_EXTENT_CACHE 0x00002000 -#define F2FS_MOUNT_FORCE_FG_GC 0x00004000 #define F2FS_MOUNT_DATA_FLUSH 0x00008000 #define F2FS_MOUNT_FAULT_INJECTION 0x00010000 -#define F2FS_MOUNT_ADAPTIVE 0x00020000 -#define F2FS_MOUNT_LFS 0x00040000 #define F2FS_MOUNT_USRQUOTA 0x00080000 #define F2FS_MOUNT_GRPQUOTA 0x00100000 #define F2FS_MOUNT_PRJQUOTA 0x00200000 @@ -101,6 +97,7 @@ extern const char *f2fs_fault_name[FAULT_MAX]; #define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000 #define F2FS_MOUNT_RESERVE_ROOT 0x01000000 #define F2FS_MOUNT_DISABLE_CHECKPOINT 0x02000000 +#define F2FS_MOUNT_NORECOVERY 0x04000000 #define F2FS_OPTION(sbi) ((sbi)->mount_opt) #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) @@ -117,6 +114,8 @@ typedef u32 block_t; /* */ typedef u32 nid_t; +#define COMPRESS_EXT_NUM 16 + struct f2fs_mount_info { unsigned int opt; int write_io_size_bits; /* Write IO size bits */ @@ -137,10 +136,21 @@ struct f2fs_mount_info { int whint_mode; int alloc_mode; /* segment allocation policy */ int fsync_mode; /* fsync policy */ + int fs_mode; /* fs mode: LFS or ADAPTIVE */ + int bggc_mode; /* bggc mode: off, on or sync */ bool test_dummy_encryption; /* test dummy encryption */ +#ifdef CONFIG_FS_ENCRYPTION + bool inlinecrypt; /* inline encryption enabled */ +#endif block_t unusable_cap; /* Amount of space allowed to be * unusable when disabling checkpoint */ + + /* For compression */ + unsigned char compress_algorithm; /* algorithm type */ + unsigned compress_log_size; /* cluster log size */ + unsigned char compress_ext_cnt; /* extension count */ + unsigned char extensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */ }; #define F2FS_FEATURE_ENCRYPT 0x0001 @@ -156,6 +166,7 @@ struct f2fs_mount_info { #define F2FS_FEATURE_VERITY 0x0400 #define F2FS_FEATURE_SB_CHKSUM 0x0800 #define F2FS_FEATURE_CASEFOLD 0x1000 +#define F2FS_FEATURE_COMPRESSION 0x2000 #define __F2FS_HAS_FEATURE(raw_super, mask) \ ((raw_super->feature & cpu_to_le32(mask)) != 0) @@ -323,8 +334,8 @@ struct discard_policy { bool io_aware; /* issue discard in idle time */ bool sync; /* submit discard with REQ_SYNC flag */ bool ordered; /* issue discard by lba order */ + bool timeout; /* discard timeout for put_super */ unsigned int granularity; /* discard granularity */ - int timeout; /* discard timeout for put_super */ }; struct discard_cmd_control { @@ -419,6 +430,7 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal, #define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32) #define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) #define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, __u64) +#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, __u64) #define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY #define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY @@ -548,6 +560,9 @@ enum { #define DEFAULT_RETRY_IO_COUNT 8 /* maximum retry read IO count */ +/* congestion wait timeout value, default: 20ms */ +#define DEFAULT_IO_TIMEOUT (msecs_to_jiffies(20)) + /* maximum retry quota flush count */ #define DEFAULT_RETRY_QUOTA_FLUSH_COUNT 8 @@ -664,6 +679,44 @@ enum { MAX_GC_FAILURE }; +/* used for f2fs_inode_info->flags */ +enum { + FI_NEW_INODE, /* indicate newly allocated inode */ + FI_DIRTY_INODE, /* indicate inode is dirty or not */ + FI_AUTO_RECOVER, /* indicate inode is recoverable */ + FI_DIRTY_DIR, /* indicate directory has dirty pages */ + FI_INC_LINK, /* need to increment i_nlink */ + FI_ACL_MODE, /* indicate acl mode */ + FI_NO_ALLOC, /* should not allocate any blocks */ + FI_FREE_NID, /* free allocated nide */ + FI_NO_EXTENT, /* not to use the extent cache */ + FI_INLINE_XATTR, /* used for inline xattr */ + FI_INLINE_DATA, /* used for inline data*/ + FI_INLINE_DENTRY, /* used for inline dentry */ + FI_APPEND_WRITE, /* inode has appended data */ + FI_UPDATE_WRITE, /* inode has in-place-update data */ + FI_NEED_IPU, /* used for ipu per file */ + FI_ATOMIC_FILE, /* indicate atomic file */ + FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */ + FI_VOLATILE_FILE, /* indicate volatile file */ + FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */ + FI_DROP_CACHE, /* drop dirty page cache */ + FI_DATA_EXIST, /* indicate data exists */ + FI_INLINE_DOTS, /* indicate inline dot dentries */ + FI_DO_DEFRAG, /* indicate defragment is running */ + FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */ + FI_NO_PREALLOC, /* indicate skipped preallocated blocks */ + FI_HOT_DATA, /* indicate file is hot */ + FI_EXTRA_ATTR, /* indicate file has extra attribute */ + FI_PROJ_INHERIT, /* indicate file inherits projectid */ + FI_PIN_FILE, /* indicate file should not be gced */ + FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */ + FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */ + FI_COMPRESSED_FILE, /* indicate file's data can be compressed */ + FI_MMAP_FILE, /* indicate file was mmapped */ + FI_MAX, /* max flag, never be used */ +}; + struct f2fs_inode_info { struct inode vfs_inode; /* serve a vfs inode */ unsigned long i_flags; /* keep an inode flags for ioctl */ @@ -676,7 +729,7 @@ struct f2fs_inode_info { umode_t i_acl_mode; /* keep file acl mode temporarily */ /* Use below internally in f2fs*/ - unsigned long flags; /* use to pass per-file flags */ + unsigned long flags[BITS_TO_LONGS(FI_MAX)]; /* use to pass per-file flags */ struct rw_semaphore i_sem; /* protect fi info */ atomic_t dirty_pages; /* # of dirty pages */ f2fs_hash_t chash; /* hash value of given file name */ @@ -685,6 +738,7 @@ struct f2fs_inode_info { struct task_struct *cp_task; /* separate cp/wb IO stats*/ nid_t i_xattr_nid; /* node id that contains xattrs */ loff_t last_disk_size; /* lastly written file size */ + spinlock_t i_size_lock; /* protect last_disk_size */ #ifdef CONFIG_QUOTA struct dquot *i_dquot[MAXQUOTAS]; @@ -710,6 +764,12 @@ struct f2fs_inode_info { int i_inline_xattr_size; /* inline xattr size */ struct timespec i_crtime; /* inode creation time */ struct timespec i_disk_time[4]; /* inode disk times */ + + /* for file compress */ + u64 i_compr_blocks; /* # of compressed blocks */ + unsigned char i_compress_algorithm; /* algorithm type */ + unsigned char i_log_cluster_size; /* log of cluster size */ + unsigned int i_cluster_size; /* cluster size */ }; static inline void get_extent_info(struct extent_info *ext, @@ -1016,6 +1076,7 @@ enum need_lock_type { enum cp_reason_type { CP_NO_NEEDED, CP_NON_REGULAR, + CP_COMPRESSED, CP_HARDLINK, CP_SB_NEED_CP, CP_WRONG_PINO, @@ -1027,8 +1088,9 @@ enum cp_reason_type { }; enum iostat_type { - APP_DIRECT_IO, /* app direct IOs */ - APP_BUFFERED_IO, /* app buffered IOs */ + /* WRITE IO */ + APP_DIRECT_IO, /* app direct write IOs */ + APP_BUFFERED_IO, /* app buffered write IOs */ APP_WRITE_IO, /* app write IOs */ APP_MAPPED_IO, /* app mapped IOs */ FS_DATA_IO, /* data IOs from kworker/fsync/reclaimer */ @@ -1039,6 +1101,17 @@ enum iostat_type { FS_CP_DATA_IO, /* data IOs from checkpoint */ FS_CP_NODE_IO, /* node IOs from checkpoint */ FS_CP_META_IO, /* meta IOs from checkpoint */ + + /* READ IO */ + APP_DIRECT_READ_IO, /* app direct read IOs */ + APP_BUFFERED_READ_IO, /* app buffered read IOs */ + APP_READ_IO, /* app read IOs */ + APP_MAPPED_READ_IO, /* app mapped read IOs */ + FS_DATA_READ_IO, /* data read IOs */ + FS_NODE_READ_IO, /* node read IOs */ + FS_META_READ_IO, /* meta read IOs */ + + /* other */ FS_DISCARD, /* discard */ NR_IO_TYPE, }; @@ -1054,12 +1127,15 @@ struct f2fs_io_info { block_t old_blkaddr; /* old block address before Cow */ struct page *page; /* page to be written */ struct page *encrypted_page; /* encrypted page */ + struct page *compressed_page; /* compressed page */ struct list_head list; /* serialize IOs */ bool submitted; /* indicate IO submission */ int need_lock; /* indicate we need to lock cp_rwsem */ bool in_list; /* indicate fio is in io_list */ bool is_por; /* indicate IO is from recovery or not */ bool retry; /* need to reallocate block address */ + int compr_blocks; /* # of compressed block addresses */ + bool encrypted; /* indicate file is encrypted */ enum iostat_type io_type; /* io type */ struct writeback_control *io_wbc; /* writeback control */ struct bio **bio; /* bio for ipu */ @@ -1150,6 +1226,20 @@ enum { GC_URGENT, }; +enum { + BGGC_MODE_ON, /* background gc is on */ + BGGC_MODE_OFF, /* background gc is off */ + BGGC_MODE_SYNC, /* + * background gc is on, migrating blocks + * like foreground gc + */ +}; + +enum { + FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */ + FS_MODE_LFS, /* use lfs allocation only */ +}; + enum { WHINT_MODE_OFF, /* not pass down write hints */ WHINT_MODE_USER, /* try to pass down hints given by users */ @@ -1167,6 +1257,18 @@ enum fsync_mode { FSYNC_MODE_NOBARRIER, /* fsync behaves nobarrier based on posix */ }; +/* + * this value is set in page as a private data which indicate that + * the page is atomically written, and it is in inmem_pages list. + */ +#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1) +#define DUMMY_WRITTEN_PAGE ((unsigned long)-2) + +#define IS_ATOMIC_WRITTEN_PAGE(page) \ + (page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE) +#define IS_DUMMY_WRITTEN_PAGE(page) \ + (page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE) + #ifdef CONFIG_FS_ENCRYPTION #define DUMMY_ENCRYPTION_ENABLED(sbi) \ (unlikely(F2FS_OPTION(sbi).test_dummy_encryption)) @@ -1174,6 +1276,79 @@ enum fsync_mode { #define DUMMY_ENCRYPTION_ENABLED(sbi) (0) #endif +/* For compression */ +enum compress_algorithm_type { + COMPRESS_LZO, + COMPRESS_LZ4, + COMPRESS_ZSTD, + COMPRESS_MAX, +}; + +#define COMPRESS_DATA_RESERVED_SIZE 5 +struct compress_data { + __le32 clen; /* compressed data size */ + __le32 reserved[COMPRESS_DATA_RESERVED_SIZE]; /* reserved */ + u8 cdata[]; /* compressed data */ +}; + +#define COMPRESS_HEADER_SIZE (sizeof(struct compress_data)) + +#define F2FS_COMPRESSED_PAGE_MAGIC 0xF5F2C000 + +/* compress context */ +struct compress_ctx { + struct inode *inode; /* inode the context belong to */ + pgoff_t cluster_idx; /* cluster index number */ + unsigned int cluster_size; /* page count in cluster */ + unsigned int log_cluster_size; /* log of cluster size */ + struct page **rpages; /* pages store raw data in cluster */ + unsigned int nr_rpages; /* total page number in rpages */ + struct page **cpages; /* pages store compressed data in cluster */ + unsigned int nr_cpages; /* total page number in cpages */ + void *rbuf; /* virtual mapped address on rpages */ + struct compress_data *cbuf; /* virtual mapped address on cpages */ + size_t rlen; /* valid data length in rbuf */ + size_t clen; /* valid data length in cbuf */ + void *private; /* payload buffer for specified compression algorithm */ + void *private2; /* extra payload buffer */ +}; + +/* compress context for write IO path */ +struct compress_io_ctx { + u32 magic; /* magic number to indicate page is compressed */ + struct inode *inode; /* inode the context belong to */ + struct page **rpages; /* pages store raw data in cluster */ + unsigned int nr_rpages; /* total page number in rpages */ + refcount_t ref; /* referrence count of raw page */ +}; + +/* decompress io context for read IO path */ +struct decompress_io_ctx { + u32 magic; /* magic number to indicate page is compressed */ + struct inode *inode; /* inode the context belong to */ + pgoff_t cluster_idx; /* cluster index number */ + unsigned int cluster_size; /* page count in cluster */ + unsigned int log_cluster_size; /* log of cluster size */ + struct page **rpages; /* pages store raw data in cluster */ + unsigned int nr_rpages; /* total page number in rpages */ + struct page **cpages; /* pages store compressed data in cluster */ + unsigned int nr_cpages; /* total page number in cpages */ + struct page **tpages; /* temp pages to pad holes in cluster */ + void *rbuf; /* virtual mapped address on rpages */ + struct compress_data *cbuf; /* virtual mapped address on cpages */ + size_t rlen; /* valid data length in rbuf */ + size_t clen; /* valid data length in cbuf */ + refcount_t ref; /* referrence count of compressed page */ + bool failed; /* indicate IO error during decompression */ + void *private; /* payload buffer for specified decompression algorithm */ + void *private2; /* extra payload buffer */ +}; + +#define NULL_CLUSTER ((unsigned int)(~0)) +#define MIN_COMPRESS_LOG_SIZE 2 +#define MAX_COMPRESS_LOG_SIZE 8 +#define MAX_COMPRESS_WINDOW_SIZE ((PAGE_SIZE) << MAX_COMPRESS_LOG_SIZE) + struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ struct proc_dir_entry *s_proc; /* proc entry */ @@ -1182,10 +1357,6 @@ struct f2fs_sb_info { int valid_super_block; /* valid super block no */ unsigned long s_flag; /* flags for sbi */ struct mutex writepages; /* mutex for writepages() */ -#ifdef CONFIG_UNICODE - struct unicode_map *s_encoding; - __u16 s_encoding_flags; -#endif #ifdef CONFIG_BLK_DEV_ZONED unsigned int blocks_per_blkz; /* F2FS blocks per zone */ @@ -1289,7 +1460,10 @@ struct f2fs_sb_info { struct f2fs_mount_info mount_opt; /* mount options */ /* for cleaning operations */ - struct mutex gc_mutex; /* mutex for GC */ + struct rw_semaphore gc_lock; /* + * semaphore for GC, avoid + * race between GC and GC or CP + */ struct f2fs_gc_kthread *gc_thread; /* GC thread */ unsigned int cur_victim_sec; /* current victim section num */ unsigned int gc_mode; /* current GC state */ @@ -1325,11 +1499,11 @@ struct f2fs_sb_info { atomic_t inline_xattr; /* # of inline_xattr inodes */ atomic_t inline_inode; /* # of inline_data inodes */ atomic_t inline_dir; /* # of inline_dentry inodes */ - atomic_t aw_cnt; /* # of atomic writes */ + atomic_t compr_inode; /* # of compressed inodes */ + atomic_t compr_blocks; /* # of compressed blocks */ atomic_t vw_cnt; /* # of volatile writes */ atomic_t max_aw_cnt; /* max # of atomic writes */ atomic_t max_vw_cnt; /* max # of volatile writes */ - int bg_gc; /* background gc calls */ unsigned int io_skip_bggc; /* skip background gc for in-flight IO */ unsigned int other_skip_bggc; /* skip background gc for other reasons */ unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ @@ -1338,8 +1512,14 @@ struct f2fs_sb_info { /* For app/fs IO statistics */ spinlock_t iostat_lock; - unsigned long long write_iostat[NR_IO_TYPE]; + unsigned long long rw_iostat[NR_IO_TYPE]; + unsigned long long prev_rw_iostat[NR_IO_TYPE]; bool iostat_enable; + unsigned long iostat_next_period; + unsigned int iostat_period_ms; + + /* to attach REQ_META|REQ_FUA flags */ + unsigned int data_io_flag; /* For sysfs suppport */ struct kobject s_kobj; @@ -1363,6 +1543,11 @@ struct f2fs_sb_info { /* Precomputed FS UUID checksum for seeding other checksums */ __u32 s_chksum_seed; + + struct workqueue_struct *post_read_wq; /* post read workqueue */ + + struct kmem_cache *inline_xattr_slab; /* inline xattr entry */ + unsigned int inline_xattr_slab_size; /* default inline xattr slab size */ }; struct f2fs_private_dio { @@ -2104,7 +2289,7 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi, dquot_free_inode(inode); } else { if (unlikely(inode->i_blocks == 0)) { - f2fs_warn(sbi, "Inconsistent i_blocks, ino:%lu, iblocks:%llu", + f2fs_warn(sbi, "dec_valid_node_count: inconsistent i_blocks, ino:%lu, iblocks:%llu", inode->i_ino, (unsigned long long)inode->i_blocks); set_sbi_flag(sbi, SBI_NEED_FSCK); @@ -2221,26 +2406,6 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, return entry; } -static inline struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, - int npages, bool no_fail) -{ - struct bio *bio; - - if (no_fail) { - /* No failure on bio allocation */ - bio = bio_alloc(GFP_NOIO, npages); - if (!bio) - bio = bio_alloc(GFP_NOIO | __GFP_NOFAIL, npages); - return bio; - } - if (time_to_inject(sbi, FAULT_ALLOC_BIO)) { - f2fs_show_injection_info(sbi, FAULT_ALLOC_BIO); - return NULL; - } - - return bio_alloc(GFP_KERNEL, npages); -} - static inline bool is_idle(struct f2fs_sb_info *sbi, int type) { if (sbi->gc_mode == GC_URGENT) @@ -2292,7 +2457,7 @@ static inline __le32 *blkaddr_in_node(struct f2fs_node *node) } static inline int f2fs_has_extra_attr(struct inode *inode); -static inline block_t datablock_addr(struct inode *inode, +static inline block_t data_blkaddr(struct inode *inode, struct page *node_page, unsigned int offset) { struct f2fs_node *raw_node; @@ -2302,9 +2467,9 @@ static inline block_t datablock_addr(struct inode *inode, raw_node = F2FS_NODE(node_page); - /* from GC path only */ if (is_inode) { if (!inode) + /* from GC path only */ base = offset_in_addr(&raw_node->i); else if (f2fs_has_extra_attr(inode)) base = get_extra_isize(inode); @@ -2314,6 +2479,11 @@ static inline block_t datablock_addr(struct inode *inode, return le32_to_cpu(addr_array[base + offset]); } +static inline block_t f2fs_data_blkaddr(struct dnode_of_data *dn) +{ + return data_blkaddr(dn->inode, dn->node_page, dn->ofs_in_node); +} + static inline int f2fs_test_bit(unsigned int nr, char *addr) { int mask; @@ -2377,11 +2547,13 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr) /* * On-disk inode flags (f2fs_inode::i_flags) */ +#define F2FS_COMPR_FL 0x00000004 /* Compress file */ #define F2FS_SYNC_FL 0x00000008 /* Synchronous updates */ #define F2FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ #define F2FS_APPEND_FL 0x00000020 /* writes to file may only append */ #define F2FS_NODUMP_FL 0x00000040 /* do not dump file */ #define F2FS_NOATIME_FL 0x00000080 /* do not update atime */ +#define F2FS_NOCOMP_FL 0x00000400 /* Don't compress */ #define F2FS_INDEX_FL 0x00001000 /* hash-indexed directory */ #define F2FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define F2FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ @@ -2390,7 +2562,7 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr) /* Flags that should be inherited by new inodes from their parent. */ #define F2FS_FL_INHERITED (F2FS_SYNC_FL | F2FS_NODUMP_FL | F2FS_NOATIME_FL | \ F2FS_DIRSYNC_FL | F2FS_PROJINHERIT_FL | \ - F2FS_CASEFOLD_FL) + F2FS_CASEFOLD_FL | F2FS_COMPR_FL | F2FS_NOCOMP_FL) /* Flags that are appropriate for regular files (all but dir-specific ones). */ #define F2FS_REG_FLMASK (~(F2FS_DIRSYNC_FL | F2FS_PROJINHERIT_FL | \ @@ -2409,41 +2581,6 @@ static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags) return flags & F2FS_OTHER_FLMASK; } -/* used for f2fs_inode_info->flags */ -enum { - FI_NEW_INODE, /* indicate newly allocated inode */ - FI_DIRTY_INODE, /* indicate inode is dirty or not */ - FI_AUTO_RECOVER, /* indicate inode is recoverable */ - FI_DIRTY_DIR, /* indicate directory has dirty pages */ - FI_INC_LINK, /* need to increment i_nlink */ - FI_ACL_MODE, /* indicate acl mode */ - FI_NO_ALLOC, /* should not allocate any blocks */ - FI_FREE_NID, /* free allocated nide */ - FI_NO_EXTENT, /* not to use the extent cache */ - FI_INLINE_XATTR, /* used for inline xattr */ - FI_INLINE_DATA, /* used for inline data*/ - FI_INLINE_DENTRY, /* used for inline dentry */ - FI_APPEND_WRITE, /* inode has appended data */ - FI_UPDATE_WRITE, /* inode has in-place-update data */ - FI_NEED_IPU, /* used for ipu per file */ - FI_ATOMIC_FILE, /* indicate atomic file */ - FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */ - FI_VOLATILE_FILE, /* indicate volatile file */ - FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */ - FI_DROP_CACHE, /* drop dirty page cache */ - FI_DATA_EXIST, /* indicate data exists */ - FI_INLINE_DOTS, /* indicate inline dot dentries */ - FI_DO_DEFRAG, /* indicate defragment is running */ - FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */ - FI_NO_PREALLOC, /* indicate skipped preallocated blocks */ - FI_HOT_DATA, /* indicate file is hot */ - FI_EXTRA_ATTR, /* indicate file has extra attribute */ - FI_PROJ_INHERIT, /* indicate file inherits projectid */ - FI_PIN_FILE, /* indicate file should not be gced */ - FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */ - FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */ -}; - static inline void __mark_inode_dirty_flag(struct inode *inode, int flag, bool set) { @@ -2464,20 +2601,18 @@ static inline void __mark_inode_dirty_flag(struct inode *inode, static inline void set_inode_flag(struct inode *inode, int flag) { - if (!test_bit(flag, &F2FS_I(inode)->flags)) - set_bit(flag, &F2FS_I(inode)->flags); + test_and_set_bit(flag, F2FS_I(inode)->flags); __mark_inode_dirty_flag(inode, flag, true); } static inline int is_inode_flag_set(struct inode *inode, int flag) { - return test_bit(flag, &F2FS_I(inode)->flags); + return test_bit(flag, F2FS_I(inode)->flags); } static inline void clear_inode_flag(struct inode *inode, int flag) { - if (test_bit(flag, &F2FS_I(inode)->flags)) - clear_bit(flag, &F2FS_I(inode)->flags); + test_and_clear_bit(flag, F2FS_I(inode)->flags); __mark_inode_dirty_flag(inode, flag, false); } @@ -2568,19 +2703,19 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri) struct f2fs_inode_info *fi = F2FS_I(inode); if (ri->i_inline & F2FS_INLINE_XATTR) - set_bit(FI_INLINE_XATTR, &fi->flags); + set_bit(FI_INLINE_XATTR, fi->flags); if (ri->i_inline & F2FS_INLINE_DATA) - set_bit(FI_INLINE_DATA, &fi->flags); + set_bit(FI_INLINE_DATA, fi->flags); if (ri->i_inline & F2FS_INLINE_DENTRY) - set_bit(FI_INLINE_DENTRY, &fi->flags); + set_bit(FI_INLINE_DENTRY, fi->flags); if (ri->i_inline & F2FS_DATA_EXIST) - set_bit(FI_DATA_EXIST, &fi->flags); + set_bit(FI_DATA_EXIST, fi->flags); if (ri->i_inline & F2FS_INLINE_DOTS) - set_bit(FI_INLINE_DOTS, &fi->flags); + set_bit(FI_INLINE_DOTS, fi->flags); if (ri->i_inline & F2FS_EXTRA_ATTR) - set_bit(FI_EXTRA_ATTR, &fi->flags); + set_bit(FI_EXTRA_ATTR, fi->flags); if (ri->i_inline & F2FS_PIN_FILE) - set_bit(FI_PIN_FILE, &fi->flags); + set_bit(FI_PIN_FILE, fi->flags); } static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) @@ -2613,16 +2748,27 @@ static inline int f2fs_has_inline_xattr(struct inode *inode) return is_inode_flag_set(inode, FI_INLINE_XATTR); } +static inline int f2fs_compressed_file(struct inode *inode) +{ + return S_ISREG(inode->i_mode) && + is_inode_flag_set(inode, FI_COMPRESSED_FILE); +} + static inline unsigned int addrs_per_inode(struct inode *inode) { unsigned int addrs = CUR_ADDRS_PER_INODE(inode) - get_inline_xattr_addrs(inode); - return ALIGN_DOWN(addrs, 1); + + if (!f2fs_compressed_file(inode)) + return addrs; + return ALIGN_DOWN(addrs, F2FS_I(inode)->i_cluster_size); } static inline unsigned int addrs_per_block(struct inode *inode) { - return ALIGN_DOWN(DEF_ADDRS_PER_BLOCK, 1); + if (!f2fs_compressed_file(inode)) + return DEF_ADDRS_PER_BLOCK; + return ALIGN_DOWN(DEF_ADDRS_PER_BLOCK, F2FS_I(inode)->i_cluster_size); } static inline void *inline_xattr_addr(struct inode *inode, struct page *page) @@ -2655,6 +2801,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode) return is_inode_flag_set(inode, FI_INLINE_DOTS); } +static inline int f2fs_is_mmap_file(struct inode *inode) +{ + return is_inode_flag_set(inode, FI_MMAP_FILE); +} + static inline bool f2fs_is_pinned_file(struct inode *inode) { return is_inode_flag_set(inode, FI_PIN_FILE); @@ -2749,9 +2900,9 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync) if (!f2fs_is_time_consistent(inode)) return false; - down_read(&F2FS_I(inode)->i_sem); + spin_lock(&F2FS_I(inode)->i_size_lock); ret = F2FS_I(inode)->last_disk_size == i_size_read(inode); - up_read(&F2FS_I(inode)->i_sem); + spin_unlock(&F2FS_I(inode)->i_size_lock); return ret; } @@ -2782,7 +2933,8 @@ static inline bool f2fs_may_extent_tree(struct inode *inode) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); if (!test_opt(sbi, EXTENT_CACHE) || - is_inode_flag_set(inode, FI_NO_EXTENT)) + is_inode_flag_set(inode, FI_NO_EXTENT) || + is_inode_flag_set(inode, FI_COMPRESSED_FILE)) return false; /* @@ -2859,29 +3011,45 @@ static inline int get_inline_xattr_addrs(struct inode *inode) sizeof((f2fs_inode)->field)) \ <= (F2FS_OLD_ATTRIBUTE_SIZE + (extra_isize))) \ +#define DEFAULT_IOSTAT_PERIOD_MS 3000 +#define MIN_IOSTAT_PERIOD_MS 100 +/* maximum period of iostat tracing is 1 day */ +#define MAX_IOSTAT_PERIOD_MS 8640000 + static inline void f2fs_reset_iostat(struct f2fs_sb_info *sbi) { int i; spin_lock(&sbi->iostat_lock); - for (i = 0; i < NR_IO_TYPE; i++) - sbi->write_iostat[i] = 0; + for (i = 0; i < NR_IO_TYPE; i++) { + sbi->rw_iostat[i] = 0; + sbi->prev_rw_iostat[i] = 0; + } spin_unlock(&sbi->iostat_lock); } +extern void f2fs_record_iostat(struct f2fs_sb_info *sbi); + static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi, enum iostat_type type, unsigned long long io_bytes) { if (!sbi->iostat_enable) return; spin_lock(&sbi->iostat_lock); - sbi->write_iostat[type] += io_bytes; + sbi->rw_iostat[type] += io_bytes; if (type == APP_WRITE_IO || type == APP_DIRECT_IO) - sbi->write_iostat[APP_BUFFERED_IO] = - sbi->write_iostat[APP_WRITE_IO] - - sbi->write_iostat[APP_DIRECT_IO]; + sbi->rw_iostat[APP_BUFFERED_IO] = + sbi->rw_iostat[APP_WRITE_IO] - + sbi->rw_iostat[APP_DIRECT_IO]; + + if (type == APP_READ_IO || type == APP_DIRECT_READ_IO) + sbi->rw_iostat[APP_BUFFERED_READ_IO] = + sbi->rw_iostat[APP_READ_IO] - + sbi->rw_iostat[APP_DIRECT_READ_IO]; spin_unlock(&sbi->iostat_lock); + + f2fs_record_iostat(sbi); } #define __is_large_section(sbi) ((sbi)->segs_per_sec > 1) @@ -2902,7 +3070,8 @@ static inline void verify_blkaddr(struct f2fs_sb_info *sbi, static inline bool __is_valid_data_blkaddr(block_t blkaddr) { - if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR || + blkaddr == COMPRESS_ADDR) return false; return true; } @@ -2968,11 +3137,6 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name, bool hot, bool set); struct dentry *f2fs_get_parent(struct dentry *child); -extern int f2fs_ci_compare(const struct inode *parent, - const struct qstr *name, - const struct qstr *entry, - bool quick); - /* * dir.c */ @@ -3000,11 +3164,13 @@ ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr, struct page **page); void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, struct page *page, struct inode *inode); +bool f2fs_has_enough_room(struct inode *dir, struct page *ipage, + struct fscrypt_name *fname); void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, const struct qstr *name, f2fs_hash_t name_hash, unsigned int bit_pos); int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, - const struct qstr *orig_name, + const struct qstr *orig_name, f2fs_hash_t dentry_hash, struct inode *inode, nid_t ino, umode_t mode); int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname, struct inode *inode, nid_t ino, umode_t mode); @@ -3037,7 +3203,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi); * hash.c */ f2fs_hash_t f2fs_dentry_hash(const struct inode *dir, - const struct qstr *name_info, struct fscrypt_name *fname); + const struct qstr *name_info, const struct fscrypt_name *fname); /* * node.c @@ -3101,7 +3267,7 @@ void f2fs_drop_inmem_pages(struct inode *inode); void f2fs_drop_inmem_page(struct inode *inode, struct page *page); int f2fs_commit_inmem_pages(struct inode *inode); void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need); -void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi); +void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg); int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino); int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi); int f2fs_flush_device_cache(struct f2fs_sb_info *sbi); @@ -3195,7 +3361,7 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi); void f2fs_update_dirty_page(struct inode *inode, struct page *page); void f2fs_remove_dirty_inode(struct inode *inode); int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type); -void f2fs_wait_on_all_pages_writeback(struct f2fs_sb_info *sbi); +void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type); int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc); void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi); int __init f2fs_create_checkpoint_caches(void); @@ -3204,10 +3370,13 @@ void f2fs_destroy_checkpoint_caches(void); /* * data.c */ -int f2fs_init_post_read_processing(void); -void f2fs_destroy_post_read_processing(void); +int __init f2fs_init_bioset(void); +void f2fs_destroy_bioset(void); +struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, int npages, bool noio); int f2fs_init_bio_entry_cache(void); void f2fs_destroy_bio_entry_cache(void); +void f2fs_submit_bio(struct f2fs_sb_info *sbi, + struct bio *bio, enum page_type type); void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type); void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, struct inode *inode, struct page *page, @@ -3228,6 +3397,9 @@ int f2fs_reserve_new_block(struct dnode_of_data *dn); int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index); int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from); int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index); +int f2fs_mpage_readpages(struct address_space *mapping, + struct list_head *pages, struct page *page, + unsigned nr_pages, bool is_readahead); struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index, int op_flags, bool for_write); struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index); @@ -3241,8 +3413,14 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int create, int flag); int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); +int f2fs_encrypt_one_page(struct f2fs_io_info *fio); bool f2fs_should_update_inplace(struct inode *inode, struct f2fs_io_info *fio); bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio); +int f2fs_write_single_data_page(struct page *page, int *submitted, + struct bio **bio, sector_t *last_block, + struct writeback_control *wbc, + enum iostat_type io_type, + int compr_blocks); void f2fs_invalidate_page(struct page *page, unsigned int offset, unsigned int length); int f2fs_release_page(struct page *page, gfp_t wait); @@ -3252,6 +3430,10 @@ int f2fs_migrate_page(struct address_space *mapping, struct page *newpage, #endif bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len); void f2fs_clear_radix_tree_dirty_tag(struct page *page); +int f2fs_init_post_read_processing(void); +void f2fs_destroy_post_read_processing(void); +int f2fs_init_post_read_wq(struct f2fs_sb_info *sbi); +void f2fs_destroy_post_read_wq(struct f2fs_sb_info *sbi); /* * gc.c @@ -3298,6 +3480,7 @@ struct f2fs_stat_info { int nr_discard_cmd; unsigned int undiscard_blks; int inline_xattr, inline_inode, inline_dir, append, update, orphans; + int compr_inode, compr_blocks; int aw_cnt, max_aw_cnt, vw_cnt, max_vw_cnt; unsigned int valid_count, valid_node_count, valid_inode_count, discard_blks; unsigned int bimodal, avg_vblocks; @@ -3329,7 +3512,7 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) #define stat_inc_cp_count(si) ((si)->cp_count++) #define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++) #define stat_inc_call_count(si) ((si)->call_count++) -#define stat_inc_bggc_count(sbi) ((sbi)->bg_gc++) +#define stat_inc_bggc_count(si) ((si)->bg_gc++) #define stat_io_skip_bggc_count(sbi) ((sbi)->io_skip_bggc++) #define stat_other_skip_bggc_count(sbi) ((sbi)->other_skip_bggc++) #define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++) @@ -3368,6 +3551,20 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) if (f2fs_has_inline_dentry(inode)) \ (atomic_dec(&F2FS_I_SB(inode)->inline_dir)); \ } while (0) +#define stat_inc_compr_inode(inode) \ + do { \ + if (f2fs_compressed_file(inode)) \ + (atomic_inc(&F2FS_I_SB(inode)->compr_inode)); \ + } while (0) +#define stat_dec_compr_inode(inode) \ + do { \ + if (f2fs_compressed_file(inode)) \ + (atomic_dec(&F2FS_I_SB(inode)->compr_inode)); \ + } while (0) +#define stat_add_compr_blocks(inode, blocks) \ + (atomic_add(blocks, &F2FS_I_SB(inode)->compr_blocks)) +#define stat_sub_compr_blocks(inode, blocks) \ + (atomic_sub(blocks, &F2FS_I_SB(inode)->compr_blocks)) #define stat_inc_meta_count(sbi, blkaddr) \ do { \ if (blkaddr < SIT_I(sbi)->sit_base_addr) \ @@ -3385,13 +3582,9 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) ((sbi)->block_count[(curseg)->alloc_type]++) #define stat_inc_inplace_blocks(sbi) \ (atomic_inc(&(sbi)->inplace_count)) -#define stat_inc_atomic_write(inode) \ - (atomic_inc(&F2FS_I_SB(inode)->aw_cnt)) -#define stat_dec_atomic_write(inode) \ - (atomic_dec(&F2FS_I_SB(inode)->aw_cnt)) #define stat_update_max_atomic_write(inode) \ do { \ - int cur = atomic_read(&F2FS_I_SB(inode)->aw_cnt); \ + int cur = F2FS_I_SB(inode)->atomic_files; \ int max = atomic_read(&F2FS_I_SB(inode)->max_aw_cnt); \ if (cur > max) \ atomic_set(&F2FS_I_SB(inode)->max_aw_cnt, cur); \ @@ -3443,6 +3636,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi); void f2fs_destroy_stats(struct f2fs_sb_info *sbi); void __init f2fs_create_root_stats(void); void f2fs_destroy_root_stats(void); +void f2fs_update_sit_info(struct f2fs_sb_info *sbi); #else #define stat_inc_cp_count(si) do { } while (0) #define stat_inc_bg_cp_count(si) do { } while (0) @@ -3452,8 +3646,8 @@ void f2fs_destroy_root_stats(void); #define stat_other_skip_bggc_count(sbi) do { } while (0) #define stat_inc_dirty_inode(sbi, type) do { } while (0) #define stat_dec_dirty_inode(sbi, type) do { } while (0) -#define stat_inc_total_hit(sb) do { } while (0) -#define stat_inc_rbtree_node_hit(sb) do { } while (0) +#define stat_inc_total_hit(sbi) do { } while (0) +#define stat_inc_rbtree_node_hit(sbi) do { } while (0) #define stat_inc_largest_node_hit(sbi) do { } while (0) #define stat_inc_cached_node_hit(sbi) do { } while (0) #define stat_inc_inline_xattr(inode) do { } while (0) @@ -3462,6 +3656,10 @@ void f2fs_destroy_root_stats(void); #define stat_dec_inline_inode(inode) do { } while (0) #define stat_inc_inline_dir(inode) do { } while (0) #define stat_dec_inline_dir(inode) do { } while (0) +#define stat_inc_compr_inode(inode) do { } while (0) +#define stat_dec_compr_inode(inode) do { } while (0) +#define stat_add_compr_blocks(inode, blocks) do { } while (0) +#define stat_sub_compr_blocks(inode, blocks) do { } while (0) #define stat_inc_atomic_write(inode) do { } while (0) #define stat_dec_atomic_write(inode) do { } while (0) #define stat_update_max_atomic_write(inode) do { } while (0) @@ -3481,12 +3679,10 @@ static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; } static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { } static inline void __init f2fs_create_root_stats(void) { } static inline void f2fs_destroy_root_stats(void) { } +static inline void update_sit_info(struct f2fs_sb_info *sbi) {} #endif extern const struct file_operations f2fs_dir_operations; -#ifdef CONFIG_UNICODE -extern const struct dentry_operations f2fs_dentry_ops; -#endif extern const struct file_operations f2fs_file_operations; extern const struct inode_operations f2fs_file_inode_operations; extern const struct address_space_operations f2fs_dblock_aops; @@ -3509,6 +3705,7 @@ void f2fs_truncate_inline_inode(struct inode *inode, int f2fs_read_inline_data(struct inode *inode, struct page *page); int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page); int f2fs_convert_inline_inode(struct inode *inode); +int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry); int f2fs_write_inline_data(struct inode *inode, struct page *page); bool f2fs_recover_inline_data(struct inode *inode, struct page *npage); struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, @@ -3516,7 +3713,7 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, int f2fs_make_empty_inline_dir(struct inode *inode, struct inode *parent, struct page *ipage); int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, - const struct qstr *orig_name, + const struct fscrypt_name *fname, struct inode *inode, nid_t ino, umode_t mode); void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page, struct inode *dir, @@ -3601,7 +3798,91 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode) */ static inline bool f2fs_post_read_required(struct inode *inode) { - return f2fs_encrypted_file(inode) || fsverity_active(inode); + return f2fs_encrypted_file(inode) || fsverity_active(inode) || + f2fs_compressed_file(inode); +} + +/* + * compress.c + */ +#ifdef CONFIG_F2FS_FS_COMPRESSION +bool f2fs_is_compressed_page(struct page *page); +struct page *f2fs_compress_control_page(struct page *page); +int f2fs_prepare_compress_overwrite(struct inode *inode, + struct page **pagep, pgoff_t index, void **fsdata); +bool f2fs_compress_write_end(struct inode *inode, void *fsdata, + pgoff_t index, unsigned copied); +void f2fs_compress_write_end_io(struct bio *bio, struct page *page); +bool f2fs_is_compress_backend_ready(struct inode *inode); +void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity); +bool f2fs_cluster_is_empty(struct compress_ctx *cc); +bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index); +void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page); +int f2fs_write_multi_pages(struct compress_ctx *cc, + int *submitted, + struct writeback_control *wbc, + enum iostat_type io_type); +int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index); +int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, + unsigned nr_pages, sector_t *last_block_in_bio, + bool is_readahead, bool for_write); +struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc); +void f2fs_free_dic(struct decompress_io_ctx *dic); +void f2fs_decompress_end_io(struct page **rpages, + unsigned int cluster_size, bool err, bool verity); +int f2fs_init_compress_ctx(struct compress_ctx *cc); +void f2fs_destroy_compress_ctx(struct compress_ctx *cc); +void f2fs_init_compress_info(struct f2fs_sb_info *sbi); +#else +static inline bool f2fs_is_compressed_page(struct page *page) { return false; } +static inline bool f2fs_is_compress_backend_ready(struct inode *inode) +{ + if (!f2fs_compressed_file(inode)) + return true; + /* not support compression */ + return false; +} +static inline struct page *f2fs_compress_control_page(struct page *page) +{ + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); +} +#endif + +static inline void set_compress_context(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + F2FS_I(inode)->i_compress_algorithm = + F2FS_OPTION(sbi).compress_algorithm; + F2FS_I(inode)->i_log_cluster_size = + F2FS_OPTION(sbi).compress_log_size; + F2FS_I(inode)->i_cluster_size = + 1 << F2FS_I(inode)->i_log_cluster_size; + F2FS_I(inode)->i_flags |= F2FS_COMPR_FL; + set_inode_flag(inode, FI_COMPRESSED_FILE); + stat_inc_compr_inode(inode); + f2fs_mark_inode_dirty_sync(inode, true); +} + +static inline u64 f2fs_disable_compressed_file(struct inode *inode) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + + if (!f2fs_compressed_file(inode)) + return 0; + if (S_ISREG(inode->i_mode)) { + if (get_dirty_pages(inode)) + return 1; + if (fi->i_compr_blocks) + return fi->i_compr_blocks; + } + + fi->i_flags &= ~F2FS_COMPR_FL; + stat_dec_compr_inode(inode); + clear_inode_flag(inode, FI_COMPRESSED_FILE); + f2fs_mark_inode_dirty_sync(inode, true); + return 0; } #define F2FS_FEATURE_FUNCS(name, flagname) \ @@ -3622,6 +3903,7 @@ F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); F2FS_FEATURE_FUNCS(verity, VERITY); F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM); F2FS_FEATURE_FUNCS(casefold, CASEFOLD); +F2FS_FEATURE_FUNCS(compression, COMPRESSION); #ifdef CONFIG_BLK_DEV_ZONED static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi, @@ -3676,31 +3958,49 @@ static inline bool f2fs_hw_is_readonly(struct f2fs_sb_info *sbi) return false; } - -static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt) +static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi) { - clear_opt(sbi, ADAPTIVE); - clear_opt(sbi, LFS); - - switch (mt) { - case F2FS_MOUNT_ADAPTIVE: - set_opt(sbi, ADAPTIVE); - break; - case F2FS_MOUNT_LFS: - set_opt(sbi, LFS); - break; - } + return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS; } -static inline bool f2fs_may_encrypt(struct inode *inode) +static inline bool f2fs_may_encrypt(struct inode *dir, struct inode *inode) { #ifdef CONFIG_FS_ENCRYPTION + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); umode_t mode = inode->i_mode; - return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)); -#else - return false; + /* + * If the directory encrypted or dummy encryption enabled, + * then we should encrypt the inode. + */ + if (IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) + return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)); #endif + return false; +} + +static inline bool f2fs_may_compress(struct inode *inode) +{ + if (IS_SWAPFILE(inode) || f2fs_is_pinned_file(inode) || + f2fs_is_atomic_file(inode) || + f2fs_is_volatile_file(inode)) + return false; + return S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode); +} + +static inline void f2fs_i_compr_blocks_update(struct inode *inode, + u64 blocks, bool add) +{ + int diff = F2FS_I(inode)->i_cluster_size - blocks; + + if (add) { + F2FS_I(inode)->i_compr_blocks += diff; + stat_add_compr_blocks(inode, diff); + } else { + F2FS_I(inode)->i_compr_blocks -= diff; + stat_sub_compr_blocks(inode, diff); + } + f2fs_mark_inode_dirty_sync(inode, true); } static inline int block_unaligned_IO(struct inode *inode, @@ -3720,7 +4020,7 @@ static inline int allow_outplace_dio(struct inode *inode, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int rw = iov_iter_rw(iter); - return (test_opt(sbi, LFS) && (rw == WRITE) && + return (f2fs_lfs_mode(sbi) && (rw == WRITE) && !block_unaligned_IO(inode, iocb, iter)); } @@ -3730,18 +4030,21 @@ static inline bool f2fs_force_buffered_io(struct inode *inode, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int rw = iov_iter_rw(iter); - if (f2fs_encrypted_file(inode) && - !fscrypt_using_hardware_encryption(inode)) + if (!fscrypt_dio_supported(iocb, iter)) + return true; + if (fsverity_active(inode)) return true; if (f2fs_is_multi_device(sbi)) return true; + if (f2fs_compressed_file(inode)) + return true; /* * for blkzoned device, fallback direct IO to buffered IO, so * all IOs can be serialized by log-structured write. */ if (f2fs_sb_has_blkzoned(sbi)) return true; - if (test_opt(sbi, LFS) && (rw == WRITE)) { + if (f2fs_lfs_mode(sbi) && (rw == WRITE)) { if (block_unaligned_IO(inode, iocb, iter)) return true; if (F2FS_IO_ALIGNED(sbi)) @@ -3754,16 +4057,6 @@ static inline bool f2fs_force_buffered_io(struct inode *inode, return false; } -static inline bool f2fs_may_encrypt_bio(struct inode *inode, - struct f2fs_io_info *fio) -{ - if (fio && (fio->type != DATA || fio->encrypted_page)) - return false; - - return (f2fs_encrypted_file(inode) && - fscrypt_using_hardware_encryption(inode)); -} - #ifdef CONFIG_F2FS_FAULT_INJECTION extern void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate, unsigned int type); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 2b64e03d8865f6a242cd17d6eedf10ca9fe67da1..311a36cba3306b137e5941e16cc63d658d2f064b 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -40,6 +40,10 @@ static int f2fs_filemap_fault(struct vm_fault *vmf) err = filemap_fault(vmf); up_read(&F2FS_I(inode)->i_mmap_sem); + if (!err) + f2fs_update_iostat(F2FS_I_SB(inode), APP_MAPPED_READ_IO, + F2FS_BLKSIZE); + trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)err); return err; @@ -50,8 +54,9 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) struct page *page = vmf->page; struct inode *inode = file_inode(vmf->vma->vm_file); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct dnode_of_data dn = { .node_changed = false }; - int err; + struct dnode_of_data dn; + bool need_alloc = true; + int err = 0; if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; @@ -63,6 +68,26 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) goto err; } +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_compressed_file(inode)) { + int ret = f2fs_is_compressed_cluster(inode, page->index); + + if (ret < 0) { + err = ret; + goto err; + } else if (ret) { + if (ret < F2FS_I(inode)->i_cluster_size) { + err = -EAGAIN; + goto err; + } + need_alloc = false; + } + } +#endif + /* should do out of any locked page */ + if (need_alloc) + f2fs_balance_fs(sbi, true); + sb_start_pagefault(inode->i_sb); f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); @@ -78,18 +103,27 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) goto out_sem; } - /* block allocation */ - __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = f2fs_get_block(&dn, page->index); - f2fs_put_dnode(&dn); - __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + if (need_alloc) { + /* block allocation */ + __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = f2fs_get_block(&dn, page->index); + f2fs_put_dnode(&dn); + __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + } + +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (!need_alloc) { + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE); + f2fs_put_dnode(&dn); + } +#endif if (err) { unlock_page(page); goto out_sem; } - /* fill the page */ f2fs_wait_on_page_writeback(page, DATA, false, true); /* wait for GCed page writeback via META_MAPPING */ @@ -120,8 +154,6 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) out_sem: up_read(&F2FS_I(inode)->i_mmap_sem); - f2fs_balance_fs(sbi, dn.node_changed); - sb_end_pagefault(inode->i_sb); err: return block_page_mkwrite_return(err); @@ -155,6 +187,8 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode) if (!S_ISREG(inode->i_mode)) cp_reason = CP_NON_REGULAR; + else if (f2fs_compressed_file(inode)) + cp_reason = CP_COMPRESSED; else if (inode->i_nlink != 1) cp_reason = CP_HARDLINK; else if (is_sbi_flag_set(sbi, SBI_NEED_CP)) @@ -436,8 +470,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) data_ofs = (loff_t)pgofs << PAGE_SHIFT) { block_t blkaddr; - blkaddr = datablock_addr(dn.inode, - dn.node_page, dn.ofs_in_node); + blkaddr = f2fs_data_blkaddr(&dn); if (__is_valid_data_blkaddr(blkaddr) && !f2fs_is_valid_blkaddr(F2FS_I_SB(inode), @@ -496,6 +529,9 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; + if (!f2fs_is_compress_backend_ready(inode)) + return -EOPNOTSUPP; + /* we don't need to use inline_data strictly */ err = f2fs_convert_inline_inode(inode); if (err) @@ -503,6 +539,7 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) file_accessed(file); vma->vm_ops = &f2fs_file_vm_ops; + set_inode_flag(inode, FI_MMAP_FILE); return 0; } @@ -513,6 +550,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) if (err) return err; + if (!f2fs_is_compress_backend_ready(inode)) + return -EOPNOTSUPP; + err = fsverity_file_open(inode, filp); if (err) return err; @@ -529,6 +569,9 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) int nr_free = 0, ofs = dn->ofs_in_node, len = count; __le32 *addr; int base = 0; + bool compressed_cluster = false; + int cluster_index = 0, valid_blocks = 0; + int cluster_size = F2FS_I(dn->inode)->i_cluster_size; if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode)) base = get_extra_isize(dn->inode); @@ -536,26 +579,43 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) raw_node = F2FS_NODE(dn->node_page); addr = blkaddr_in_node(raw_node) + base + ofs; - for (; count > 0; count--, addr++, dn->ofs_in_node++) { + /* Assumption: truncateion starts with cluster */ + for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) { block_t blkaddr = le32_to_cpu(*addr); + if (f2fs_compressed_file(dn->inode) && + !(cluster_index & (cluster_size - 1))) { + if (compressed_cluster) + f2fs_i_compr_blocks_update(dn->inode, + valid_blocks, false); + compressed_cluster = (blkaddr == COMPRESS_ADDR); + valid_blocks = 0; + } + if (blkaddr == NULL_ADDR) continue; dn->data_blkaddr = NULL_ADDR; f2fs_set_data_blkaddr(dn); - if (__is_valid_data_blkaddr(blkaddr) && - !f2fs_is_valid_blkaddr(sbi, blkaddr, + if (__is_valid_data_blkaddr(blkaddr)) { + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) - continue; + continue; + if (compressed_cluster) + valid_blocks++; + } - f2fs_invalidate_blocks(sbi, blkaddr); if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page)) clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN); + + f2fs_invalidate_blocks(sbi, blkaddr); nr_free++; } + if (compressed_cluster) + f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false); + if (nr_free) { pgoff_t fofs; /* @@ -598,6 +658,9 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, return 0; } + if (f2fs_compressed_file(inode)) + return 0; + page = f2fs_get_lock_data_page(inode, index, true); if (IS_ERR(page)) return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page); @@ -613,7 +676,7 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, return 0; } -int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock) +static int do_truncate_blocks(struct inode *inode, u64 from, bool lock) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; @@ -678,6 +741,28 @@ int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock) return err; } +int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock) +{ + u64 free_from = from; + + /* + * for compressed file, only support cluster size + * aligned truncation. + */ + if (f2fs_compressed_file(inode)) { + size_t cluster_shift = PAGE_SHIFT + + F2FS_I(inode)->i_log_cluster_size; + size_t cluster_mask = (1 << cluster_shift) - 1; + + free_from = from >> cluster_shift; + if (from & cluster_mask) + free_from++; + free_from <<= cluster_shift; + } + + return do_truncate_blocks(inode, free_from, lock); +} + int f2fs_truncate(struct inode *inode) { int err; @@ -729,6 +814,8 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, } flags = fi->i_flags; + if (flags & F2FS_COMPR_FL) + stat->attributes |= STATX_ATTR_COMPRESSED; if (flags & F2FS_APPEND_FL) stat->attributes |= STATX_ATTR_APPEND; if (IS_ENCRYPTED(inode)) @@ -740,7 +827,8 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, if (IS_VERITY(inode)) stat->attributes |= STATX_ATTR_VERITY; - stat->attributes_mask |= (STATX_ATTR_APPEND | + stat->attributes_mask |= (STATX_ATTR_COMPRESSED | + STATX_ATTR_APPEND | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | STATX_ATTR_NODUMP | @@ -794,6 +882,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; + if ((attr->ia_valid & ATTR_SIZE) && + !f2fs_is_compress_backend_ready(inode)) + return -EOPNOTSUPP; + err = setattr_prepare(dentry, attr); if (err) return err; @@ -864,10 +956,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) if (err) return err; - down_write(&F2FS_I(inode)->i_sem); + spin_lock(&F2FS_I(inode)->i_size_lock); inode->i_mtime = inode->i_ctime = current_time(inode); F2FS_I(inode)->last_disk_size = i_size_read(inode); - up_write(&F2FS_I(inode)->i_sem); + spin_unlock(&F2FS_I(inode)->i_size_lock); } __setattr_copy(inode, attr); @@ -1034,8 +1126,8 @@ static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr, } else if (ret == -ENOENT) { if (dn.max_level == 0) return -ENOENT; - done = min((pgoff_t)ADDRS_PER_BLOCK(inode) - dn.ofs_in_node, - len); + done = min((pgoff_t)ADDRS_PER_BLOCK(inode) - + dn.ofs_in_node, len); blkaddr += done; do_replace += done; goto next; @@ -1044,8 +1136,7 @@ static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr, done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) - dn.ofs_in_node, len); for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) { - *blkaddr = datablock_addr(dn.inode, - dn.node_page, dn.ofs_in_node); + *blkaddr = f2fs_data_blkaddr(&dn); if (__is_valid_data_blkaddr(*blkaddr) && !f2fs_is_valid_blkaddr(sbi, *blkaddr, @@ -1056,7 +1147,7 @@ static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr, if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) { - if (test_opt(sbi, LFS)) { + if (f2fs_lfs_mode(sbi)) { f2fs_put_dnode(&dn); return -EOPNOTSUPP; } @@ -1134,8 +1225,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode, ADDRS_PER_PAGE(dn.node_page, dst_inode) - dn.ofs_in_node, len - i); do { - dn.data_blkaddr = datablock_addr(dn.inode, - dn.node_page, dn.ofs_in_node); + dn.data_blkaddr = f2fs_data_blkaddr(&dn); f2fs_truncate_data_blocks_range(&dn, 1); if (do_replace[i]) { @@ -1198,13 +1288,13 @@ static int __exchange_data_block(struct inode *src_inode, src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode), array_size(olen, sizeof(block_t)), - GFP_KERNEL); + GFP_NOFS); if (!src_blkaddr) return -ENOMEM; do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode), array_size(olen, sizeof(int)), - GFP_KERNEL); + GFP_NOFS); if (!do_replace) { kvfree(src_blkaddr); return -ENOMEM; @@ -1311,8 +1401,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start, int ret; for (; index < end; index++, dn->ofs_in_node++) { - if (datablock_addr(dn->inode, dn->node_page, - dn->ofs_in_node) == NULL_ADDR) + if (f2fs_data_blkaddr(dn) == NULL_ADDR) count++; } @@ -1323,8 +1412,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start, dn->ofs_in_node = ofs_in_node; for (index = start; index < end; index++, dn->ofs_in_node++) { - dn->data_blkaddr = datablock_addr(dn->inode, - dn->node_page, dn->ofs_in_node); + dn->data_blkaddr = f2fs_data_blkaddr(dn); /* * f2fs_reserve_new_blocks will not guarantee entire block * allocation. @@ -1571,7 +1659,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset, next_alloc: if (has_not_enough_free_secs(sbi, 0, GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) { - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); err = f2fs_gc(sbi, true, false, NULL_SEGNO); if (err && err != -ENODATA && err != -EAGAIN) goto out_err; @@ -1629,6 +1717,8 @@ static long f2fs_fallocate(struct file *file, int mode, return -EIO; if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode))) return -ENOSPC; + if (!f2fs_is_compress_backend_ready(inode)) + return -EOPNOTSUPP; /* f2fs only support ->fallocate for regular file */ if (!S_ISREG(inode->i_mode)) @@ -1638,6 +1728,11 @@ static long f2fs_fallocate(struct file *file, int mode, (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE))) return -EOPNOTSUPP; + if (f2fs_compressed_file(inode) && + (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | + FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE))) + return -EOPNOTSUPP; + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE)) @@ -1715,19 +1810,50 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) { struct f2fs_inode_info *fi = F2FS_I(inode); + u32 masked_flags = fi->i_flags & mask; + + f2fs_bug_on(F2FS_I_SB(inode), (iflags & ~mask)); /* Is it quota file? Do not allow user to mess with it */ if (IS_NOQUOTA(inode)) return -EPERM; - if ((iflags ^ fi->i_flags) & F2FS_CASEFOLD_FL) { + if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) { if (!f2fs_sb_has_casefold(F2FS_I_SB(inode))) return -EOPNOTSUPP; if (!f2fs_empty_dir(inode)) return -ENOTEMPTY; } + if (iflags & (F2FS_COMPR_FL | F2FS_NOCOMP_FL)) { + if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) + return -EOPNOTSUPP; + if ((iflags & F2FS_COMPR_FL) && (iflags & F2FS_NOCOMP_FL)) + return -EINVAL; + } + + if ((iflags ^ masked_flags) & F2FS_COMPR_FL) { + if (masked_flags & F2FS_COMPR_FL) { + if (f2fs_disable_compressed_file(inode)) + return -EINVAL; + } + if (iflags & F2FS_NOCOMP_FL) + return -EINVAL; + if (iflags & F2FS_COMPR_FL) { + if (!f2fs_may_compress(inode)) + return -EINVAL; + + set_compress_context(inode); + } + } + if ((iflags ^ masked_flags) & F2FS_NOCOMP_FL) { + if (masked_flags & F2FS_COMPR_FL) + return -EINVAL; + } + fi->i_flags = iflags | (fi->i_flags & ~mask); + f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) && + (fi->i_flags & F2FS_NOCOMP_FL)); if (fi->i_flags & F2FS_PROJINHERIT_FL) set_inode_flag(inode, FI_PROJ_INHERIT); @@ -1753,11 +1879,13 @@ static const struct { u32 iflag; u32 fsflag; } f2fs_fsflags_map[] = { + { F2FS_COMPR_FL, FS_COMPR_FL }, { F2FS_SYNC_FL, FS_SYNC_FL }, { F2FS_IMMUTABLE_FL, FS_IMMUTABLE_FL }, { F2FS_APPEND_FL, FS_APPEND_FL }, { F2FS_NODUMP_FL, FS_NODUMP_FL }, { F2FS_NOATIME_FL, FS_NOATIME_FL }, + { F2FS_NOCOMP_FL, FS_NOCOMP_FL }, { F2FS_INDEX_FL, FS_INDEX_FL }, { F2FS_DIRSYNC_FL, FS_DIRSYNC_FL }, { F2FS_PROJINHERIT_FL, FS_PROJINHERIT_FL }, @@ -1765,11 +1893,13 @@ static const struct { }; #define F2FS_GETTABLE_FS_FL ( \ + FS_COMPR_FL | \ FS_SYNC_FL | \ FS_IMMUTABLE_FL | \ FS_APPEND_FL | \ FS_NODUMP_FL | \ FS_NOATIME_FL | \ + FS_NOCOMP_FL | \ FS_INDEX_FL | \ FS_DIRSYNC_FL | \ FS_PROJINHERIT_FL | \ @@ -1780,11 +1910,13 @@ static const struct { FS_CASEFOLD_FL) #define F2FS_SETTABLE_FS_FL ( \ + FS_COMPR_FL | \ FS_SYNC_FL | \ FS_IMMUTABLE_FL | \ FS_APPEND_FL | \ FS_NODUMP_FL | \ FS_NOATIME_FL | \ + FS_NOCOMP_FL | \ FS_DIRSYNC_FL | \ FS_PROJINHERIT_FL | \ FS_CASEFOLD_FL) @@ -1905,6 +2037,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) inode_lock(inode); + f2fs_disable_compressed_file(inode); + if (f2fs_is_atomic_file(inode)) { if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) ret = -EINVAL; @@ -1943,7 +2077,6 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); F2FS_I(inode)->inmem_task = current; - stat_inc_atomic_write(inode); stat_update_max_atomic_write(inode); out: inode_unlock(inode); @@ -2311,6 +2444,14 @@ static int f2fs_ioc_get_encryption_key_status(struct file *filp, return fscrypt_ioctl_get_key_status(filp, (void __user *)arg); } +static int f2fs_ioc_get_encryption_nonce(struct file *filp, unsigned long arg) +{ + if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp)))) + return -EOPNOTSUPP; + + return fscrypt_ioctl_get_nonce(filp, (void __user *)arg); +} + static int f2fs_ioc_gc(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); @@ -2332,12 +2473,12 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg) return ret; if (!sync) { - if (!mutex_trylock(&sbi->gc_mutex)) { + if (!down_write_trylock(&sbi->gc_lock)) { ret = -EBUSY; goto out; } } else { - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); } ret = f2fs_gc(sbi, sync, true, NULL_SEGNO); @@ -2375,12 +2516,12 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) do_more: if (!range.sync) { - if (!mutex_trylock(&sbi->gc_mutex)) { + if (!down_write_trylock(&sbi->gc_lock)) { ret = -EBUSY; goto out; } } else { - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); } ret = f2fs_gc(sbi, range.sync, true, GET_SEGNO(sbi, range.start)); @@ -2811,7 +2952,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) end_segno = min(start_segno + range.segments, dev_end_segno); while (start_segno < end_segno) { - if (!mutex_trylock(&sbi->gc_mutex)) { + if (!down_write_trylock(&sbi->gc_lock)) { ret = -EBUSY; goto out; } @@ -3106,10 +3247,16 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) ret = -EAGAIN; goto out; } + ret = f2fs_convert_inline_inode(inode); if (ret) goto out; + if (f2fs_disable_compressed_file(inode)) { + ret = -EOPNOTSUPP; + goto out; + } + set_inode_flag(inode, FI_PIN_FILE); ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; done: @@ -3213,6 +3360,21 @@ static int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg) return fsverity_ioctl_measure(filp, (void __user *)arg); } +static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg) +{ + struct inode *inode = file_inode(filp); + __u64 blocks; + + if (!f2fs_sb_has_compression(F2FS_I_SB(inode))) + return -EOPNOTSUPP; + + if (!f2fs_compressed_file(inode)) + return -EINVAL; + + blocks = F2FS_I(inode)->i_compr_blocks; + return put_user(blocks, (u64 __user *)arg); +} + long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp))))) @@ -3257,6 +3419,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return f2fs_ioc_remove_encryption_key_all_users(filp, arg); case FS_IOC_GET_ENCRYPTION_KEY_STATUS: return f2fs_ioc_get_encryption_key_status(filp, arg); + case FS_IOC_GET_ENCRYPTION_NONCE: + return f2fs_ioc_get_encryption_nonce(filp, arg); case F2FS_IOC_GARBAGE_COLLECT: return f2fs_ioc_gc(filp, arg); case F2FS_IOC_GARBAGE_COLLECT_RANGE: @@ -3287,11 +3451,30 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return f2fs_ioc_enable_verity(filp, arg); case FS_IOC_MEASURE_VERITY: return f2fs_ioc_measure_verity(filp, arg); + case F2FS_IOC_GET_COMPRESS_BLOCKS: + return f2fs_get_compress_blocks(filp, arg); default: return -ENOTTY; } } +static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + int ret; + + if (!f2fs_is_compress_backend_ready(inode)) + return -EOPNOTSUPP; + + ret = generic_file_read_iter(iocb, iter); + + if (ret > 0) + f2fs_update_iostat(F2FS_I_SB(inode), APP_READ_IO, ret); + + return ret; +} + static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; @@ -3303,6 +3486,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) goto out; } + if (!f2fs_is_compress_backend_ready(inode)) { + ret = -EOPNOTSUPP; + goto out; + } + if (iocb->ki_flags & IOCB_NOWAIT) { if (!inode_trylock(inode)) { ret = -EAGAIN; @@ -3331,18 +3519,41 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = -EAGAIN; goto out; } - } else { - preallocated = true; - target_size = iocb->ki_pos + iov_iter_count(from); + goto write; + } - err = f2fs_preallocate_blocks(iocb, from); - if (err) { - clear_inode_flag(inode, FI_NO_PREALLOC); - inode_unlock(inode); - ret = err; - goto out; - } + if (is_inode_flag_set(inode, FI_NO_PREALLOC)) + goto write; + + if (iocb->ki_flags & IOCB_DIRECT) { + /* + * Convert inline data for Direct I/O before entering + * f2fs_direct_IO(). + */ + err = f2fs_convert_inline_inode(inode); + if (err) + goto out_err; + /* + * If force_buffere_io() is true, we have to allocate + * blocks all the time, since f2fs_direct_IO will fall + * back to buffered IO. + */ + if (!f2fs_force_buffered_io(inode, iocb, from) && + allow_outplace_dio(inode, iocb, from)) + goto write; + } + preallocated = true; + target_size = iocb->ki_pos + iov_iter_count(from); + + err = f2fs_preallocate_blocks(iocb, from); + if (err) { +out_err: + clear_inode_flag(inode, FI_NO_PREALLOC); + inode_unlock(inode); + ret = err; + goto out; } +write: ret = __generic_file_write_iter(iocb, from); clear_inode_flag(inode, FI_NO_PREALLOC); @@ -3389,6 +3600,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case FS_IOC_REMOVE_ENCRYPTION_KEY: case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: case FS_IOC_GET_ENCRYPTION_KEY_STATUS: + case FS_IOC_GET_ENCRYPTION_NONCE: case F2FS_IOC_GARBAGE_COLLECT: case F2FS_IOC_GARBAGE_COLLECT_RANGE: case F2FS_IOC_WRITE_CHECKPOINT: @@ -3404,6 +3616,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case F2FS_IOC_RESIZE_FS: case FS_IOC_ENABLE_VERITY: case FS_IOC_MEASURE_VERITY: + case F2FS_IOC_GET_COMPRESS_BLOCKS: break; default: return -ENOIOCTLCMD; @@ -3414,7 +3627,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) const struct file_operations f2fs_file_operations = { .llseek = f2fs_llseek, - .read_iter = generic_file_read_iter, + .read_iter = f2fs_file_read_iter, .write_iter = f2fs_file_write_iter, .open = f2fs_file_open, .release = f2fs_release_file, diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 088d29017a58c5901ecf8eab7a274d881a9cf845..0c03f7d05fa6f6cc6c4e4eeccd103ca98107bae3 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -31,6 +31,8 @@ static int gc_thread_func(void *data) set_freezable(); do { + bool sync_mode; + wait_event_interruptible_timeout(*wq, kthread_should_stop() || freezing(current) || gc_th->gc_wake, @@ -78,18 +80,18 @@ static int gc_thread_func(void *data) */ if (sbi->gc_mode == GC_URGENT) { wait_ms = gc_th->urgent_sleep_time; - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); goto do_gc; } - if (!mutex_trylock(&sbi->gc_mutex)) { + if (!down_write_trylock(&sbi->gc_lock)) { stat_other_skip_bggc_count(sbi); goto next; } if (!is_idle(sbi, GC_TIME)) { increase_sleep_time(gc_th, &wait_ms); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); stat_io_skip_bggc_count(sbi); goto next; } @@ -99,17 +101,19 @@ static int gc_thread_func(void *data) else increase_sleep_time(gc_th, &wait_ms); do_gc: - stat_inc_bggc_count(sbi); + stat_inc_bggc_count(sbi->stat_info); + + sync_mode = F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC; /* if return value is not zero, no victim was selected */ - if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO)) + if (f2fs_gc(sbi, sync_mode, true, NULL_SEGNO)) wait_ms = gc_th->no_gc_sleep_time; trace_f2fs_background_gc(sbi->sb, wait_ms, prefree_segments(sbi), free_segments(sbi)); /* balancing f2fs's metadata periodically */ - f2fs_balance_fs_bg(sbi); + f2fs_balance_fs_bg(sbi, true); next: sb_end_write(sbi->sb); @@ -192,7 +196,10 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, p->ofs_unit = sbi->segs_per_sec; } - /* we need to check every dirty segments in the FG_GC case */ + /* + * adjust candidates range, should select all dirty segments for + * foreground GC and urgent GC cases. + */ if (gc_type != FG_GC && (sbi->gc_mode != GC_URGENT) && p->max_search > sbi->max_victim_search) @@ -634,7 +641,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, } *nofs = ofs_of_node(node_page); - source_blkaddr = datablock_addr(NULL, node_page, ofs_in_node); + source_blkaddr = data_blkaddr(NULL, node_page, ofs_in_node); f2fs_put_page(node_page, 1); if (source_blkaddr != blkaddr) { @@ -730,6 +737,9 @@ static int ra_data_block(struct inode *inode, pgoff_t index) goto put_encrypted_page; f2fs_put_page(fio.encrypted_page, 0); f2fs_put_page(page, 1); + + f2fs_update_iostat(sbi, FS_DATA_READ_IO, F2FS_BLKSIZE); + return 0; put_encrypted_page: f2fs_put_page(fio.encrypted_page, 1); @@ -762,7 +772,7 @@ static int move_data_block(struct inode *inode, block_t bidx, struct page *page, *mpage; block_t newaddr; int err = 0; - bool lfs_mode = test_opt(fio.sbi, LFS); + bool lfs_mode = f2fs_lfs_mode(fio.sbi); /* do not read out */ page = f2fs_grab_cache_page(inode->i_mapping, bidx, false); @@ -834,6 +844,9 @@ static int move_data_block(struct inode *inode, block_t bidx, f2fs_put_page(mpage, 1); goto up_out; } + + f2fs_update_iostat(fio.sbi, FS_DATA_READ_IO, F2FS_BLKSIZE); + lock_page(mpage); if (unlikely(mpage->mapping != META_MAPPING(fio.sbi) || !PageUptodate(mpage))) { @@ -971,7 +984,8 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type, if (err) { clear_cold_data(page); if (err == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); goto retry; } if (is_dirty) @@ -1019,8 +1033,8 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, * race condition along with SSR block allocation. */ if ((gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) || - get_valid_blocks(sbi, segno, false) == - sbi->blocks_per_seg) + get_valid_blocks(sbi, segno, true) == + BLKS_PER_SEC(sbi)) return submitted; if (check_valid_map(sbi, segno, off) == 0) @@ -1050,8 +1064,10 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (phase == 3) { inode = f2fs_iget(sb, dni.ino); - if (IS_ERR(inode) || is_bad_inode(inode)) + if (IS_ERR(inode) || is_bad_inode(inode)) { + set_sbi_flag(sbi, SBI_NEED_FSCK); continue; + } if (!down_write_trylock( &F2FS_I(inode)->i_gc_rwsem[WRITE])) { @@ -1202,7 +1218,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, if (get_valid_blocks(sbi, segno, false) == 0) goto freed; - if (__is_large_section(sbi) && + if (gc_type == BG_GC && __is_large_section(sbi) && migrated >= sbi->migration_granularity) goto skip; if (!PageUptodate(sum_page) || unlikely(f2fs_cp_error(sbi))) @@ -1232,12 +1248,12 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, segno, gc_type); stat_inc_seg_count(sbi, type, gc_type); + migrated++; freed: if (gc_type == FG_GC && get_valid_blocks(sbi, segno, false) == 0) seg_freed++; - migrated++; if (__is_large_section(sbi) && segno + 1 < end_segno) sbi->next_victim_seg[gc_type] = segno + 1; @@ -1369,7 +1385,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, reserved_segments(sbi), prefree_segments(sbi)); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); put_gc_inode(&gc_list); @@ -1408,9 +1424,9 @@ static int free_segment_range(struct f2fs_sb_info *sbi, unsigned int start, .iroot = RADIX_TREE_INIT(GFP_NOFS), }; - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); do_garbage_collect(sbi, segno, &gc_list, FG_GC); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); put_gc_inode(&gc_list); if (get_valid_blocks(sbi, segno, true)) @@ -1433,12 +1449,19 @@ static int free_segment_range(struct f2fs_sb_info *sbi, unsigned int start, static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs) { struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi); - int section_count = le32_to_cpu(raw_sb->section_count); - int segment_count = le32_to_cpu(raw_sb->segment_count); - int segment_count_main = le32_to_cpu(raw_sb->segment_count_main); - long long block_count = le64_to_cpu(raw_sb->block_count); + int section_count; + int segment_count; + int segment_count_main; + long long block_count; int segs = secs * sbi->segs_per_sec; + down_write(&sbi->sb_lock); + + section_count = le32_to_cpu(raw_sb->section_count); + segment_count = le32_to_cpu(raw_sb->segment_count); + segment_count_main = le32_to_cpu(raw_sb->segment_count_main); + block_count = le64_to_cpu(raw_sb->block_count); + raw_sb->section_count = cpu_to_le32(section_count + secs); raw_sb->segment_count = cpu_to_le32(segment_count + segs); raw_sb->segment_count_main = cpu_to_le32(segment_count_main + segs); @@ -1452,6 +1475,8 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs) raw_sb->devs[last_dev].total_segments = cpu_to_le32(dev_segs + segs); } + + up_write(&sbi->sb_lock); } static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs) @@ -1569,11 +1594,17 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count) goto out; } + mutex_lock(&sbi->cp_mutex); update_fs_metadata(sbi, -secs); clear_sbi_flag(sbi, SBI_IS_RESIZEFS); + set_sbi_flag(sbi, SBI_IS_DIRTY); + mutex_unlock(&sbi->cp_mutex); + err = f2fs_sync_fs(sbi->sb, 1); if (err) { + mutex_lock(&sbi->cp_mutex); update_fs_metadata(sbi, secs); + mutex_unlock(&sbi->cp_mutex); update_sb_metadata(sbi, secs); f2fs_commit_super(sbi, false); } diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index 5bc4dcd8fc03fbbb97ece6233c925634dc972fa8..8f7ee4362312b3398d79f1a36ad459f8134ee1aa 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -68,8 +68,9 @@ static void str2hashbuf(const unsigned char *msg, size_t len, *buf++ = pad; } -static f2fs_hash_t __f2fs_dentry_hash(const struct qstr *name_info, - struct fscrypt_name *fname) +static f2fs_hash_t __f2fs_dentry_hash(const struct inode *dir, + const struct qstr *name_info, + const struct fscrypt_name *fname) { __u32 hash; f2fs_hash_t f2fs_hash; @@ -79,12 +80,17 @@ static f2fs_hash_t __f2fs_dentry_hash(const struct qstr *name_info, size_t len = name_info->len; /* encrypted bigname case */ - if (fname && !fname->disk_name.name) + if (fname && fname->is_ciphertext_name) return cpu_to_le32(fname->hash); if (is_dot_dotdot(name_info)) return 0; + if (IS_CASEFOLDED(dir) && IS_ENCRYPTED(dir)) { + f2fs_hash = cpu_to_le32(fscrypt_fname_siphash(dir, name_info)); + return f2fs_hash; + } + /* Initialize the default seed for the hash checksum functions */ buf[0] = 0x67452301; buf[1] = 0xefcdab89; @@ -106,35 +112,38 @@ static f2fs_hash_t __f2fs_dentry_hash(const struct qstr *name_info, } f2fs_hash_t f2fs_dentry_hash(const struct inode *dir, - const struct qstr *name_info, struct fscrypt_name *fname) + const struct qstr *name_info, const struct fscrypt_name *fname) { #ifdef CONFIG_UNICODE struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); - const struct unicode_map *um = sbi->s_encoding; + const struct unicode_map *um = dir->i_sb->s_encoding; int r, dlen; unsigned char *buff; struct qstr folded; + const struct qstr *name = fname ? fname->usr_fname : name_info; if (!name_info->len || !IS_CASEFOLDED(dir)) goto opaque_seq; + if (IS_ENCRYPTED(dir) && !fscrypt_has_encryption_key(dir)) + goto opaque_seq; + buff = f2fs_kzalloc(sbi, sizeof(char) * PATH_MAX, GFP_KERNEL); if (!buff) return -ENOMEM; - - dlen = utf8_casefold(um, name_info, buff, PATH_MAX); + dlen = utf8_casefold(um, name, buff, PATH_MAX); if (dlen < 0) { kvfree(buff); goto opaque_seq; } folded.name = buff; folded.len = dlen; - r = __f2fs_dentry_hash(&folded, fname); + r = __f2fs_dentry_hash(dir, &folded, fname); kvfree(buff); return r; opaque_seq: #endif - return __f2fs_dentry_hash(name_info, fname); + return __f2fs_dentry_hash(dir, name_info, fname); } diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 74aa7b143ae244a6a939bd85b32735f2162a912f..b01e0ac34f8c84d40fcc8084fa94a2de02eecea8 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -385,7 +385,7 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage, struct f2fs_dentry_ptr src, dst; int err; - page = f2fs_grab_cache_page(dir->i_mapping, 0, false); + page = f2fs_grab_cache_page(dir->i_mapping, 0, true); if (!page) { f2fs_put_page(ipage, 1); return -ENOMEM; @@ -482,8 +482,8 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry) ino = le32_to_cpu(de->ino); fake_mode = f2fs_get_de_type(de) << S_SHIFT; - err = f2fs_add_regular_entry(dir, &new_name, NULL, NULL, - ino, fake_mode); + err = f2fs_add_regular_entry(dir, &new_name, NULL, + de->hash_code, NULL, ino, fake_mode); if (err) goto punch_dentry_pages; @@ -547,7 +547,7 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage, return err; } -static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, +static int do_convert_inline_dir(struct inode *dir, struct page *ipage, void *inline_dentry) { if (!F2FS_I(dir)->i_dir_level) @@ -556,8 +556,46 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry); } +int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct page *ipage; + struct fscrypt_name fname; + void *inline_dentry = NULL; + int err = 0; + + if (!f2fs_has_inline_dentry(dir)) + return 0; + + f2fs_lock_op(sbi); + + err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname); + if (err) + goto out; + + ipage = f2fs_get_node_page(sbi, dir->i_ino); + if (IS_ERR(ipage)) { + err = PTR_ERR(ipage); + goto out; + } + + if (f2fs_has_enough_room(dir, ipage, &fname)) { + f2fs_put_page(ipage, 1); + goto out; + } + + inline_dentry = inline_data_addr(dir, ipage); + + err = do_convert_inline_dir(dir, ipage, inline_dentry); + if (!err) + f2fs_put_page(ipage, 1); +out: + f2fs_unlock_op(sbi); + return err; +} + int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, - const struct qstr *orig_name, + const struct fscrypt_name *fname, struct inode *inode, nid_t ino, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); @@ -568,6 +606,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, struct f2fs_dentry_ptr d; int slots = GET_DENTRY_SLOTS(new_name->len); struct page *page = NULL; + const struct qstr *orig_name = fname->usr_fname; int err = 0; ipage = f2fs_get_node_page(sbi, dir->i_ino); @@ -579,7 +618,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, bit_pos = f2fs_room_for_filename(d.bitmap, slots, d.max); if (bit_pos >= d.max) { - err = f2fs_convert_inline_dir(dir, ipage, inline_dentry); + err = do_convert_inline_dir(dir, ipage, inline_dentry); if (err) return err; err = -EAGAIN; @@ -598,7 +637,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, f2fs_wait_on_page_writeback(ipage, NODE, true, true); - name_hash = f2fs_dentry_hash(dir, new_name, NULL); + name_hash = f2fs_dentry_hash(dir, new_name, fname); f2fs_update_dentry(ino, mode, &d, new_name, name_hash, bit_pos); set_page_dirty(ipage); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index e3ee44ca3450cfd121da7518bf32c10dd5ad0ea4..482d267f4a639cd955523378e341c5283a3d4ace 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -200,6 +200,7 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_inode *ri = F2FS_INODE(node_page); unsigned long long iblocks; iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks); @@ -286,6 +287,36 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page) return false; } + if (f2fs_has_extra_attr(inode) && f2fs_sb_has_compression(sbi) && + fi->i_flags & F2FS_COMPR_FL && + F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, + i_log_cluster_size)) { + if (ri->i_compress_algorithm >= COMPRESS_MAX) { + f2fs_warn(sbi, "%s: inode (ino=%lx) has unsupported " + "compress algorithm: %u, run fsck to fix", + __func__, inode->i_ino, + ri->i_compress_algorithm); + return false; + } + if (le64_to_cpu(ri->i_compr_blocks) > + SECTOR_TO_BLOCK(inode->i_blocks)) { + f2fs_warn(sbi, "%s: inode (ino=%lx) has inconsistent " + "i_compr_blocks:%llu, i_blocks:%lu, run fsck to fix", + __func__, inode->i_ino, + le64_to_cpu(ri->i_compr_blocks), + SECTOR_TO_BLOCK(inode->i_blocks)); + return false; + } + if (ri->i_log_cluster_size < MIN_COMPRESS_LOG_SIZE || + ri->i_log_cluster_size > MAX_COMPRESS_LOG_SIZE) { + f2fs_warn(sbi, "%s: inode (ino=%lx) has unsupported " + "log cluster size: %u, run fsck to fix", + __func__, inode->i_ino, + ri->i_log_cluster_size); + return false; + } + } + return true; } @@ -331,7 +362,7 @@ static int do_read_inode(struct inode *inode) fi->i_flags = le32_to_cpu(ri->i_flags); if (S_ISREG(inode->i_mode)) fi->i_flags &= ~F2FS_PROJINHERIT_FL; - fi->flags = 0; + bitmap_zero(fi->flags, FI_MAX); fi->i_advise = ri->i_advise; fi->i_pino = le32_to_cpu(ri->i_pino); fi->i_dir_level = ri->i_dir_level; @@ -407,6 +438,18 @@ static int do_read_inode(struct inode *inode) fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec); } + if (f2fs_has_extra_attr(inode) && f2fs_sb_has_compression(sbi) && + (fi->i_flags & F2FS_COMPR_FL)) { + if (F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, + i_log_cluster_size)) { + fi->i_compr_blocks = le64_to_cpu(ri->i_compr_blocks); + fi->i_compress_algorithm = ri->i_compress_algorithm; + fi->i_log_cluster_size = ri->i_log_cluster_size; + fi->i_cluster_size = 1 << fi->i_log_cluster_size; + set_inode_flag(inode, FI_COMPRESSED_FILE); + } + } + F2FS_I(inode)->i_disk_time[0] = inode->i_atime; F2FS_I(inode)->i_disk_time[1] = inode->i_ctime; F2FS_I(inode)->i_disk_time[2] = inode->i_mtime; @@ -416,6 +459,8 @@ static int do_read_inode(struct inode *inode) stat_inc_inline_xattr(inode); stat_inc_inline_inode(inode); stat_inc_inline_dir(inode); + stat_inc_compr_inode(inode); + stat_add_compr_blocks(inode, F2FS_I(inode)->i_compr_blocks); return 0; } @@ -490,7 +535,7 @@ struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino) inode = f2fs_iget(sb, ino); if (IS_ERR(inode)) { if (PTR_ERR(inode) == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); goto retry; } } @@ -569,6 +614,17 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page) ri->i_crtime_nsec = cpu_to_le32(F2FS_I(inode)->i_crtime.tv_nsec); } + + if (f2fs_sb_has_compression(F2FS_I_SB(inode)) && + F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize, + i_log_cluster_size)) { + ri->i_compr_blocks = + cpu_to_le64(F2FS_I(inode)->i_compr_blocks); + ri->i_compress_algorithm = + F2FS_I(inode)->i_compress_algorithm; + ri->i_log_cluster_size = + F2FS_I(inode)->i_log_cluster_size; + } } __set_inode_rdev(inode, ri); @@ -711,6 +767,8 @@ void f2fs_evict_inode(struct inode *inode) stat_dec_inline_xattr(inode); stat_dec_inline_dir(inode); stat_dec_inline_inode(inode); + stat_dec_compr_inode(inode); + stat_sub_compr_blocks(inode, F2FS_I(inode)->i_compr_blocks); if (unlikely(is_inode_flag_set(inode, FI_DIRTY_INODE))) { f2fs_inode_synced(inode); @@ -721,7 +779,7 @@ void f2fs_evict_inode(struct inode *inode) f2fs_bug_on(sbi, 1); } - /* ino == 0, if f2fs_new_inode() was failed t*/ + /* for the case f2fs_new_inode() was failed, .i_ino is zero, skip it */ if (inode->i_ino) invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 2a97d6215102a61ba16fb681b9ea78ee223954a9..a8959c64bf3a5efe3ff71dbc806c2f08d29c20f0 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -75,9 +75,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) set_inode_flag(inode, FI_NEW_INODE); - /* If the directory encrypted, then we should encrypt the inode. */ - if ((IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) && - f2fs_may_encrypt(inode)) + if (f2fs_may_encrypt(dir, inode)) f2fs_set_encrypted_inode(inode); if (f2fs_sb_has_extra_attr(sbi)) { @@ -119,6 +117,13 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL) set_inode_flag(inode, FI_PROJ_INHERIT); + if (f2fs_sb_has_compression(sbi)) { + /* Inherit the compression flag in directory */ + if ((F2FS_I(dir)->i_flags & F2FS_COMPR_FL) && + f2fs_may_compress(inode)) + set_compress_context(inode); + } + f2fs_set_inode_flags(inode); trace_f2fs_new_inode(inode, 0); @@ -149,6 +154,9 @@ static inline int is_extension_exist(const unsigned char *s, const char *sub) size_t sublen = strlen(sub); int i; + if (sublen == 1 && *sub == '*') + return 1; + /* * filename format of multimedia file should be defined as: * "filename + '.' + extension + (optional: '.' + temp extension)". @@ -167,7 +175,7 @@ static inline int is_extension_exist(const unsigned char *s, const char *sub) } /* - * Set multimedia files as cold files for hot/cold data separation + * Set file's temperature for hot/cold data separation */ static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode, const unsigned char *name) @@ -262,6 +270,45 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name, return 0; } +static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode, + const unsigned char *name) +{ + __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; + unsigned char (*ext)[F2FS_EXTENSION_LEN]; + unsigned int ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; + int i, cold_count, hot_count; + + if (!f2fs_sb_has_compression(sbi) || + is_inode_flag_set(inode, FI_COMPRESSED_FILE) || + F2FS_I(inode)->i_flags & F2FS_NOCOMP_FL || + !f2fs_may_compress(inode)) + return; + + down_read(&sbi->sb_lock); + + cold_count = le32_to_cpu(sbi->raw_super->extension_count); + hot_count = sbi->raw_super->hot_ext_count; + + for (i = cold_count; i < cold_count + hot_count; i++) { + if (is_extension_exist(name, extlist[i])) { + up_read(&sbi->sb_lock); + return; + } + } + + up_read(&sbi->sb_lock); + + ext = F2FS_OPTION(sbi).extensions; + + for (i = 0; i < ext_cnt; i++) { + if (!is_extension_exist(name, ext[i])) + continue; + + set_compress_context(inode); + return; + } +} + static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { @@ -286,6 +333,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) set_file_temperature(sbi, inode, dentry->d_name.name); + set_compress_inode(sbi, inode, dentry->d_name.name); + inode->i_op = &f2fs_file_inode_operations; inode->i_fop = &f2fs_file_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; @@ -443,6 +492,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, } err = fscrypt_prepare_lookup(dir, dentry, &fname); + generic_set_encrypted_ci_d_ops(dir, dentry); if (err == -ENOENT) goto out_splice; if (err) @@ -797,6 +847,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, if (whiteout) { f2fs_i_links_write(inode, false); + inode->i_state |= I_LINKABLE; *whiteout = inode; } else { d_tmpfile(dentry, inode); @@ -824,12 +875,6 @@ static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) if (!f2fs_is_checkpoint_ready(sbi)) return -ENOSPC; - if (IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) { - int err = fscrypt_get_encryption_info(dir); - if (err) - return err; - } - return __f2fs_tmpfile(dir, dentry, mode, NULL); } @@ -849,12 +894,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *old_inode = d_inode(old_dentry); struct inode *new_inode = d_inode(new_dentry); struct inode *whiteout = NULL; - struct page *old_dir_page; + struct page *old_dir_page = NULL; struct page *old_page, *new_page = NULL; struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; - bool is_old_inline = f2fs_has_inline_dentry(old_dir); int err; if (unlikely(f2fs_cp_error(sbi))) @@ -867,6 +911,26 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, F2FS_I(old_dentry->d_inode)->i_projid))) return -EXDEV; + /* + * If new_inode is null, the below renaming flow will + * add a link in old_dir which can conver inline_dir. + * After then, if we failed to get the entry due to other + * reasons like ENOMEM, we had to remove the new entry. + * Instead of adding such the error handling routine, let's + * simply convert first here. + */ + if (old_dir == new_dir && !new_inode) { + err = f2fs_try_convert_inline_dir(old_dir, new_dentry); + if (err) + return err; + } + + if (flags & RENAME_WHITEOUT) { + err = f2fs_create_whiteout(old_dir, &whiteout); + if (err) + return err; + } + err = dquot_initialize(old_dir); if (err) goto out; @@ -898,17 +962,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, } } - if (flags & RENAME_WHITEOUT) { - err = f2fs_create_whiteout(old_dir, &whiteout); - if (err) - goto out_dir; - } - if (new_inode) { err = -ENOTEMPTY; if (old_dir_entry && !f2fs_empty_dir(new_inode)) - goto out_whiteout; + goto out_dir; err = -ENOENT; new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, @@ -916,7 +974,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, if (!new_entry) { if (IS_ERR(new_page)) err = PTR_ERR(new_page); - goto out_whiteout; + goto out_dir; } f2fs_balance_fs(sbi, true); @@ -928,6 +986,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, goto put_out_dir; f2fs_set_link(new_dir, new_entry, new_page, old_inode); + new_page = NULL; new_inode->i_ctime = current_time(new_inode); down_write(&F2FS_I(new_inode)->i_sem); @@ -948,33 +1007,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, err = f2fs_add_link(new_dentry, old_inode); if (err) { f2fs_unlock_op(sbi); - goto out_whiteout; + goto out_dir; } if (old_dir_entry) f2fs_i_links_write(new_dir, true); - - /* - * old entry and new entry can locate in the same inline - * dentry in inode, when attaching new entry in inline dentry, - * it could force inline dentry conversion, after that, - * old_entry and old_page will point to wrong address, in - * order to avoid this, let's do the check and update here. - */ - if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) { - f2fs_put_page(old_page, 0); - old_page = NULL; - - old_entry = f2fs_find_entry(old_dir, - &old_dentry->d_name, &old_page); - if (!old_entry) { - err = -ENOENT; - if (IS_ERR(old_page)) - err = PTR_ERR(old_page); - f2fs_unlock_op(sbi); - goto out_whiteout; - } - } } down_write(&F2FS_I(old_inode)->i_sem); @@ -989,9 +1026,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, f2fs_mark_inode_dirty_sync(old_inode, false); f2fs_delete_entry(old_entry, old_page, old_dir, NULL); + old_page = NULL; if (whiteout) { - whiteout->i_state |= I_LINKABLE; set_inode_flag(whiteout, FI_INC_LINK); err = f2fs_add_link(old_dentry, whiteout); if (err) @@ -1025,17 +1062,15 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, put_out_dir: f2fs_unlock_op(sbi); - if (new_page) - f2fs_put_page(new_page, 0); -out_whiteout: - if (whiteout) - iput(whiteout); + f2fs_put_page(new_page, 0); out_dir: if (old_dir_entry) f2fs_put_page(old_dir_page, 0); out_old: f2fs_put_page(old_page, 0); out: + if (whiteout) + iput(whiteout); return err; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index dcacdab66558811d832d42c9e68e45bd6ebf168a..1e80fa16fb01be745dd915968c93cd073aca532d 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -510,9 +510,6 @@ int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) return nr - nr_shrink; } -/* - * This function always returns success - */ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) { @@ -714,8 +711,7 @@ static int get_node_path(struct inode *inode, long block, /* * Caller should call f2fs_put_dnode(dn). * Also, it should grab and release a rwsem by calling f2fs_lock_op() and - * f2fs_unlock_op() only if ro is not set RDONLY_NODE. - * In the case of RDONLY_NODE, we don't need to care about mutex. + * f2fs_unlock_op() only if mode is set with ALLOC_NODE. */ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) { @@ -807,8 +803,7 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) dn->nid = nids[level]; dn->ofs_in_node = offset[level]; dn->node_page = npage[level]; - dn->data_blkaddr = datablock_addr(dn->inode, - dn->node_page, dn->ofs_in_node); + dn->data_blkaddr = f2fs_data_blkaddr(dn); return 0; release_pages: @@ -1184,8 +1179,9 @@ int f2fs_remove_inode_page(struct inode *inode) } if (unlikely(inode->i_blocks != 0 && inode->i_blocks != 8)) { - f2fs_warn(F2FS_I_SB(inode), "Inconsistent i_blocks, ino:%lu, iblocks:%llu", - inode->i_ino, (unsigned long long)inode->i_blocks); + f2fs_warn(F2FS_I_SB(inode), + "f2fs_remove_inode_page: inconsistent i_blocks, ino:%lu, iblocks:%llu", + inode->i_ino, (unsigned long long)inode->i_blocks); set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK); } @@ -1300,7 +1296,13 @@ static int read_node_page(struct page *page, int op_flags) } fio.new_blkaddr = fio.old_blkaddr = ni.blk_addr; - return f2fs_submit_page_bio(&fio); + + err = f2fs_submit_page_bio(&fio); + + if (!err) + f2fs_update_iostat(sbi, FS_NODE_READ_IO, F2FS_BLKSIZE); + + return err; } /* @@ -1560,15 +1562,16 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, if (atomic && !test_opt(sbi, NOBARRIER)) fio.op_flags |= REQ_PREFLUSH | REQ_FUA; - set_page_writeback(page); - ClearPageError(page); - + /* should add to global list before clearing PAGECACHE status */ if (f2fs_in_warm_node_list(sbi, page)) { seq = f2fs_add_fsync_node_entry(sbi, page); if (seq_id) *seq_id = seq; } + set_page_writeback(page); + ClearPageError(page); + fio.old_blkaddr = ni.blk_addr; f2fs_do_write_node_page(nid, &fio); set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page)); @@ -1977,7 +1980,7 @@ static int f2fs_write_node_pages(struct address_space *mapping, goto skip_write; /* balancing f2fs's metadata in background */ - f2fs_balance_fs_bg(sbi); + f2fs_balance_fs_bg(sbi, true); /* collect a number of dirty node pages and write together */ if (wbc->sync_mode != WB_SYNC_ALL && @@ -2594,7 +2597,7 @@ int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) retry: ipage = f2fs_grab_cache_page(NODE_MAPPING(sbi), ino, false); if (!ipage) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); goto retry; } @@ -3184,22 +3187,22 @@ void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi) int __init f2fs_create_node_manager_caches(void) { - nat_entry_slab = f2fs_kmem_cache_create("nat_entry", + nat_entry_slab = f2fs_kmem_cache_create("f2fs_nat_entry", sizeof(struct nat_entry)); if (!nat_entry_slab) goto fail; - free_nid_slab = f2fs_kmem_cache_create("free_nid", + free_nid_slab = f2fs_kmem_cache_create("f2fs_free_nid", sizeof(struct free_nid)); if (!free_nid_slab) goto destroy_nat_entry; - nat_entry_set_slab = f2fs_kmem_cache_create("nat_entry_set", + nat_entry_set_slab = f2fs_kmem_cache_create("f2fs_nat_entry_set", sizeof(struct nat_entry_set)); if (!nat_entry_set_slab) goto destroy_free_nid; - fsync_node_entry_slab = f2fs_kmem_cache_create("fsync_node_entry", + fsync_node_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_node_entry", sizeof(struct fsync_node_entry)); if (!fsync_node_entry_slab) goto destroy_nat_entry_set; diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index f177e2749f19c487db65865bc48ad681487725b9..5288a6f71ca24b3353eb2ed63e594ab614d133c3 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -496,8 +496,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, return 0; truncate_out: - if (datablock_addr(tdn.inode, tdn.node_page, - tdn.ofs_in_node) == blkaddr) + if (f2fs_data_blkaddr(&tdn) == blkaddr) f2fs_truncate_data_blocks_range(&tdn, 1); if (dn->inode->i_ino == nid && !dn->inode_page_locked) unlock_page(dn->inode_page); @@ -535,7 +534,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, err = f2fs_get_dnode_of_data(&dn, start, ALLOC_NODE); if (err) { if (err == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); goto retry_dn; } goto out; @@ -560,8 +559,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, for (; start < end; start++, dn.ofs_in_node++) { block_t src, dest; - src = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node); - dest = datablock_addr(dn.inode, page, dn.ofs_in_node); + src = f2fs_data_blkaddr(&dn); + dest = data_blkaddr(dn.inode, page, dn.ofs_in_node); if (__is_valid_data_blkaddr(src) && !f2fs_is_valid_blkaddr(sbi, src, META_POR)) { @@ -618,7 +617,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, err = check_index_in_prev_nodes(sbi, dest, &dn); if (err) { if (err == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); goto retry_prev; } goto err; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 8cf86a71edaa08325569dac875d8aa1bd90cf076..6da162a71105a9ecc3494d765da014e300396482 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -172,7 +172,7 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi) int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); - if (test_opt(sbi, LFS)) + if (f2fs_lfs_mode(sbi)) return false; if (sbi->gc_mode == GC_URGENT) return true; @@ -245,7 +245,8 @@ static int __revoke_inmem_pages(struct inode *inode, LOOKUP_NODE); if (err) { if (err == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); cond_resched(); goto retry; } @@ -310,7 +311,7 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure) skip: iput(inode); } - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); cond_resched(); if (gc_failure) { if (++looped >= count) @@ -332,7 +333,6 @@ void f2fs_drop_inmem_pages(struct inode *inode) } fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0; - stat_dec_atomic_write(inode); spin_lock(&sbi->inode_lock[ATOMIC_FILE]); if (!list_empty(&fi->inmem_ilist)) @@ -414,7 +414,8 @@ static int __f2fs_commit_inmem_pages(struct inode *inode) err = f2fs_do_write_data_page(&fio); if (err) { if (err == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); cond_resched(); goto retry; } @@ -493,7 +494,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) /* balance_fs_bg is able to be pending */ if (need && excess_cached_nats(sbi)) - f2fs_balance_fs_bg(sbi); + f2fs_balance_fs_bg(sbi, false); if (!f2fs_is_checkpoint_ready(sbi)) return; @@ -503,12 +504,12 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) * dir/node pages without enough free segments. */ if (has_not_enough_free_secs(sbi, 0, 0)) { - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); f2fs_gc(sbi, false, false, NULL_SEGNO); } } -void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) +void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg) { if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) return; @@ -537,7 +538,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) || f2fs_time_over(sbi, CP_TIME)) { - if (test_opt(sbi, DATA_FLUSH)) { + if (test_opt(sbi, DATA_FLUSH) && from_bg) { struct blk_plug plug; mutex_lock(&sbi->flush_lock); @@ -1026,9 +1027,9 @@ static void f2fs_submit_discard_endio(struct bio *bio) struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private; unsigned long flags; - dc->error = blk_status_to_errno(bio->bi_status); - spin_lock_irqsave(&dc->lock, flags); + if (!dc->error) + dc->error = blk_status_to_errno(bio->bi_status); dc->bio_ref--; if (!dc->bio_ref && dc->state == D_SUBMIT) { dc->state = D_DONE; @@ -1077,7 +1078,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; dpolicy->io_aware_gran = MAX_PLIST_NUM; - dpolicy->timeout = 0; + dpolicy->timeout = false; if (discard_type == DPOLICY_BG) { dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; @@ -1098,10 +1099,10 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, } else if (discard_type == DPOLICY_FSTRIM) { dpolicy->io_aware = false; } else if (discard_type == DPOLICY_UMOUNT) { - dpolicy->max_requests = UINT_MAX; dpolicy->io_aware = false; /* we need to issue all to keep CP_TRIMMED_FLAG */ dpolicy->granularity = 1; + dpolicy->timeout = true; } } @@ -1211,8 +1212,10 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, len = total_len; } - if (!err && len) + if (!err && len) { + dcc->undiscard_blks -= len; __update_discard_tree_range(sbi, bdev, lstart, start, len); + } return err; } @@ -1459,6 +1462,8 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, return issued; } +static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi, + struct discard_policy *dpolicy); static int __issue_discard_cmd(struct f2fs_sb_info *sbi, struct discard_policy *dpolicy) @@ -1467,15 +1472,17 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, struct list_head *pend_list; struct discard_cmd *dc, *tmp; struct blk_plug plug; - int i, issued = 0; + int i, issued; bool io_interrupted = false; - if (dpolicy->timeout != 0) - f2fs_update_time(sbi, dpolicy->timeout); + if (dpolicy->timeout) + f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT); +retry: + issued = 0; for (i = MAX_PLIST_NUM - 1; i >= 0; i--) { - if (dpolicy->timeout != 0 && - f2fs_time_over(sbi, dpolicy->timeout)) + if (dpolicy->timeout && + f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT)) break; if (i + 1 < dpolicy->granularity) @@ -1496,8 +1503,8 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, list_for_each_entry_safe(dc, tmp, pend_list, list) { f2fs_bug_on(sbi, dc->state != D_PREP); - if (dpolicy->timeout != 0 && - f2fs_time_over(sbi, dpolicy->timeout)) + if (dpolicy->timeout && + f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT)) break; if (dpolicy->io_aware && i < dpolicy->io_aware_gran && @@ -1519,6 +1526,11 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, break; } + if (dpolicy->type == DPOLICY_UMOUNT && issued) { + __wait_all_discard_cmd(sbi, dpolicy); + goto retry; + } + if (!issued && io_interrupted) issued = -1; @@ -1676,7 +1688,6 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, dcc->discard_granularity); - dpolicy.timeout = UMOUNT_DISCARD_TIMEOUT; __issue_discard_cmd(sbi, &dpolicy); dropped = __drop_discard_cmd(sbi); @@ -1938,7 +1949,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, unsigned int start = 0, end = -1; unsigned int secno, start_segno; bool force = (cpc->reason & CP_DISCARD); - bool need_align = test_opt(sbi, LFS) && __is_large_section(sbi); + bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi); mutex_lock(&dirty_i->seglist_lock); @@ -1970,7 +1981,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, (end - 1) <= cpc->trim_end) continue; - if (!test_opt(sbi, LFS) || !__is_large_section(sbi)) { + if (!f2fs_lfs_mode(sbi) || !__is_large_section(sbi)) { f2fs_issue_discard(sbi, START_BLOCK(sbi, start), (end - start) << sbi->log_blocks_per_seg); continue; @@ -2222,7 +2233,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) struct sit_info *sit_i = SIT_I(sbi); f2fs_bug_on(sbi, addr == NULL_ADDR); - if (addr == NEW_ADDR) + if (addr == NEW_ADDR || addr == COMPRESS_ADDR) return; invalidate_mapping_pages(META_MAPPING(sbi), addr, addr); @@ -2799,7 +2810,7 @@ static unsigned int __issue_discard_cmd_range(struct f2fs_sb_info *sbi, blk_finish_plug(&plug); mutex_unlock(&dcc->cmd_lock); trimmed += __wait_all_discard_cmd(sbi, NULL); - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); goto next; } skip: @@ -2828,7 +2839,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) struct discard_policy dpolicy; unsigned long long trimmed = 0; int err = 0; - bool need_align = test_opt(sbi, LFS) && __is_large_section(sbi); + bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi); if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) return -EINVAL; @@ -2858,9 +2869,9 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) if (sbi->discard_blks == 0) goto out; - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); err = f2fs_write_checkpoint(sbi, &cpc); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); if (err) goto out; @@ -3033,7 +3044,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) if (fio->type == DATA) { struct inode *inode = fio->page->mapping->host; - if (is_cold_data(fio->page) || file_is_cold(inode)) + if (is_cold_data(fio->page) || file_is_cold(inode) || + f2fs_compressed_file(inode)) return CURSEG_COLD_DATA; if (file_is_hot(inode) || is_inode_flag_set(inode, FI_HOT_DATA) || @@ -3190,7 +3202,7 @@ static void update_device_state(struct f2fs_io_info *fio) static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) { int type = __get_segment_type(fio); - bool keep_order = (test_opt(fio->sbi, LFS) && type == CURSEG_COLD_DATA); + bool keep_order = (f2fs_lfs_mode(fio->sbi) && type == CURSEG_COLD_DATA); if (keep_order) down_read(&fio->sbi->io_order_lock); @@ -3286,7 +3298,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) stat_inc_inplace_blocks(fio->sbi); - if (fio->bio) + if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) err = f2fs_merge_page_bio(fio); else err = f2fs_submit_page_bio(fio); @@ -4068,7 +4080,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi) sit_i->dirty_sentries = 0; sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time); - sit_i->mounted_time = ktime_get_real_seconds(); + sit_i->mounted_time = ktime_get_boottime_seconds(); init_rwsem(&sit_i->sentry_lock); return 0; } @@ -4418,7 +4430,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi) if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS) sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS; - if (!test_opt(sbi, LFS)) + if (!f2fs_lfs_mode(sbi)) sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; @@ -4570,22 +4582,22 @@ void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi) int __init f2fs_create_segment_manager_caches(void) { - discard_entry_slab = f2fs_kmem_cache_create("discard_entry", + discard_entry_slab = f2fs_kmem_cache_create("f2fs_discard_entry", sizeof(struct discard_entry)); if (!discard_entry_slab) goto fail; - discard_cmd_slab = f2fs_kmem_cache_create("discard_cmd", + discard_cmd_slab = f2fs_kmem_cache_create("f2fs_discard_cmd", sizeof(struct discard_cmd)); if (!discard_cmd_slab) goto destroy_discard_entry; - sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set", + sit_entry_set_slab = f2fs_kmem_cache_create("f2fs_sit_entry_set", sizeof(struct sit_entry_set)); if (!sit_entry_set_slab) goto destroy_discard_cmd; - inmem_entry_slab = f2fs_kmem_cache_create("inmem_page_entry", + inmem_entry_slab = f2fs_kmem_cache_create("f2fs_inmem_page_entry", sizeof(struct inmem_pages)); if (!inmem_entry_slab) goto destroy_sit_entry_set; diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index a95467b202ea2040800f4d87209f317757f62f6a..c476e7ca35957326ecbc29ba85d42895695e521f 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -200,18 +200,6 @@ struct segment_allocation { void (*allocate_segment)(struct f2fs_sb_info *, int, bool); }; -/* - * this value is set in page as a private data which indicate that - * the page is atomically written, and it is in inmem_pages list. - */ -#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1) -#define DUMMY_WRITTEN_PAGE ((unsigned long)-2) - -#define IS_ATOMIC_WRITTEN_PAGE(page) \ - (page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE) -#define IS_DUMMY_WRITTEN_PAGE(page) \ - (page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE) - #define MAX_SKIP_GC_COUNT 16 struct inmem_pages { @@ -619,8 +607,10 @@ static inline int utilization(struct f2fs_sb_info *sbi) * threashold, * F2FS_IPU_FSYNC - activated in fsync path only for high performance flash * storages. IPU will be triggered only if the # of dirty - * pages over min_fsync_blocks. - * F2FS_IPUT_DISABLE - disable IPU. (=default option) + * pages over min_fsync_blocks. (=default option) + * F2FS_IPU_ASYNC - do IPU given by asynchronous write requests. + * F2FS_IPU_NOCACHE - disable IPU bio cache. + * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode) */ #define DEF_MIN_IPU_UTIL 70 #define DEF_MIN_FSYNC_BLOCKS 8 @@ -635,6 +625,7 @@ enum { F2FS_IPU_SSR_UTIL, F2FS_IPU_FSYNC, F2FS_IPU_ASYNC, + F2FS_IPU_NOCACHE, }; static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, @@ -761,11 +752,16 @@ static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start) #endif } +static inline time64_t ktime_get_boottime_seconds(void) +{ + return ktime_divns(ktime_get_boottime(), NSEC_PER_SEC); +} + static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi, bool base_time) { struct sit_info *sit_i = SIT_I(sbi); - time64_t diff, now = ktime_get_real_seconds(); + time64_t diff, now = ktime_get_boottime_seconds(); if (now >= sit_i->mounted_time) return sit_i->elapsed_time + now - sit_i->mounted_time; diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c index a467aca29cfefd8a25a16b125356debc54850e33..d66de5999a26d8bb4b147468e071203c82b70982 100644 --- a/fs/f2fs/shrinker.c +++ b/fs/f2fs/shrinker.c @@ -58,7 +58,7 @@ unsigned long f2fs_shrink_count(struct shrinker *shrink, /* count extent cache entries */ count += __count_extent_cache(sbi); - /* shrink clean nat cache entries */ + /* count clean nat cache entries */ count += __count_nat_entries(sbi); /* count free nids cache entries */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index f06bac3a503e426e9190991fc6aa6f88b19ca88d..fa0a4ae4cf9674b153d7e5898fa8dab81cea519c 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -137,10 +137,14 @@ enum { Opt_alloc, Opt_fsync, Opt_test_dummy_encryption, + Opt_inlinecrypt, Opt_checkpoint_disable, Opt_checkpoint_disable_cap, Opt_checkpoint_disable_cap_perc, Opt_checkpoint_enable, + Opt_compress_algorithm, + Opt_compress_log_size, + Opt_compress_extension, Opt_err, }; @@ -199,10 +203,14 @@ static match_table_t f2fs_tokens = { {Opt_alloc, "alloc_mode=%s"}, {Opt_fsync, "fsync_mode=%s"}, {Opt_test_dummy_encryption, "test_dummy_encryption"}, + {Opt_inlinecrypt, "inlinecrypt"}, {Opt_checkpoint_disable, "checkpoint=disable"}, {Opt_checkpoint_disable_cap, "checkpoint=disable:%u"}, {Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"}, {Opt_checkpoint_enable, "checkpoint=enable"}, + {Opt_compress_algorithm, "compress_algorithm=%s"}, + {Opt_compress_log_size, "compress_log_size=%u"}, + {Opt_compress_extension, "compress_extension=%s"}, {Opt_err, NULL}, }; @@ -391,8 +399,9 @@ static int parse_options(struct super_block *sb, char *options) { struct f2fs_sb_info *sbi = F2FS_SB(sb); substring_t args[MAX_OPT_ARGS]; + unsigned char (*ext)[F2FS_EXTENSION_LEN]; char *p, *name; - int arg = 0; + int arg = 0, ext_cnt; kuid_t uid; kgid_t gid; #ifdef CONFIG_QUOTA @@ -420,14 +429,11 @@ static int parse_options(struct super_block *sb, char *options) if (!name) return -ENOMEM; if (strlen(name) == 2 && !strncmp(name, "on", 2)) { - set_opt(sbi, BG_GC); - clear_opt(sbi, FORCE_FG_GC); + F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; } else if (strlen(name) == 3 && !strncmp(name, "off", 3)) { - clear_opt(sbi, BG_GC); - clear_opt(sbi, FORCE_FG_GC); + F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_OFF; } else if (strlen(name) == 4 && !strncmp(name, "sync", 4)) { - set_opt(sbi, BG_GC); - set_opt(sbi, FORCE_FG_GC); + F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_SYNC; } else { kvfree(name); return -EINVAL; @@ -439,7 +445,7 @@ static int parse_options(struct super_block *sb, char *options) break; case Opt_norecovery: /* this option mounts f2fs with ro */ - set_opt(sbi, DISABLE_ROLL_FORWARD); + set_opt(sbi, NORECOVERY); if (!f2fs_readonly(sb)) return -EINVAL; break; @@ -593,10 +599,10 @@ static int parse_options(struct super_block *sb, char *options) kvfree(name); return -EINVAL; } - set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE); + F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; } else if (strlen(name) == 3 && !strncmp(name, "lfs", 3)) { - set_opt_mode(sbi, F2FS_MOUNT_LFS); + F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; } else { kvfree(name); return -EINVAL; @@ -783,6 +789,13 @@ static int parse_options(struct super_block *sb, char *options) f2fs_info(sbi, "Test dummy encryption mode enabled"); #else f2fs_info(sbi, "Test dummy encryption mount option ignored"); +#endif + break; + case Opt_inlinecrypt: +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT + F2FS_OPTION(sbi).inlinecrypt = true; +#else + f2fs_info(sbi, "inline encryption not supported"); #endif break; case Opt_checkpoint_disable_cap_perc: @@ -810,6 +823,70 @@ static int parse_options(struct super_block *sb, char *options) case Opt_checkpoint_enable: clear_opt(sbi, DISABLE_CHECKPOINT); break; + case Opt_compress_algorithm: + if (!f2fs_sb_has_compression(sbi)) { + f2fs_err(sbi, "Compression feature if off"); + return -EINVAL; + } + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (strlen(name) == 3 && !strcmp(name, "lzo")) { + F2FS_OPTION(sbi).compress_algorithm = + COMPRESS_LZO; + } else if (strlen(name) == 3 && + !strcmp(name, "lz4")) { + F2FS_OPTION(sbi).compress_algorithm = + COMPRESS_LZ4; + } else if (strlen(name) == 4 && + !strcmp(name, "zstd")) { + F2FS_OPTION(sbi).compress_algorithm = + COMPRESS_ZSTD; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_compress_log_size: + if (!f2fs_sb_has_compression(sbi)) { + f2fs_err(sbi, "Compression feature is off"); + return -EINVAL; + } + if (args->from && match_int(args, &arg)) + return -EINVAL; + if (arg < MIN_COMPRESS_LOG_SIZE || + arg > MAX_COMPRESS_LOG_SIZE) { + f2fs_err(sbi, + "Compress cluster log size is out of range"); + return -EINVAL; + } + F2FS_OPTION(sbi).compress_log_size = arg; + break; + case Opt_compress_extension: + if (!f2fs_sb_has_compression(sbi)) { + f2fs_err(sbi, "Compression feature is off"); + return -EINVAL; + } + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + + ext = F2FS_OPTION(sbi).extensions; + ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; + + if (strlen(name) >= F2FS_EXTENSION_LEN || + ext_cnt >= COMPRESS_EXT_NUM) { + f2fs_err(sbi, + "invalid extension length/number"); + kfree(name); + return -EINVAL; + } + + strcpy(ext[ext_cnt], name); + F2FS_OPTION(sbi).compress_ext_cnt++; + kfree(name); + break; default: f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value", p); @@ -837,7 +914,7 @@ static int parse_options(struct super_block *sb, char *options) } #endif - if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) { + if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) { f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO", F2FS_IO_SIZE_KB(sbi)); return -EINVAL; @@ -867,7 +944,7 @@ static int parse_options(struct super_block *sb, char *options) } } - if (test_opt(sbi, DISABLE_CHECKPOINT) && test_opt(sbi, LFS)) { + if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) { f2fs_err(sbi, "LFS not compatible with checkpoint=disable\n"); return -EINVAL; } @@ -893,6 +970,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Initialize f2fs-specific inode info */ atomic_set(&fi->dirty_pages, 0); init_rwsem(&fi->i_sem); + spin_lock_init(&fi->i_size_lock); INIT_LIST_HEAD(&fi->dirty_list); INIT_LIST_HEAD(&fi->gdirty_list); INIT_LIST_HEAD(&fi->inmem_ilist); @@ -1080,9 +1158,9 @@ static void f2fs_umount_end(struct super_block *sb, int flags) struct cp_control cpc = { .reason = CP_UMOUNT, }; - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); f2fs_write_checkpoint(F2FS_SB(sb), &cpc); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); } } } @@ -1134,7 +1212,7 @@ static void f2fs_put_super(struct super_block *sb) /* our cp_error case, we can wait for any writeback page */ f2fs_flush_merged_writes(sbi); - f2fs_wait_on_all_pages_writeback(sbi); + f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); f2fs_bug_on(sbi, sbi->fsync_node_num); @@ -1154,6 +1232,8 @@ static void f2fs_put_super(struct super_block *sb) f2fs_destroy_node_manager(sbi); f2fs_destroy_segment_manager(sbi); + f2fs_destroy_post_read_wq(sbi); + kvfree(sbi->ckpt); f2fs_unregister_sysfs(sbi); @@ -1164,6 +1244,7 @@ static void f2fs_put_super(struct super_block *sb) kvfree(sbi->raw_super); destroy_device_list(sbi); + f2fs_destroy_xattr_caches(sbi); mempool_destroy(sbi->write_io_dummy); #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) @@ -1173,7 +1254,7 @@ static void f2fs_put_super(struct super_block *sb) for (i = 0; i < NR_PAGE_TYPE; i++) kvfree(sbi->write_io[i]); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif kvfree(sbi); } @@ -1198,9 +1279,9 @@ int f2fs_sync_fs(struct super_block *sb, int sync) cpc.reason = __get_cp_reason(sbi); - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); err = f2fs_write_checkpoint(sbi, &cpc); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); } f2fs_trace_ios(NULL, 1); @@ -1242,12 +1323,10 @@ static int f2fs_statfs_project(struct super_block *sb, return PTR_ERR(dquot); spin_lock(&dquot->dq_dqb_lock); - limit = 0; - if (dquot->dq_dqb.dqb_bsoftlimit) - limit = dquot->dq_dqb.dqb_bsoftlimit; - if (dquot->dq_dqb.dqb_bhardlimit && - (!limit || dquot->dq_dqb.dqb_bhardlimit < limit)) - limit = dquot->dq_dqb.dqb_bhardlimit; + limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit, + dquot->dq_dqb.dqb_bhardlimit); + if (limit) + limit >>= sb->s_blocksize_bits; if (limit && buf->f_blocks > limit) { curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits; @@ -1257,12 +1336,8 @@ static int f2fs_statfs_project(struct super_block *sb, (buf->f_blocks - curblock) : 0; } - limit = 0; - if (dquot->dq_dqb.dqb_isoftlimit) - limit = dquot->dq_dqb.dqb_isoftlimit; - if (dquot->dq_dqb.dqb_ihardlimit && - (!limit || dquot->dq_dqb.dqb_ihardlimit < limit)) - limit = dquot->dq_dqb.dqb_ihardlimit; + limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit, + dquot->dq_dqb.dqb_ihardlimit); if (limit && buf->f_files > limit) { buf->f_files = limit; @@ -1369,20 +1444,53 @@ static inline void f2fs_show_quota_options(struct seq_file *seq, #endif } +static inline void f2fs_show_compress_options(struct seq_file *seq, + struct super_block *sb) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + char *algtype = ""; + int i; + + if (!f2fs_sb_has_compression(sbi)) + return; + + switch (F2FS_OPTION(sbi).compress_algorithm) { + case COMPRESS_LZO: + algtype = "lzo"; + break; + case COMPRESS_LZ4: + algtype = "lz4"; + break; + case COMPRESS_ZSTD: + algtype = "zstd"; + break; + } + seq_printf(seq, ",compress_algorithm=%s", algtype); + + seq_printf(seq, ",compress_log_size=%u", + F2FS_OPTION(sbi).compress_log_size); + + for (i = 0; i < F2FS_OPTION(sbi).compress_ext_cnt; i++) { + seq_printf(seq, ",compress_extension=%s", + F2FS_OPTION(sbi).extensions[i]); + } +} + static int f2fs_show_options(struct seq_file *seq, struct dentry *root) { struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); - if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC)) { - if (test_opt(sbi, FORCE_FG_GC)) - seq_printf(seq, ",background_gc=%s", "sync"); - else - seq_printf(seq, ",background_gc=%s", "on"); - } else { + if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC) + seq_printf(seq, ",background_gc=%s", "sync"); + else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_ON) + seq_printf(seq, ",background_gc=%s", "on"); + else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF) seq_printf(seq, ",background_gc=%s", "off"); - } + if (test_opt(sbi, DISABLE_ROLL_FORWARD)) seq_puts(seq, ",disable_roll_forward"); + if (test_opt(sbi, NORECOVERY)) + seq_puts(seq, ",norecovery"); if (test_opt(sbi, DISCARD)) seq_puts(seq, ",discard"); else @@ -1434,9 +1542,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",data_flush"); seq_puts(seq, ",mode="); - if (test_opt(sbi, ADAPTIVE)) + if (F2FS_OPTION(sbi).fs_mode == FS_MODE_ADAPTIVE) seq_puts(seq, "adaptive"); - else if (test_opt(sbi, LFS)) + else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS) seq_puts(seq, "lfs"); seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); if (test_opt(sbi, RESERVE_ROOT)) @@ -1475,6 +1583,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) #ifdef CONFIG_FS_ENCRYPTION if (F2FS_OPTION(sbi).test_dummy_encryption) seq_puts(seq, ",test_dummy_encryption"); + if (F2FS_OPTION(sbi).inlinecrypt) + seq_puts(seq, ",inlinecrypt"); #endif if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT) @@ -1491,6 +1601,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_printf(seq, ",fsync_mode=%s", "strict"); else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_NOBARRIER) seq_printf(seq, ",fsync_mode=%s", "nobarrier"); + + f2fs_show_compress_options(seq, sbi->sb); return 0; } @@ -1503,10 +1615,16 @@ static void default_options(struct f2fs_sb_info *sbi) F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; F2FS_OPTION(sbi).test_dummy_encryption = false; +#ifdef CONFIG_FS_ENCRYPTION + F2FS_OPTION(sbi).inlinecrypt = false; +#endif F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); + F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4; + F2FS_OPTION(sbi).compress_log_size = MIN_COMPRESS_LOG_SIZE; + F2FS_OPTION(sbi).compress_ext_cnt = 0; + F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; - set_opt(sbi, BG_GC); set_opt(sbi, INLINE_XATTR); set_opt(sbi, INLINE_DATA); set_opt(sbi, INLINE_DENTRY); @@ -1518,9 +1636,9 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, FLUSH_MERGE); set_opt(sbi, DISCARD); if (f2fs_sb_has_blkzoned(sbi)) - set_opt_mode(sbi, F2FS_MOUNT_LFS); + F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; else - set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE); + F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; #ifdef CONFIG_F2FS_FS_XATTR set_opt(sbi, XATTR_USER); @@ -1553,7 +1671,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) f2fs_update_time(sbi, DISABLE_TIME); while (!f2fs_time_over(sbi, DISABLE_TIME)) { - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); err = f2fs_gc(sbi, true, false, NULL_SEGNO); if (err == -ENODATA) { err = 0; @@ -1575,7 +1693,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) goto restore_flag; } - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); cpc.reason = CP_PAUSE; set_sbi_flag(sbi, SBI_CP_DISABLED); err = f2fs_write_checkpoint(sbi, &cpc); @@ -1587,20 +1705,20 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) spin_unlock(&sbi->stat_lock); out_unlock: - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); restore_flag: - sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */ + sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */ return err; } static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) { - mutex_lock(&sbi->gc_mutex); + down_write(&sbi->gc_lock); f2fs_dirty_to_prefree(sbi); clear_sbi_flag(sbi, SBI_CP_DISABLED); set_sbi_flag(sbi, SBI_IS_DIRTY); - mutex_unlock(&sbi->gc_mutex); + up_write(&sbi->gc_lock); f2fs_sync_fs(sbi->sb, 1); } @@ -1712,7 +1830,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) * or if background_gc = off is passed in mount * option. Also sync the filesystem. */ - if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) { + if ((*flags & MS_RDONLY) || + F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF) { if (sbi->gc_thread) { f2fs_stop_gc_thread(sbi); need_restart_gc = true; @@ -1817,7 +1936,8 @@ static ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data, page = read_cache_page_gfp(mapping, blkidx, GFP_NOFS); if (IS_ERR(page)) { if (PTR_ERR(page) == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); goto repeat; } set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); @@ -1859,6 +1979,7 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type, int offset = off & (sb->s_blocksize - 1); size_t towrite = len; struct page *page; + void *fsdata = NULL; char *kaddr; int err = 0; int tocopy; @@ -1868,10 +1989,11 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type, towrite); retry: err = a_ops->write_begin(NULL, mapping, off, tocopy, 0, - &page, NULL); + &page, &fsdata); if (unlikely(err)) { if (err == -ENOMEM) { - congestion_wait(BLK_RW_ASYNC, HZ/50); + congestion_wait(BLK_RW_ASYNC, + DEFAULT_IO_TIMEOUT); goto retry; } set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); @@ -1884,7 +2006,7 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type, flush_dcache_page(page); a_ops->write_end(NULL, mapping, off, tocopy, tocopy, - page, NULL); + page, fsdata); offset = 0; towrite -= tocopy; off += tocopy; @@ -2187,7 +2309,7 @@ static int f2fs_dquot_commit(struct dquot *dquot) struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); int ret; - down_read(&sbi->quota_sem); + down_read_nested(&sbi->quota_sem, SINGLE_DEPTH_NESTING); ret = dquot_commit(dquot); if (ret < 0) set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); @@ -2211,13 +2333,10 @@ static int f2fs_dquot_acquire(struct dquot *dquot) static int f2fs_dquot_release(struct dquot *dquot) { struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); - int ret; + int ret = dquot_release(dquot); - down_read(&sbi->quota_sem); - ret = dquot_release(dquot); if (ret < 0) set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); - up_read(&sbi->quota_sem); return ret; } @@ -2225,29 +2344,22 @@ static int f2fs_dquot_mark_dquot_dirty(struct dquot *dquot) { struct super_block *sb = dquot->dq_sb; struct f2fs_sb_info *sbi = F2FS_SB(sb); - int ret; - - down_read(&sbi->quota_sem); - ret = dquot_mark_dquot_dirty(dquot); + int ret = dquot_mark_dquot_dirty(dquot); /* if we are using journalled quota */ if (is_journalled_quota(sbi)) set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); - up_read(&sbi->quota_sem); return ret; } static int f2fs_dquot_commit_info(struct super_block *sb, int type) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - int ret; + int ret = dquot_commit_info(sb, type); - down_read(&sbi->quota_sem); - ret = dquot_commit_info(sb, type); if (ret < 0) set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); - up_read(&sbi->quota_sem); return ret; } @@ -2358,6 +2470,30 @@ static void f2fs_get_ino_and_lblk_bits(struct super_block *sb, *lblk_bits_ret = 8 * sizeof(block_t); } +static bool f2fs_inline_crypt_enabled(struct super_block *sb) +{ + return F2FS_OPTION(F2FS_SB(sb)).inlinecrypt; +} + +static int f2fs_get_num_devices(struct super_block *sb) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + if (f2fs_is_multi_device(sbi)) + return sbi->s_ndevs; + return 1; +} + +static void f2fs_get_devices(struct super_block *sb, + struct request_queue **devs) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + int i; + + for (i = 0; i < sbi->s_ndevs; i++) + devs[i] = bdev_get_queue(FDEV(i).bdev); +} + static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, @@ -2367,6 +2503,9 @@ static const struct fscrypt_operations f2fs_cryptops = { .max_namelen = F2FS_NAME_LEN, .has_stable_inodes = f2fs_has_stable_inodes, .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, + .inline_crypt_enabled = f2fs_inline_crypt_enabled, + .get_num_devices = f2fs_get_num_devices, + .get_devices = f2fs_get_devices, }; #endif @@ -3187,17 +3326,11 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) static int f2fs_setup_casefold(struct f2fs_sb_info *sbi) { #ifdef CONFIG_UNICODE - if (f2fs_sb_has_casefold(sbi) && !sbi->s_encoding) { + if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) { const struct f2fs_sb_encodings *encoding_info; struct unicode_map *encoding; __u16 encoding_flags; - if (f2fs_sb_has_encrypt(sbi)) { - f2fs_err(sbi, - "Can't mount with encoding and encryption"); - return -EINVAL; - } - if (f2fs_sb_read_encoding(sbi->raw_super, &encoding_info, &encoding_flags)) { f2fs_err(sbi, @@ -3218,9 +3351,8 @@ static int f2fs_setup_casefold(struct f2fs_sb_info *sbi) "%s-%s with flags 0x%hx", encoding_info->name, encoding_info->version?:"\b", encoding_flags); - sbi->s_encoding = encoding; - sbi->s_encoding_flags = encoding_flags; - sbi->sb->s_d_op = &f2fs_dentry_ops; + sbi->sb->s_encoding = encoding; + sbi->sb->s_encoding_flags = encoding_flags; } #else if (f2fs_sb_has_casefold(sbi)) { @@ -3362,7 +3494,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) /* init f2fs-specific super block info */ sbi->valid_super_block = valid_super_block; - mutex_init(&sbi->gc_mutex); + init_rwsem(&sbi->gc_lock); mutex_init(&sbi->writepages); mutex_init(&sbi->cp_mutex); mutex_init(&sbi->resize_mutex); @@ -3376,6 +3508,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) /* init iostat info */ spin_lock_init(&sbi->iostat_lock); sbi->iostat_enable = false; + sbi->iostat_period_ms = DEFAULT_IOSTAT_PERIOD_MS; for (i = 0; i < NR_PAGE_TYPE; i++) { int n = (i == META) ? 1: NR_TEMP_TYPE; @@ -3420,12 +3553,17 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) } } + /* init per sbi slab cache */ + err = f2fs_init_xattr_caches(sbi); + if (err) + goto free_io_dummy; + /* get an inode for meta space */ sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); if (IS_ERR(sbi->meta_inode)) { f2fs_err(sbi, "Failed to read F2FS meta data inode"); err = PTR_ERR(sbi->meta_inode); - goto free_io_dummy; + goto free_xattr_cache; } err = f2fs_get_valid_checkpoint(sbi); @@ -3451,6 +3589,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_devices; } + err = f2fs_init_post_read_wq(sbi); + if (err) { + f2fs_err(sbi, "Failed to initialize post read workqueue"); + goto free_devices; + } + sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); percpu_counter_set(&sbi->total_valid_inode_count, @@ -3546,7 +3690,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) f2fs_err(sbi, "Cannot turn on quotas: error %d", err); } #endif - /* if there are nt orphan nodes free them */ + /* if there are any orphan inodes, free them */ err = f2fs_recover_orphan_inodes(sbi); if (err) goto free_meta; @@ -3555,7 +3699,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto reset_checkpoint; /* recover fsynced data */ - if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { + if (!test_opt(sbi, DISABLE_ROLL_FORWARD) && + !test_opt(sbi, NORECOVERY)) { /* * mount should be failed, when device has readonly mode, and * previous checkpoint was not done by clean system shutdown. @@ -3610,7 +3755,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * If filesystem is not mounted as read-only then * do start the gc_thread. */ - if (test_opt(sbi, BG_GC) && !f2fs_readonly(sb)) { + if (F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF && !f2fs_readonly(sb)) { /* After POR, we can run background GC thread.*/ err = f2fs_start_gc_thread(sbi); if (err) @@ -3671,6 +3816,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) f2fs_destroy_node_manager(sbi); free_sm: f2fs_destroy_segment_manager(sbi); + f2fs_destroy_post_read_wq(sbi); free_devices: destroy_device_list(sbi); kvfree(sbi->ckpt); @@ -3678,6 +3824,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) make_bad_inode(sbi->meta_inode); iput(sbi->meta_inode); sbi->meta_inode = NULL; +free_xattr_cache: + f2fs_destroy_xattr_caches(sbi); free_io_dummy: mempool_destroy(sbi->write_io_dummy); free_percpu: @@ -3687,7 +3835,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) kvfree(sbi->write_io[i]); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif free_options: #ifdef CONFIG_QUOTA @@ -3812,8 +3960,12 @@ static int __init init_f2fs_fs(void) err = f2fs_init_bio_entry_cache(); if (err) goto free_post_read; + err = f2fs_init_bioset(); + if (err) + goto free_bio_enrty_cache; return 0; - +free_bio_enrty_cache: + f2fs_destroy_bio_entry_cache(); free_post_read: f2fs_destroy_post_read_processing(); free_root_stats: @@ -3839,6 +3991,7 @@ static int __init init_f2fs_fs(void) static void __exit exit_f2fs_fs(void) { + f2fs_destroy_bioset(); f2fs_destroy_bio_entry_cache(); f2fs_destroy_post_read_processing(); f2fs_destroy_root_stats(); diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 9ed632b9c9bb83c3265e73276435e01a5ca6b7e4..70893a98c0e96772c51d3655c487f8b107437b3c 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -15,6 +15,7 @@ #include "f2fs.h" #include "segment.h" #include "gc.h" +#include static struct proc_dir_entry *f2fs_proc_root; @@ -25,6 +26,9 @@ enum { DCC_INFO, /* struct discard_cmd_control */ NM_INFO, /* struct f2fs_nm_info */ F2FS_SBI, /* struct f2fs_sb_info */ +#ifdef CONFIG_F2FS_STAT_FS + STAT_INFO, /* struct f2fs_stat_info */ +#endif #ifdef CONFIG_F2FS_FAULT_INJECTION FAULT_INFO_RATE, /* struct f2fs_fault_info */ FAULT_INFO_TYPE, /* struct f2fs_fault_info */ @@ -42,6 +46,9 @@ struct f2fs_attr { int id; }; +static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf); + static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) { if (struct_type == GC_THREAD) @@ -58,6 +65,10 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) else if (struct_type == FAULT_INFO_RATE || struct_type == FAULT_INFO_TYPE) return (unsigned char *)&F2FS_OPTION(sbi).fault_info; +#endif +#ifdef CONFIG_F2FS_STAT_FS + else if (struct_type == STAT_INFO) + return (unsigned char *)F2FS_STAT(sbi); #endif return NULL; } @@ -65,35 +76,15 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) static ssize_t dirty_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)(dirty_segments(sbi))); + return sprintf(buf, "%llu\n", + (unsigned long long)(dirty_segments(sbi))); } -static ssize_t unusable_show(struct f2fs_attr *a, +static ssize_t free_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { - block_t unusable; - - if (test_opt(sbi, DISABLE_CHECKPOINT)) - unusable = sbi->unusable_block_count; - else - unusable = f2fs_get_unusable_blocks(sbi); - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)unusable); -} - -static ssize_t encoding_show(struct f2fs_attr *a, - struct f2fs_sb_info *sbi, char *buf) -{ -#ifdef CONFIG_UNICODE - if (f2fs_sb_has_casefold(sbi)) - return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n", - sbi->s_encoding->charset, - (sbi->s_encoding->version >> 16) & 0xff, - (sbi->s_encoding->version >> 8) & 0xff, - sbi->s_encoding->version & 0xff); -#endif - return snprintf(buf, PAGE_SIZE, "(none)"); + return sprintf(buf, "%llu\n", + (unsigned long long)(free_segments(sbi))); } static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, @@ -102,10 +93,10 @@ static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, struct super_block *sb = sbi->sb; if (!sb->s_bdev->bd_part) - return snprintf(buf, PAGE_SIZE, "0\n"); + return sprintf(buf, "0\n"); - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)(sbi->kbytes_written + + return sprintf(buf, "%llu\n", + (unsigned long long)(sbi->kbytes_written + BD_PART_WRITTEN(sbi))); } @@ -116,56 +107,124 @@ static ssize_t features_show(struct f2fs_attr *a, int len = 0; if (!sb->s_bdev->bd_part) - return snprintf(buf, PAGE_SIZE, "0\n"); + return sprintf(buf, "0\n"); if (f2fs_sb_has_encrypt(sbi)) - len += snprintf(buf, PAGE_SIZE - len, "%s", + len += scnprintf(buf, PAGE_SIZE - len, "%s", "encryption"); if (f2fs_sb_has_blkzoned(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "blkzoned"); if (f2fs_sb_has_extra_attr(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "extra_attr"); if (f2fs_sb_has_project_quota(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "projquota"); if (f2fs_sb_has_inode_chksum(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "inode_checksum"); if (f2fs_sb_has_flexible_inline_xattr(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "flexible_inline_xattr"); if (f2fs_sb_has_quota_ino(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "quota_ino"); if (f2fs_sb_has_inode_crtime(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "inode_crtime"); if (f2fs_sb_has_lost_found(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "lost_found"); if (f2fs_sb_has_verity(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "verity"); if (f2fs_sb_has_sb_chksum(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "sb_checksum"); if (f2fs_sb_has_casefold(sbi)) - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "casefold"); - len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + if (f2fs_sb_has_compression(sbi)) + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len ? ", " : "", "compression"); + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "pin_file"); - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); return len; } static ssize_t current_reserved_blocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { - return snprintf(buf, PAGE_SIZE, "%u\n", sbi->current_reserved_blocks); + return sprintf(buf, "%u\n", sbi->current_reserved_blocks); } +static ssize_t unusable_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + block_t unusable; + + if (test_opt(sbi, DISABLE_CHECKPOINT)) + unusable = sbi->unusable_block_count; + else + unusable = f2fs_get_unusable_blocks(sbi); + return sprintf(buf, "%llu\n", (unsigned long long)unusable); +} + +static ssize_t encoding_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ +#ifdef CONFIG_UNICODE + struct super_block *sb = sbi->sb; + + if (f2fs_sb_has_casefold(sbi)) + return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n", + sb->s_encoding->charset, + (sb->s_encoding->version >> 16) & 0xff, + (sb->s_encoding->version >> 8) & 0xff, + sb->s_encoding->version & 0xff); +#endif + return sprintf(buf, "(none)"); +} + +static ssize_t mounted_time_sec_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + return sprintf(buf, "%llu", SIT_I(sbi)->mounted_time); +} + +#ifdef CONFIG_F2FS_STAT_FS +static ssize_t moved_blocks_foreground_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + struct f2fs_stat_info *si = F2FS_STAT(sbi); + + return sprintf(buf, "%llu\n", + (unsigned long long)(si->tot_blks - + (si->bg_data_blks + si->bg_node_blks))); +} + +static ssize_t moved_blocks_background_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + struct f2fs_stat_info *si = F2FS_STAT(sbi); + + return sprintf(buf, "%llu\n", + (unsigned long long)(si->bg_data_blks + si->bg_node_blks)); +} + +static ssize_t avg_vblocks_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + struct f2fs_stat_info *si = F2FS_STAT(sbi); + + si->dirty_count = dirty_segments(sbi); + f2fs_update_sit_info(sbi); + return sprintf(buf, "%llu\n", (unsigned long long)(si->avg_vblocks)); +} +#endif + static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { @@ -183,23 +242,23 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, int hot_count = sbi->raw_super->hot_ext_count; int len = 0, i; - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "cold file extension:\n"); for (i = 0; i < cold_count; i++) - len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", extlist[i]); - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "hot file extension:\n"); for (i = cold_count; i < cold_count + hot_count; i++) - len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", + len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", extlist[i]); return len; } ui = (unsigned int *)(ptr + a->offset); - return snprintf(buf, PAGE_SIZE, "%u\n", *ui); + return sprintf(buf, "%u\n", *ui); } static ssize_t __sbi_store(struct f2fs_attr *a, @@ -316,7 +375,6 @@ static ssize_t __sbi_store(struct f2fs_attr *a, return count; } - if (!strcmp(a->attr.name, "iostat_enable")) { sbi->iostat_enable = !!t; if (!sbi->iostat_enable) @@ -324,6 +382,15 @@ static ssize_t __sbi_store(struct f2fs_attr *a, return count; } + if (!strcmp(a->attr.name, "iostat_period_ms")) { + if (t < MIN_IOSTAT_PERIOD_MS || t > MAX_IOSTAT_PERIOD_MS) + return -EINVAL; + spin_lock(&sbi->iostat_lock); + sbi->iostat_period_ms = (unsigned int)t; + spin_unlock(&sbi->iostat_lock); + return count; + } + *ui = (unsigned int)t; return count; @@ -389,6 +456,7 @@ enum feat_id { FEAT_VERITY, FEAT_SB_CHECKSUM, FEAT_CASEFOLD, + FEAT_COMPRESSION, }; static ssize_t f2fs_feature_show(struct f2fs_attr *a, @@ -408,7 +476,8 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, case FEAT_VERITY: case FEAT_SB_CHECKSUM: case FEAT_CASEFOLD: - return snprintf(buf, PAGE_SIZE, "supported\n"); + case FEAT_COMPRESSION: + return sprintf(buf, "supported\n"); } return 0; } @@ -437,6 +506,14 @@ static struct f2fs_attr f2fs_attr_##_name = { \ .id = _id, \ } +#define F2FS_STAT_ATTR(_struct_type, _struct_name, _name, _elname) \ +static struct f2fs_attr f2fs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = 0444 }, \ + .show = f2fs_sbi_show, \ + .struct_type = _struct_type, \ + .offset = offsetof(struct _struct_name, _elname), \ +} + F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time, urgent_sleep_time); F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); @@ -470,6 +547,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle_interval, interval_time[GC_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_period_ms, iostat_period_ms); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); @@ -477,12 +555,24 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); #endif +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag); F2FS_GENERAL_RO_ATTR(dirty_segments); +F2FS_GENERAL_RO_ATTR(free_segments); F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); F2FS_GENERAL_RO_ATTR(features); F2FS_GENERAL_RO_ATTR(current_reserved_blocks); F2FS_GENERAL_RO_ATTR(unusable); F2FS_GENERAL_RO_ATTR(encoding); +F2FS_GENERAL_RO_ATTR(mounted_time_sec); +#ifdef CONFIG_F2FS_STAT_FS +F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_foreground_calls, cp_count); +F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_background_calls, bg_cp_count); +F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, gc_foreground_calls, call_count); +F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, gc_background_calls, bg_gc); +F2FS_GENERAL_RO_ATTR(moved_blocks_background); +F2FS_GENERAL_RO_ATTR(moved_blocks_foreground); +F2FS_GENERAL_RO_ATTR(avg_vblocks); +#endif #ifdef CONFIG_FS_ENCRYPTION F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); @@ -503,6 +593,9 @@ F2FS_FEATURE_RO_ATTR(verity, FEAT_VERITY); #endif F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); F2FS_FEATURE_RO_ATTR(casefold, FEAT_CASEFOLD); +#ifdef CONFIG_F2FS_FS_COMPRESSION +F2FS_FEATURE_RO_ATTR(compression, FEAT_COMPRESSION); +#endif #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -535,6 +628,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(gc_idle_interval), ATTR_LIST(umount_discard_timeout), ATTR_LIST(iostat_enable), + ATTR_LIST(iostat_period_ms), ATTR_LIST(readdir_ra), ATTR_LIST(gc_pin_file_thresh), ATTR_LIST(extension_list), @@ -542,13 +636,25 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(inject_rate), ATTR_LIST(inject_type), #endif + ATTR_LIST(data_io_flag), ATTR_LIST(dirty_segments), + ATTR_LIST(free_segments), ATTR_LIST(unusable), ATTR_LIST(lifetime_write_kbytes), ATTR_LIST(features), ATTR_LIST(reserved_blocks), ATTR_LIST(current_reserved_blocks), ATTR_LIST(encoding), + ATTR_LIST(mounted_time_sec), +#ifdef CONFIG_F2FS_STAT_FS + ATTR_LIST(cp_foreground_calls), + ATTR_LIST(cp_background_calls), + ATTR_LIST(gc_foreground_calls), + ATTR_LIST(gc_background_calls), + ATTR_LIST(moved_blocks_foreground), + ATTR_LIST(moved_blocks_background), + ATTR_LIST(avg_vblocks), +#endif NULL, }; @@ -572,6 +678,9 @@ static struct attribute *f2fs_feat_attrs[] = { #endif ATTR_LIST(sb_checksum), ATTR_LIST(casefold), +#ifdef CONFIG_F2FS_FS_COMPRESSION + ATTR_LIST(compression), +#endif NULL, }; @@ -654,6 +763,33 @@ static int __maybe_unused segment_bits_seq_show(struct seq_file *seq, return 0; } +void f2fs_record_iostat(struct f2fs_sb_info *sbi) +{ + unsigned long long iostat_diff[NR_IO_TYPE]; + int i; + + if (time_is_after_jiffies(sbi->iostat_next_period)) + return; + + /* Need double check under the lock */ + spin_lock(&sbi->iostat_lock); + if (time_is_after_jiffies(sbi->iostat_next_period)) { + spin_unlock(&sbi->iostat_lock); + return; + } + sbi->iostat_next_period = jiffies + + msecs_to_jiffies(sbi->iostat_period_ms); + + for (i = 0; i < NR_IO_TYPE; i++) { + iostat_diff[i] = sbi->rw_iostat[i] - + sbi->prev_rw_iostat[i]; + sbi->prev_rw_iostat[i] = sbi->rw_iostat[i]; + } + spin_unlock(&sbi->iostat_lock); + + trace_f2fs_iostat(sbi, iostat_diff); +} + static int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset) { @@ -666,33 +802,51 @@ static int __maybe_unused iostat_info_seq_show(struct seq_file *seq, seq_printf(seq, "time: %-16llu\n", now); - /* print app IOs */ + /* print app write IOs */ seq_printf(seq, "app buffered: %-16llu\n", - sbi->write_iostat[APP_BUFFERED_IO]); + sbi->rw_iostat[APP_BUFFERED_IO]); seq_printf(seq, "app direct: %-16llu\n", - sbi->write_iostat[APP_DIRECT_IO]); + sbi->rw_iostat[APP_DIRECT_IO]); seq_printf(seq, "app mapped: %-16llu\n", - sbi->write_iostat[APP_MAPPED_IO]); + sbi->rw_iostat[APP_MAPPED_IO]); - /* print fs IOs */ + /* print fs write IOs */ seq_printf(seq, "fs data: %-16llu\n", - sbi->write_iostat[FS_DATA_IO]); + sbi->rw_iostat[FS_DATA_IO]); seq_printf(seq, "fs node: %-16llu\n", - sbi->write_iostat[FS_NODE_IO]); + sbi->rw_iostat[FS_NODE_IO]); seq_printf(seq, "fs meta: %-16llu\n", - sbi->write_iostat[FS_META_IO]); + sbi->rw_iostat[FS_META_IO]); seq_printf(seq, "fs gc data: %-16llu\n", - sbi->write_iostat[FS_GC_DATA_IO]); + sbi->rw_iostat[FS_GC_DATA_IO]); seq_printf(seq, "fs gc node: %-16llu\n", - sbi->write_iostat[FS_GC_NODE_IO]); + sbi->rw_iostat[FS_GC_NODE_IO]); seq_printf(seq, "fs cp data: %-16llu\n", - sbi->write_iostat[FS_CP_DATA_IO]); + sbi->rw_iostat[FS_CP_DATA_IO]); seq_printf(seq, "fs cp node: %-16llu\n", - sbi->write_iostat[FS_CP_NODE_IO]); + sbi->rw_iostat[FS_CP_NODE_IO]); seq_printf(seq, "fs cp meta: %-16llu\n", - sbi->write_iostat[FS_CP_META_IO]); + sbi->rw_iostat[FS_CP_META_IO]); + + /* print app read IOs */ + seq_printf(seq, "app buffered: %-16llu\n", + sbi->rw_iostat[APP_BUFFERED_READ_IO]); + seq_printf(seq, "app direct: %-16llu\n", + sbi->rw_iostat[APP_DIRECT_READ_IO]); + seq_printf(seq, "app mapped: %-16llu\n", + sbi->rw_iostat[APP_MAPPED_READ_IO]); + + /* print fs read IOs */ + seq_printf(seq, "fs data: %-16llu\n", + sbi->rw_iostat[FS_DATA_READ_IO]); + seq_printf(seq, "fs node: %-16llu\n", + sbi->rw_iostat[FS_NODE_READ_IO]); + seq_printf(seq, "fs meta: %-16llu\n", + sbi->rw_iostat[FS_META_READ_IO]); + + /* print other IOs */ seq_printf(seq, "fs discard: %-16llu\n", - sbi->write_iostat[FS_DISCARD]); + sbi->rw_iostat[FS_DISCARD]); return 0; } @@ -749,10 +903,12 @@ int __init f2fs_init_sysfs(void) ret = kobject_init_and_add(&f2fs_feat, &f2fs_feat_ktype, NULL, "features"); - if (ret) + if (ret) { + kobject_put(&f2fs_feat); kset_unregister(&f2fs_kset); - else + } else { f2fs_proc_root = proc_mkdir("fs/f2fs", NULL); + } return ret; } @@ -773,8 +929,11 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) init_completion(&sbi->s_kobj_unregister); err = kobject_init_and_add(&sbi->s_kobj, &f2fs_sb_ktype, NULL, "%s", sb->s_id); - if (err) + if (err) { + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); return err; + } if (f2fs_proc_root) sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); @@ -802,4 +961,5 @@ void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) remove_proc_entry(sbi->sb->s_id, f2fs_proc_root); } kobject_del(&sbi->s_kobj); + kobject_put(&sbi->s_kobj); } diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index a401ef72bc82136b31dfdc8eca4cdcf5bc445dd1..5905050f7fb89a6084a4fd0da743da6600f6c26f 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -222,12 +222,57 @@ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf, return size; } +/* + * Prefetch some pages from the file's Merkle tree. + * + * This is basically a stripped-down version of __do_page_cache_readahead() + * which works on pages past i_size. + */ +static void f2fs_merkle_tree_readahead(struct address_space *mapping, + pgoff_t start_index, unsigned long count) +{ + LIST_HEAD(pages); + unsigned int nr_pages = 0; + struct page *page; + pgoff_t index; + struct blk_plug plug; + + for (index = start_index; index < start_index + count; index++) { + rcu_read_lock(); + page = radix_tree_lookup(&mapping->page_tree, index); + rcu_read_unlock(); + if (!page || radix_tree_exceptional_entry(page)) { + page = __page_cache_alloc(readahead_gfp_mask(mapping)); + if (!page) + break; + page->index = index; + list_add(&page->lru, &pages); + nr_pages++; + } + } + blk_start_plug(&plug); + f2fs_mpage_readpages(mapping, &pages, NULL, nr_pages, true); + blk_finish_plug(&plug); +} + static struct page *f2fs_read_merkle_tree_page(struct inode *inode, - pgoff_t index) + pgoff_t index, + unsigned long num_ra_pages) { + struct page *page; + index += f2fs_verity_metadata_pos(inode) >> PAGE_SHIFT; - return read_mapping_page(inode->i_mapping, index, NULL); + page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED); + if (!page || !PageUptodate(page)) { + if (page) + put_page(page); + else if (num_ra_pages > 1) + f2fs_merkle_tree_readahead(inode->i_mapping, index, + num_ra_pages); + page = read_mapping_page(inode->i_mapping, index, NULL); + } + return page; } static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf, diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 296b3189448a466c2177ace3d0423f1f31f2162b..4f6582ef7ee331b7b62c3c0a1c77e4c732f0d1a7 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -23,6 +23,25 @@ #include "xattr.h" #include "segment.h" +static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline) +{ + if (likely(size == sbi->inline_xattr_slab_size)) { + *is_inline = true; + return kmem_cache_zalloc(sbi->inline_xattr_slab, GFP_NOFS); + } + *is_inline = false; + return f2fs_kzalloc(sbi, size, GFP_NOFS); +} + +static void xattr_free(struct f2fs_sb_info *sbi, void *xattr_addr, + bool is_inline) +{ + if (is_inline) + kmem_cache_free(sbi->inline_xattr_slab, xattr_addr); + else + kvfree(xattr_addr); +} + static int f2fs_xattr_generic_get(const struct xattr_handler *handler, struct dentry *unused, struct inode *inode, const char *name, void *buffer, size_t size) @@ -301,7 +320,8 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr) static int lookup_all_xattrs(struct inode *inode, struct page *ipage, unsigned int index, unsigned int len, const char *name, struct f2fs_xattr_entry **xe, - void **base_addr, int *base_size) + void **base_addr, int *base_size, + bool *is_inline) { void *cur_addr, *txattr_addr, *last_txattr_addr; void *last_addr = NULL; @@ -312,12 +332,12 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage, if (!xnid && !inline_size) return -ENODATA; - *base_size = XATTR_SIZE(xnid, inode) + XATTR_PADDING_SIZE; - txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS); + *base_size = XATTR_SIZE(inode) + XATTR_PADDING_SIZE; + txattr_addr = xattr_alloc(F2FS_I_SB(inode), *base_size, is_inline); if (!txattr_addr) return -ENOMEM; - last_txattr_addr = (void *)txattr_addr + XATTR_SIZE(xnid, inode); + last_txattr_addr = (void *)txattr_addr + XATTR_SIZE(inode); /* read from inline xattr */ if (inline_size) { @@ -362,7 +382,7 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage, *base_addr = txattr_addr; return 0; out: - kvfree(txattr_addr); + xattr_free(F2FS_I_SB(inode), txattr_addr, *is_inline); return err; } @@ -499,6 +519,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name, unsigned int size, len; void *base_addr = NULL; int base_size; + bool is_inline; if (name == NULL) return -EINVAL; @@ -509,7 +530,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name, down_read(&F2FS_I(inode)->i_xattr_sem); error = lookup_all_xattrs(inode, ipage, index, len, name, - &entry, &base_addr, &base_size); + &entry, &base_addr, &base_size, &is_inline); up_read(&F2FS_I(inode)->i_xattr_sem); if (error) return error; @@ -532,14 +553,13 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name, } error = size; out: - kvfree(base_addr); + xattr_free(F2FS_I_SB(inode), base_addr, is_inline); return error; } ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) { struct inode *inode = d_inode(dentry); - nid_t xnid = F2FS_I(inode)->i_xattr_nid; struct f2fs_xattr_entry *entry; void *base_addr, *last_base_addr; int error = 0; @@ -551,7 +571,7 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) if (error) return error; - last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode); + last_base_addr = (void *)base_addr + XATTR_SIZE(inode); list_for_each_xattr(entry, base_addr) { const struct xattr_handler *handler = @@ -609,7 +629,6 @@ static int __f2fs_setxattr(struct inode *inode, int index, { struct f2fs_xattr_entry *here, *last; void *base_addr, *last_base_addr; - nid_t xnid = F2FS_I(inode)->i_xattr_nid; int found, newsize; size_t len; __u32 new_hsize; @@ -633,7 +652,7 @@ static int __f2fs_setxattr(struct inode *inode, int index, if (error) return error; - last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode); + last_base_addr = (void *)base_addr + XATTR_SIZE(inode); /* find entry with wanted name. */ here = __find_xattr(base_addr, last_base_addr, index, len, name); @@ -758,14 +777,34 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, f2fs_balance_fs(sbi, true); f2fs_lock_op(sbi); - /* protect xattr_ver */ - down_write(&F2FS_I(inode)->i_sem); down_write(&F2FS_I(inode)->i_xattr_sem); err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags); up_write(&F2FS_I(inode)->i_xattr_sem); - up_write(&F2FS_I(inode)->i_sem); f2fs_unlock_op(sbi); f2fs_update_time(sbi, REQ_TIME); return err; } + +int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) +{ + dev_t dev = sbi->sb->s_bdev->bd_dev; + char slab_name[32]; + + sprintf(slab_name, "f2fs_xattr_entry-%u:%u", MAJOR(dev), MINOR(dev)); + + sbi->inline_xattr_slab_size = F2FS_OPTION(sbi).inline_xattr_size * + sizeof(__le32) + XATTR_PADDING_SIZE; + + sbi->inline_xattr_slab = f2fs_kmem_cache_create(slab_name, + sbi->inline_xattr_slab_size); + if (!sbi->inline_xattr_slab) + return -ENOMEM; + + return 0; +} + +void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) +{ + kmem_cache_destroy(sbi->inline_xattr_slab); +} diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index de0c600b9cab0973cf2b8c5ba2b4c9e45da1214c..938fcd20565dccfdaa3a37a3cdd64abe4e1ab831 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -49,7 +49,7 @@ struct f2fs_xattr_entry { __u8 e_name_index; __u8 e_name_len; __le16 e_value_size; /* size of attribute value */ - char e_name[0]; /* attribute name */ + char e_name[]; /* attribute name */ }; #define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) @@ -73,7 +73,8 @@ struct f2fs_xattr_entry { entry = XATTR_NEXT_ENTRY(entry)) #define VALID_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer)) #define XATTR_PADDING_SIZE (sizeof(__u32)) -#define XATTR_SIZE(x,i) (((x) ? VALID_XATTR_BLOCK_SIZE : 0) + \ +#define XATTR_SIZE(i) ((F2FS_I(i)->i_xattr_nid ? \ + VALID_XATTR_BLOCK_SIZE : 0) + \ (inline_xattr_size(i))) #define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \ VALID_XATTR_BLOCK_SIZE) @@ -130,6 +131,8 @@ extern int f2fs_setxattr(struct inode *, int, const char *, extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t, struct page *); extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); +extern int f2fs_init_xattr_caches(struct f2fs_sb_info *); +extern void f2fs_destroy_xattr_caches(struct f2fs_sb_info *); #else #define f2fs_xattr_handlers NULL @@ -150,6 +153,8 @@ static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, { return -EOPNOTSUPP; } +static inline int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) { return 0; } +static inline void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) { } #endif #ifdef CONFIG_F2FS_FS_SECURITY diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 204d5ca813da3ef942ba481425f30d321078da51..154728d207c343462bde4f38665e52681af228e4 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -734,6 +734,13 @@ static struct inode *fat_alloc_inode(struct super_block *sb) return NULL; init_rwsem(&ei->truncate_lock); + /* Zeroing to allow iput() even if partial initialized inode. */ + ei->mmu_private = 0; + ei->i_start = 0; + ei->i_logstart = 0; + ei->i_attrs = 0; + ei->i_pos = 0; + return &ei->vfs_inode; } @@ -1364,16 +1371,6 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, return 0; } -static void fat_dummy_inode_init(struct inode *inode) -{ - /* Initialize this dummy inode to work as no-op. */ - MSDOS_I(inode)->mmu_private = 0; - MSDOS_I(inode)->i_start = 0; - MSDOS_I(inode)->i_logstart = 0; - MSDOS_I(inode)->i_attrs = 0; - MSDOS_I(inode)->i_pos = 0; -} - static int fat_read_root(struct inode *inode) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); @@ -1818,13 +1815,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, fat_inode = new_inode(sb); if (!fat_inode) goto out_fail; - fat_dummy_inode_init(fat_inode); sbi->fat_inode = fat_inode; fsinfo_inode = new_inode(sb); if (!fsinfo_inode) goto out_fail; - fat_dummy_inode_init(fsinfo_inode); fsinfo_inode->i_ino = MSDOS_FSINFO_INO; sbi->fsinfo_inode = fsinfo_inode; insert_inode_hash(fsinfo_inode); diff --git a/fs/filesystems.c b/fs/filesystems.c index 931925d6aeed39fd2666ddb2cbe364e53963caf4..9829317d39c8da159bf2c9d371a290a7ebd7b753 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -298,7 +298,9 @@ struct file_system_type *get_fs_type(const char *name) fs = __get_fs_type(name, len); if (!fs && (request_module("fs-%.*s", len, name) == 0)) { fs = __get_fs_type(name, len); - WARN_ONCE(!fs, "request_module fs-%.*s succeeded, but still no fs?\n", len, name); + if (!fs) + pr_warn_once("request_module fs-%.*s succeeded, but still no fs?\n", + len, name); } if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) { diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index aea1ed0aebd0f6a615b8118775583e7e8e21ad43..1e2ff4b32c79aea44981c0e8cc926b32640dea8f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -636,6 +636,9 @@ __acquires(&gl->gl_lockref.lock) goto out_unlock; if (nonblock) goto out_sched; + smp_mb(); + if (atomic_read(&gl->gl_revokes) != 0) + goto out_sched; set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags); GLOCK_BUG_ON(gl, gl->gl_demote_state == LM_ST_EXCLUSIVE); gl->gl_target = gl->gl_demote_state; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c850579ae5a46f3139c82324da85e01473f9b2d0..6c6401084d3d8f72c20b3e3c208234b8f0a895b5 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1255,7 +1255,7 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, if (!(*opened & FILE_OPENED)) return finish_no_open(file, d); dput(d); - return 0; + return excl && (flags & O_CREAT) ? -EEXIST : 0; } BUG_ON(d != NULL); diff --git a/fs/hfsplus/attributes.c b/fs/hfsplus/attributes.c index e6d554476db41cf61f1d850682f2aff0583e9122..eeebe80c6be4aa39878bee63521d2558d9a189da 100644 --- a/fs/hfsplus/attributes.c +++ b/fs/hfsplus/attributes.c @@ -292,6 +292,10 @@ static int __hfsplus_delete_attr(struct inode *inode, u32 cnid, return -ENOENT; } + /* Avoid btree corruption */ + hfs_bnode_read(fd->bnode, fd->search_key, + fd->keyoffset, fd->keylength); + err = hfs_brec_remove(fd); if (err) return err; diff --git a/fs/incfs/Kconfig b/fs/incfs/Kconfig index a655d599ea46cd1b71f3398a41eaaacdc6fa9cb0..1ffe31a9c0fff12ef41656fd4a4cbbb538649cd7 100644 --- a/fs/incfs/Kconfig +++ b/fs/incfs/Kconfig @@ -9,7 +9,6 @@ config INCREMENTAL_FS select X509_CERTIFICATE_PARSER select ASYMMETRIC_KEY_TYPE select ASYMMETRIC_PUBLIC_KEY_SUBTYPE - select PKCS7_MESSAGE_PARSER help Incremental FS is a read-only virtual file system that facilitates execution of programs while their binaries are still being lazily downloaded over the diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index 109329e0a180ec5ec1966f25ac0e14c4cf1523e7..074a733c7001732d1c0acbbc418d66e04234c4a0 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -2,19 +2,28 @@ /* * Copyright 2019 Google LLC */ -#include -#include -#include +#include #include +#include #include -#include #include -#include +#include +#include +#include +#include +#include #include "data_mgmt.h" #include "format.h" #include "integrity.h" +static void log_wake_up_all(struct work_struct *work) +{ + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct read_log *rl = container_of(dw, struct read_log, ml_wakeup_work); + wake_up_all(&rl->ml_notif_wq); +} + struct mount_info *incfs_alloc_mount_info(struct super_block *sb, struct mount_options *options, struct path *backing_dir_path) @@ -27,28 +36,20 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb, return ERR_PTR(-ENOMEM); mi->mi_sb = sb; - mi->mi_options = *options; mi->mi_backing_dir_path = *backing_dir_path; mi->mi_owner = get_current_cred(); path_get(&mi->mi_backing_dir_path); mutex_init(&mi->mi_dir_struct_mutex); mutex_init(&mi->mi_pending_reads_mutex); init_waitqueue_head(&mi->mi_pending_reads_notif_wq); + init_waitqueue_head(&mi->mi_log.ml_notif_wq); + INIT_DELAYED_WORK(&mi->mi_log.ml_wakeup_work, log_wake_up_all); + spin_lock_init(&mi->mi_log.rl_lock); INIT_LIST_HEAD(&mi->mi_reads_list_head); - if (options->read_log_pages != 0) { - size_t buf_size = PAGE_SIZE * options->read_log_pages; - - spin_lock_init(&mi->mi_log.rl_writer_lock); - init_waitqueue_head(&mi->mi_log.ml_notif_wq); - - mi->mi_log.rl_size = buf_size / sizeof(*mi->mi_log.rl_ring_buf); - mi->mi_log.rl_ring_buf = kzalloc(buf_size, GFP_NOFS); - if (!mi->mi_log.rl_ring_buf) { - error = -ENOMEM; - goto err; - } - } + error = incfs_realloc_mount_info(mi, options); + if (error) + goto err; return mi; @@ -57,17 +58,62 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb, return ERR_PTR(error); } +int incfs_realloc_mount_info(struct mount_info *mi, + struct mount_options *options) +{ + void *new_buffer = NULL; + void *old_buffer; + size_t new_buffer_size = 0; + + if (options->read_log_pages != mi->mi_options.read_log_pages) { + struct read_log_state log_state; + /* + * Even though having two buffers allocated at once isn't + * usually good, allocating a multipage buffer under a spinlock + * is even worse, so let's optimize for the shorter lock + * duration. It's not end of the world if we fail to increase + * the buffer size anyway. + */ + if (options->read_log_pages > 0) { + new_buffer_size = PAGE_SIZE * options->read_log_pages; + new_buffer = kzalloc(new_buffer_size, GFP_NOFS); + if (!new_buffer) + return -ENOMEM; + } + + spin_lock(&mi->mi_log.rl_lock); + old_buffer = mi->mi_log.rl_ring_buf; + mi->mi_log.rl_ring_buf = new_buffer; + mi->mi_log.rl_size = new_buffer_size; + log_state = (struct read_log_state){ + .generation_id = mi->mi_log.rl_head.generation_id + 1, + }; + mi->mi_log.rl_head = log_state; + mi->mi_log.rl_tail = log_state; + spin_unlock(&mi->mi_log.rl_lock); + + kfree(old_buffer); + } + + mi->mi_options = *options; + return 0; +} + void incfs_free_mount_info(struct mount_info *mi) { if (!mi) return; + flush_delayed_work(&mi->mi_log.ml_wakeup_work); + dput(mi->mi_index_dir); path_put(&mi->mi_backing_dir_path); mutex_destroy(&mi->mi_dir_struct_mutex); mutex_destroy(&mi->mi_pending_reads_mutex); put_cred(mi->mi_owner); kfree(mi->mi_log.rl_ring_buf); + kfree(mi->log_xattr); + kfree(mi->pending_read_xattr); kfree(mi); } @@ -116,8 +162,8 @@ struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf) error = mutex_lock_interruptible(&bfc->bc_mutex); if (error) goto out; - error = incfs_read_file_header(bfc, &df->df_metadata_off, - &df->df_id, &size); + error = incfs_read_file_header(bfc, &df->df_metadata_off, &df->df_id, + &size, &df->df_header_flags); mutex_unlock(&bfc->bc_mutex); if (error) @@ -125,7 +171,7 @@ struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf) df->df_size = size; if (size > 0) - df->df_block_count = get_blocks_count_for_size(size); + df->df_data_block_count = get_blocks_count_for_size(size); md_records = incfs_scan_metadata_chain(df); if (md_records < 0) @@ -134,7 +180,8 @@ struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf) out: if (error) { incfs_free_bfc(bfc); - df->df_backing_file_context = NULL; + if (df) + df->df_backing_file_context = NULL; incfs_free_data_file(df); return ERR_PTR(error); } @@ -214,49 +261,148 @@ static ssize_t decompress(struct mem_range src, struct mem_range dst) return result; } +static void log_read_one_record(struct read_log *rl, struct read_log_state *rs) +{ + union log_record *record = + (union log_record *)((u8 *)rl->rl_ring_buf + rs->next_offset); + size_t record_size; + + switch (record->full_record.type) { + case FULL: + rs->base_record = record->full_record; + record_size = sizeof(record->full_record); + break; + + case SAME_FILE: + rs->base_record.block_index = + record->same_file_record.block_index; + rs->base_record.absolute_ts_us += + record->same_file_record.relative_ts_us; + record_size = sizeof(record->same_file_record); + break; + + case SAME_FILE_NEXT_BLOCK: + ++rs->base_record.block_index; + rs->base_record.absolute_ts_us += + record->same_file_next_block.relative_ts_us; + record_size = sizeof(record->same_file_next_block); + break; + + case SAME_FILE_NEXT_BLOCK_SHORT: + ++rs->base_record.block_index; + rs->base_record.absolute_ts_us += + record->same_file_next_block_short.relative_ts_us; + record_size = sizeof(record->same_file_next_block_short); + break; + } + + rs->next_offset += record_size; + if (rs->next_offset > rl->rl_size - sizeof(*record)) { + rs->next_offset = 0; + ++rs->current_pass_no; + } + ++rs->current_record_no; +} + static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, - int block_index, bool timed_out) + int block_index) { struct read_log *log = &mi->mi_log; - struct read_log_state state; - s64 now_us = ktime_to_us(ktime_get()); - struct read_log_record record = { - .file_id = *id, - .block_index = block_index, - .timed_out = timed_out, - .timestamp_us = now_us - }; - - if (log->rl_size == 0) + struct read_log_state *head, *tail; + s64 now_us; + s64 relative_us; + union log_record record; + size_t record_size; + + /* + * This may read the old value, but it's OK to delay the logging start + * right after the configuration update. + */ + if (READ_ONCE(log->rl_size) == 0) + return; + + now_us = ktime_to_us(ktime_get()); + + spin_lock(&log->rl_lock); + if (log->rl_size == 0) { + spin_unlock(&log->rl_lock); return; + } - spin_lock(&log->rl_writer_lock); - state = READ_ONCE(log->rl_state); - log->rl_ring_buf[state.next_index] = record; - if (++state.next_index == log->rl_size) { - state.next_index = 0; - ++state.current_pass_no; + head = &log->rl_head; + tail = &log->rl_tail; + relative_us = now_us - head->base_record.absolute_ts_us; + + if (memcmp(id, &head->base_record.file_id, sizeof(incfs_uuid_t)) || + relative_us >= 1ll << 32) { + record.full_record = (struct full_record){ + .type = FULL, + .block_index = block_index, + .file_id = *id, + .absolute_ts_us = now_us, + }; + head->base_record.file_id = *id; + record_size = sizeof(struct full_record); + } else if (block_index != head->base_record.block_index + 1 || + relative_us >= 1 << 30) { + record.same_file_record = (struct same_file_record){ + .type = SAME_FILE, + .block_index = block_index, + .relative_ts_us = relative_us, + }; + record_size = sizeof(struct same_file_record); + } else if (relative_us >= 1 << 14) { + record.same_file_next_block = (struct same_file_next_block){ + .type = SAME_FILE_NEXT_BLOCK, + .relative_ts_us = relative_us, + }; + record_size = sizeof(struct same_file_next_block); + } else { + record.same_file_next_block_short = + (struct same_file_next_block_short){ + .type = SAME_FILE_NEXT_BLOCK_SHORT, + .relative_ts_us = relative_us, + }; + record_size = sizeof(struct same_file_next_block_short); } - WRITE_ONCE(log->rl_state, state); - spin_unlock(&log->rl_writer_lock); - wake_up_all(&log->ml_notif_wq); + head->base_record.block_index = block_index; + head->base_record.absolute_ts_us = now_us; + + /* Advance tail beyond area we are going to overwrite */ + while (tail->current_pass_no < head->current_pass_no && + tail->next_offset < head->next_offset + record_size) + log_read_one_record(log, tail); + + memcpy(((u8 *)log->rl_ring_buf) + head->next_offset, &record, + record_size); + head->next_offset += record_size; + if (head->next_offset > log->rl_size - sizeof(record)) { + head->next_offset = 0; + ++head->current_pass_no; + } + ++head->current_record_no; + + spin_unlock(&log->rl_lock); + schedule_delayed_work(&log->ml_wakeup_work, msecs_to_jiffies(16)); } -static int validate_hash_tree(struct file *bf, struct data_file *df, - int block_index, struct mem_range data, u8 *buf) +static int validate_hash_tree(struct file *bf, struct file *f, int block_index, + struct mem_range data, u8 *buf) { - u8 digest[INCFS_MAX_HASH_SIZE] = {}; + struct data_file *df = get_incfs_data_file(f); + u8 stored_digest[INCFS_MAX_HASH_SIZE] = {}; + u8 calculated_digest[INCFS_MAX_HASH_SIZE] = {}; struct mtree *tree = NULL; - struct ondisk_signature *sig = NULL; - struct mem_range calc_digest_rng; - struct mem_range saved_digest_rng; - struct mem_range root_hash_rng; + struct incfs_df_signature *sig = NULL; int digest_size; int hash_block_index = block_index; - int hash_per_block; - int lvl = 0; + int lvl; int res; + loff_t hash_block_offset[INCFS_MAX_MTREE_LEVELS]; + size_t hash_offset_in_block[INCFS_MAX_MTREE_LEVELS]; + int hash_per_block; + pgoff_t file_pages; tree = df->df_hash_tree; sig = df->df_signature; @@ -265,38 +411,60 @@ static int validate_hash_tree(struct file *bf, struct data_file *df, digest_size = tree->alg->digest_size; hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size; - calc_digest_rng = range(digest, digest_size); - res = incfs_calc_digest(tree->alg, data, calc_digest_rng); - if (res) - return res; - for (lvl = 0; lvl < tree->depth; lvl++) { - loff_t lvl_off = tree->hash_level_suboffset[lvl] + - sig->mtree_offset; - loff_t hash_block_off = lvl_off + - round_down(hash_block_index * digest_size, - INCFS_DATA_FILE_BLOCK_SIZE); - size_t hash_off_in_block = hash_block_index * digest_size - % INCFS_DATA_FILE_BLOCK_SIZE; - struct mem_range buf_range = range(buf, - INCFS_DATA_FILE_BLOCK_SIZE); - ssize_t read_res = incfs_kread(bf, buf, - INCFS_DATA_FILE_BLOCK_SIZE, hash_block_off); - - if (read_res < 0) - return read_res; - if (read_res != INCFS_DATA_FILE_BLOCK_SIZE) + loff_t lvl_off = tree->hash_level_suboffset[lvl]; + + hash_block_offset[lvl] = + lvl_off + round_down(hash_block_index * digest_size, + INCFS_DATA_FILE_BLOCK_SIZE); + hash_offset_in_block[lvl] = hash_block_index * digest_size % + INCFS_DATA_FILE_BLOCK_SIZE; + hash_block_index /= hash_per_block; + } + + memcpy(stored_digest, tree->root_hash, digest_size); + + file_pages = DIV_ROUND_UP(df->df_size, INCFS_DATA_FILE_BLOCK_SIZE); + for (lvl = tree->depth - 1; lvl >= 0; lvl--) { + pgoff_t hash_page = + file_pages + + hash_block_offset[lvl] / INCFS_DATA_FILE_BLOCK_SIZE; + struct page *page = find_get_page_flags( + f->f_inode->i_mapping, hash_page, FGP_ACCESSED); + + if (page && PageChecked(page)) { + u8 *addr = kmap_atomic(page); + + memcpy(stored_digest, addr + hash_offset_in_block[lvl], + digest_size); + kunmap_atomic(addr); + put_page(page); + continue; + } + + if (page) + put_page(page); + + res = incfs_kread(bf, buf, INCFS_DATA_FILE_BLOCK_SIZE, + hash_block_offset[lvl] + sig->hash_offset); + if (res < 0) + return res; + if (res != INCFS_DATA_FILE_BLOCK_SIZE) return -EIO; + res = incfs_calc_digest(tree->alg, + range(buf, INCFS_DATA_FILE_BLOCK_SIZE), + range(calculated_digest, digest_size)); + if (res) + return res; - saved_digest_rng = range(buf + hash_off_in_block, digest_size); - if (!incfs_equal_ranges(calc_digest_rng, saved_digest_rng)) { + if (memcmp(stored_digest, calculated_digest, digest_size)) { int i; bool zero = true; pr_debug("incfs: Hash mismatch lvl:%d blk:%d\n", lvl, block_index); - for (i = 0; i < saved_digest_rng.len; ++i) - if (saved_digest_rng.data[i]) { + for (i = 0; i < digest_size; i++) + if (stored_digest[i]) { zero = false; break; } @@ -306,84 +474,32 @@ static int validate_hash_tree(struct file *bf, struct data_file *df, return -EBADMSG; } - res = incfs_calc_digest(tree->alg, buf_range, calc_digest_rng); - if (res) - return res; - hash_block_index /= hash_per_block; - } - - root_hash_rng = range(tree->root_hash, digest_size); - if (!incfs_equal_ranges(calc_digest_rng, root_hash_rng)) { - pr_debug("incfs: Root hash mismatch blk:%d\n", block_index); - return -EBADMSG; - } - return 0; -} + memcpy(stored_digest, buf + hash_offset_in_block[lvl], + digest_size); -static int revalidate_signature(struct file *bf, struct data_file *df) -{ - struct ondisk_signature *sig = df->df_signature; - struct mem_range root_hash = {}; - int result = 0; - u8 *sig_buf = NULL; - u8 *add_data_buf = NULL; - ssize_t read_res; - - /* File has no signature. */ - if (!sig || !df->df_hash_tree || sig->sig_size == 0) - return 0; + page = grab_cache_page(f->f_inode->i_mapping, hash_page); + if (page) { + u8 *addr = kmap_atomic(page); - /* Signature has already been validated. */ - if (df->df_signature_validated) - return 0; - - add_data_buf = kzalloc(sig->add_data_size, GFP_NOFS); - if (!add_data_buf) { - result = -ENOMEM; - goto out; - } - - read_res = incfs_kread(bf, add_data_buf, sig->add_data_size, - sig->add_data_offset); - if (read_res < 0) { - result = read_res; - goto out; - } - if (read_res != sig->add_data_size) { - result = -EIO; - goto out; + memcpy(addr, buf, INCFS_DATA_FILE_BLOCK_SIZE); + kunmap_atomic(addr); + SetPageChecked(page); + unlock_page(page); + put_page(page); + } } - sig_buf = kzalloc(sig->sig_size, GFP_NOFS); - if (!sig_buf) { - result = -ENOMEM; - goto out; - } + res = incfs_calc_digest(tree->alg, data, + range(calculated_digest, digest_size)); + if (res) + return res; - read_res = incfs_kread(bf, sig_buf, sig->sig_size, sig->sig_offset); - if (read_res < 0) { - result = read_res; - goto out; - } - if (read_res != sig->sig_size) { - result = -EIO; - goto out; + if (memcmp(stored_digest, calculated_digest, digest_size)) { + pr_debug("incfs: Leaf hash mismatch blk:%d\n", block_index); + return -EBADMSG; } - root_hash = range(df->df_hash_tree->root_hash, - df->df_hash_tree->alg->digest_size); - - result = incfs_validate_pkcs7_signature( - range(sig_buf, sig->sig_size), - root_hash, - range(add_data_buf, sig->add_data_size)); - - if (result == 0) - df->df_signature_validated = true; -out: - kfree(sig_buf); - kfree(add_data_buf); - return result; + return 0; } static struct data_file_segment *get_file_segment(struct data_file *df, @@ -400,13 +516,28 @@ static bool is_data_block_present(struct data_file_block *block) (block->db_stored_size != 0); } +static void convert_data_file_block(struct incfs_blockmap_entry *bme, + struct data_file_block *res_block) +{ + u16 flags = le16_to_cpu(bme->me_flags); + + res_block->db_backing_file_data_offset = + le16_to_cpu(bme->me_data_offset_hi); + res_block->db_backing_file_data_offset <<= 32; + res_block->db_backing_file_data_offset |= + le32_to_cpu(bme->me_data_offset_lo); + res_block->db_stored_size = le16_to_cpu(bme->me_data_size); + res_block->db_comp_alg = (flags & INCFS_BLOCK_COMPRESSED_LZ4) ? + COMPRESSION_LZ4 : + COMPRESSION_NONE; +} + static int get_data_file_block(struct data_file *df, int index, struct data_file_block *res_block) { struct incfs_blockmap_entry bme = {}; struct backing_file_context *bfc = NULL; loff_t blockmap_off = 0; - u16 flags = 0; int error = 0; if (!df || !res_block) @@ -415,26 +546,184 @@ static int get_data_file_block(struct data_file *df, int index, blockmap_off = df->df_blockmap_off; bfc = df->df_backing_file_context; - if (index < 0 || index >= df->df_block_count || blockmap_off == 0) + if (index < 0 || blockmap_off == 0) return -EINVAL; error = incfs_read_blockmap_entry(bfc, index, blockmap_off, &bme); if (error) return error; - flags = le16_to_cpu(bme.me_flags); - res_block->db_backing_file_data_offset = - le16_to_cpu(bme.me_data_offset_hi); - res_block->db_backing_file_data_offset <<= 32; - res_block->db_backing_file_data_offset |= - le32_to_cpu(bme.me_data_offset_lo); - res_block->db_stored_size = le16_to_cpu(bme.me_data_size); - res_block->db_comp_alg = (flags & INCFS_BLOCK_COMPRESSED_LZ4) ? - COMPRESSION_LZ4 : - COMPRESSION_NONE; + convert_data_file_block(&bme, res_block); + return 0; +} + +static int check_room_for_one_range(u32 size, u32 size_out) +{ + if (size_out + sizeof(struct incfs_filled_range) > size) + return -ERANGE; + return 0; +} + +static int copy_one_range(struct incfs_filled_range *range, void __user *buffer, + u32 size, u32 *size_out) +{ + int error = check_room_for_one_range(size, *size_out); + if (error) + return error; + + if (copy_to_user(((char __user *)buffer) + *size_out, range, + sizeof(*range))) + return -EFAULT; + + *size_out += sizeof(*range); return 0; } +static int update_file_header_flags(struct data_file *df, u32 bits_to_reset, + u32 bits_to_set) +{ + int result; + u32 new_flags; + struct backing_file_context *bfc; + + if (!df) + return -EFAULT; + bfc = df->df_backing_file_context; + if (!bfc) + return -EFAULT; + + result = mutex_lock_interruptible(&bfc->bc_mutex); + if (result) + return result; + + new_flags = (df->df_header_flags & ~bits_to_reset) | bits_to_set; + if (new_flags != df->df_header_flags) { + df->df_header_flags = new_flags; + result = incfs_write_file_header_flags(bfc, new_flags); + } + + mutex_unlock(&bfc->bc_mutex); + + return result; +} + +#define READ_BLOCKMAP_ENTRIES 512 +int incfs_get_filled_blocks(struct data_file *df, + struct incfs_get_filled_blocks_args *arg) +{ + int error = 0; + bool in_range = false; + struct incfs_filled_range range; + void __user *buffer = u64_to_user_ptr(arg->range_buffer); + u32 size = arg->range_buffer_size; + u32 end_index = + arg->end_index ? arg->end_index : df->df_total_block_count; + u32 *size_out = &arg->range_buffer_size_out; + int i = READ_BLOCKMAP_ENTRIES - 1; + int entries_read = 0; + struct incfs_blockmap_entry *bme; + + *size_out = 0; + if (end_index > df->df_total_block_count) + end_index = df->df_total_block_count; + arg->total_blocks_out = df->df_total_block_count; + arg->data_blocks_out = df->df_data_block_count; + + if (df->df_header_flags & INCFS_FILE_COMPLETE) { + pr_debug("File marked full, fast get_filled_blocks"); + if (arg->start_index > end_index) { + arg->index_out = arg->start_index; + return 0; + } + arg->index_out = arg->start_index; + + error = check_room_for_one_range(size, *size_out); + if (error) + return error; + + range = (struct incfs_filled_range){ + .begin = arg->start_index, + .end = end_index, + }; + + error = copy_one_range(&range, buffer, size, size_out); + if (error) + return error; + arg->index_out = end_index; + return 0; + } + + bme = kzalloc(sizeof(*bme) * READ_BLOCKMAP_ENTRIES, + GFP_NOFS | __GFP_COMP); + if (!bme) + return -ENOMEM; + + for (arg->index_out = arg->start_index; arg->index_out < end_index; + ++arg->index_out) { + struct data_file_block dfb; + + if (++i == READ_BLOCKMAP_ENTRIES) { + entries_read = incfs_read_blockmap_entries( + df->df_backing_file_context, bme, + arg->index_out, READ_BLOCKMAP_ENTRIES, + df->df_blockmap_off); + if (entries_read < 0) { + error = entries_read; + break; + } + + i = 0; + } + + if (i >= entries_read) { + error = -EIO; + break; + } + + convert_data_file_block(bme + i, &dfb); + + if (is_data_block_present(&dfb) == in_range) + continue; + + if (!in_range) { + error = check_room_for_one_range(size, *size_out); + if (error) + break; + in_range = true; + range.begin = arg->index_out; + } else { + range.end = arg->index_out; + error = copy_one_range(&range, buffer, size, size_out); + if (error) { + /* there will be another try out of the loop, + * it will reset the index_out if it fails too + */ + break; + } + in_range = false; + } + } + + if (in_range) { + range.end = arg->index_out; + error = copy_one_range(&range, buffer, size, size_out); + if (error) + arg->index_out = range.begin; + } + + if (!error && in_range && arg->start_index == 0 && + end_index == df->df_total_block_count && + *size_out == sizeof(struct incfs_filled_range)) { + int result = + update_file_header_flags(df, 0, INCFS_FILE_COMPLETE); + /* Log failure only, since it's just a failed optimization */ + pr_debug("Marked file full with result %d", result); + } + + kfree(bme); + return error; +} + static bool is_read_done(struct pending_read *read) { return atomic_read_acquire(&read->done) != 0; @@ -534,7 +823,7 @@ static int wait_for_data_block(struct data_file *df, int block_index, if (!df || !res_block) return -EFAULT; - if (block_index < 0 || block_index >= df->df_block_count) + if (block_index < 0 || block_index >= df->df_data_block_count) return -EINVAL; if (df->df_blockmap_off <= 0) @@ -565,8 +854,7 @@ static int wait_for_data_block(struct data_file *df, int block_index, mi = df->df_mount_info; if (timeout_ms == 0) { - log_block_read(mi, &df->df_id, block_index, - true /*timed out*/); + log_block_read(mi, &df->df_id, block_index); return -ETIME; } @@ -585,8 +873,7 @@ static int wait_for_data_block(struct data_file *df, int block_index, if (wait_res == 0) { /* Wait has timed out */ - log_block_read(mi, &df->df_id, block_index, - true /*timed out*/); + log_block_read(mi, &df->df_id, block_index); return -ETIME; } if (wait_res < 0) { @@ -623,7 +910,7 @@ static int wait_for_data_block(struct data_file *df, int block_index, return error; } -ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, +ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, int index, int timeout_ms, struct mem_range tmp) { @@ -633,6 +920,7 @@ ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, struct mount_info *mi = NULL; struct file *bf = NULL; struct data_file_block block = {}; + struct data_file *df = get_incfs_data_file(f); if (!dst.data || !df) return -EFAULT; @@ -675,28 +963,21 @@ ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, } if (result > 0) { - int err = validate_hash_tree(bf, df, index, dst, tmp.data); - - if (err < 0) - result = err; - } - - if (result > 0) { - int err = revalidate_signature(bf, df); + int err = validate_hash_tree(bf, f, index, dst, tmp.data); if (err < 0) result = err; } if (result >= 0) - log_block_read(mi, &df->df_id, index, false /*timed out*/); + log_block_read(mi, &df->df_id, index); out: return result; } int incfs_process_new_data_block(struct data_file *df, - struct incfs_new_data_block *block, u8 *data) + struct incfs_fill_block *block, u8 *data) { struct mount_info *mi = NULL; struct backing_file_context *bfc = NULL; @@ -711,7 +992,7 @@ int incfs_process_new_data_block(struct data_file *df, bfc = df->df_backing_file_context; mi = df->df_mount_info; - if (block->block_index >= df->df_block_count) + if (block->block_index >= df->df_data_block_count) return -ERANGE; segment = get_file_segment(df, block->block_index); @@ -753,7 +1034,7 @@ int incfs_process_new_data_block(struct data_file *df, int incfs_read_file_signature(struct data_file *df, struct mem_range dst) { struct file *bf = df->df_backing_file_context->bc_file; - struct ondisk_signature *sig; + struct incfs_df_signature *sig; int read_res = 0; if (!dst.data) @@ -778,12 +1059,12 @@ int incfs_read_file_signature(struct data_file *df, struct mem_range dst) } int incfs_process_new_hash_block(struct data_file *df, - struct incfs_new_data_block *block, u8 *data) + struct incfs_fill_block *block, u8 *data) { struct backing_file_context *bfc = NULL; struct mount_info *mi = NULL; struct mtree *hash_tree = NULL; - struct ondisk_signature *sig = NULL; + struct incfs_df_signature *sig = NULL; loff_t hash_area_base = 0; loff_t hash_area_size = 0; int error = 0; @@ -802,11 +1083,11 @@ int incfs_process_new_hash_block(struct data_file *df, hash_tree = df->df_hash_tree; sig = df->df_signature; - if (!hash_tree || !sig || sig->mtree_offset == 0) + if (!hash_tree || !sig || sig->hash_offset == 0) return -ENOTSUPP; - hash_area_base = sig->mtree_offset; - hash_area_size = sig->mtree_size; + hash_area_base = sig->hash_offset; + hash_area_size = sig->hash_size; if (hash_area_size < block->block_index * INCFS_DATA_FILE_BLOCK_SIZE + block->data_len) { /* Hash block goes beyond dedicated hash area of this file. */ @@ -814,11 +1095,12 @@ int incfs_process_new_hash_block(struct data_file *df, } error = mutex_lock_interruptible(&bfc->bc_mutex); - if (!error) + if (!error) { error = incfs_write_hash_block_to_backing_file( bfc, range(data, block->data_len), block->block_index, - hash_area_base); - mutex_unlock(&bfc->bc_mutex); + hash_area_base, df->df_blockmap_off, df->df_size); + mutex_unlock(&bfc->bc_mutex); + } return error; } @@ -833,9 +1115,10 @@ static int process_blockmap_md(struct incfs_blockmap *bm, if (!df) return -EFAULT; - if (df->df_block_count != block_count) + if (df->df_data_block_count > block_count) return -EBADMSG; + df->df_total_block_count = block_count; df->df_blockmap_off = base_off; return error; } @@ -864,58 +1147,72 @@ static int process_file_signature_md(struct incfs_file_signature *sg, { struct data_file *df = handler->context; struct mtree *hash_tree = NULL; - struct ondisk_signature *signature = NULL; int error = 0; - loff_t base_tree_off = le64_to_cpu(sg->sg_hash_tree_offset); - u32 tree_size = le32_to_cpu(sg->sg_hash_tree_size); - loff_t sig_off = le64_to_cpu(sg->sg_sig_offset); - u32 sig_size = le32_to_cpu(sg->sg_sig_size); - loff_t add_data_off = le64_to_cpu(sg->sg_add_data_offset); - u32 add_data_size = le32_to_cpu(sg->sg_add_data_size); + struct incfs_df_signature *signature = + kzalloc(sizeof(*signature), GFP_NOFS); + void *buf = NULL; + ssize_t read; - if (!df) - return -ENOENT; + if (!signature) + return -ENOMEM; + + if (!df || !df->df_backing_file_context || + !df->df_backing_file_context->bc_file) { + error = -ENOENT; + goto out; + } - signature = kzalloc(sizeof(*signature), GFP_NOFS); - if (!signature) { + signature->hash_offset = le64_to_cpu(sg->sg_hash_tree_offset); + signature->hash_size = le32_to_cpu(sg->sg_hash_tree_size); + signature->sig_offset = le64_to_cpu(sg->sg_sig_offset); + signature->sig_size = le32_to_cpu(sg->sg_sig_size); + + buf = kzalloc(signature->sig_size, GFP_NOFS); + if (!buf) { error = -ENOMEM; goto out; } - signature->add_data_offset = add_data_off; - signature->add_data_size = add_data_size; - signature->sig_offset = sig_off; - signature->sig_size = sig_size; - signature->mtree_offset = base_tree_off; - signature->mtree_size = tree_size; + read = incfs_kread(df->df_backing_file_context->bc_file, buf, + signature->sig_size, signature->sig_offset); + if (read < 0) { + error = read; + goto out; + } - hash_tree = incfs_alloc_mtree(sg->sg_hash_alg, df->df_block_count, - range(sg->sg_root_hash, sizeof(sg->sg_root_hash))); + if (read != signature->sig_size) { + error = -EINVAL; + goto out; + } + + hash_tree = incfs_alloc_mtree(range(buf, signature->sig_size), + df->df_data_block_count); if (IS_ERR(hash_tree)) { error = PTR_ERR(hash_tree); hash_tree = NULL; goto out; } - if (hash_tree->hash_tree_area_size != tree_size) { + if (hash_tree->hash_tree_area_size != signature->hash_size) { error = -EINVAL; goto out; } - if (tree_size > 0 && handler->md_record_offset <= base_tree_off) { + if (signature->hash_size > 0 && + handler->md_record_offset <= signature->hash_offset) { error = -EINVAL; goto out; } - if (handler->md_record_offset <= signature->add_data_offset || - handler->md_record_offset <= signature->sig_offset) { + if (handler->md_record_offset <= signature->sig_offset) { error = -EINVAL; goto out; } df->df_hash_tree = hash_tree; + hash_tree = NULL; df->df_signature = signature; + signature = NULL; out: - if (error) { - incfs_free_mtree(hash_tree); - kfree(signature); - } + incfs_free_mtree(hash_tree); + kfree(signature); + kfree(buf); return error; } @@ -971,6 +1268,17 @@ int incfs_scan_metadata_chain(struct data_file *df) result = records_count; } mutex_unlock(&bfc->bc_mutex); + + if (df->df_hash_tree) { + int hash_block_count = get_blocks_count_for_size( + df->df_hash_tree->hash_tree_area_size); + + if (df->df_data_block_count + hash_block_count != + df->df_total_block_count) + result = -EINVAL; + } else if (df->df_data_block_count != df->df_total_block_count) + result = -EINVAL; + out: kfree(handler); return result; @@ -1036,36 +1344,29 @@ struct read_log_state incfs_get_log_state(struct mount_info *mi) struct read_log *log = &mi->mi_log; struct read_log_state result; - spin_lock(&log->rl_writer_lock); - result = READ_ONCE(log->rl_state); - spin_unlock(&log->rl_writer_lock); + spin_lock(&log->rl_lock); + result = log->rl_head; + spin_unlock(&log->rl_lock); return result; } -static u64 calc_record_count(const struct read_log_state *state, int rl_size) -{ - return state->current_pass_no * (u64)rl_size + state->next_index; -} - int incfs_get_uncollected_logs_count(struct mount_info *mi, - struct read_log_state state) + const struct read_log_state *state) { struct read_log *log = &mi->mi_log; - - u64 count = calc_record_count(&log->rl_state, log->rl_size) - - calc_record_count(&state, log->rl_size); - return min_t(int, count, log->rl_size); -} - -static void fill_pending_read_from_log_record( - struct incfs_pending_read_info *dest, const struct read_log_record *src, - struct read_log_state *state, u64 log_size) -{ - dest->file_id = src->file_id; - dest->block_index = src->block_index; - dest->serial_number = - state->current_pass_no * log_size + state->next_index; - dest->timestamp_us = src->timestamp_us; + u32 generation; + u64 head_no, tail_no; + + spin_lock(&log->rl_lock); + tail_no = log->rl_tail.current_record_no; + head_no = log->rl_head.current_record_no; + generation = log->rl_head.generation_id; + spin_unlock(&log->rl_lock); + + if (generation != state->generation_id) + return head_no - tail_no; + else + return head_no - max_t(u64, tail_no, state->current_record_no); } int incfs_collect_logged_reads(struct mount_info *mi, @@ -1073,58 +1374,47 @@ int incfs_collect_logged_reads(struct mount_info *mi, struct incfs_pending_read_info *reads, int reads_size) { - struct read_log *log = &mi->mi_log; - struct read_log_state live_state = incfs_get_log_state(mi); - u64 read_count = calc_record_count(reader_state, log->rl_size); - u64 written_count = calc_record_count(&live_state, log->rl_size); int dst_idx; + struct read_log *log = &mi->mi_log; + struct read_log_state *head, *tail; - if (reader_state->next_index >= log->rl_size || - read_count > written_count) - return -ERANGE; + spin_lock(&log->rl_lock); + head = &log->rl_head; + tail = &log->rl_tail; - if (read_count == written_count) - return 0; + if (reader_state->generation_id != head->generation_id) { + pr_debug("read ptr is wrong generation: %u/%u", + reader_state->generation_id, head->generation_id); - if (read_count > written_count) { - /* This reader is somehow ahead of the writer. */ - pr_debug("incfs: Log reader is ahead of writer\n"); - *reader_state = live_state; + *reader_state = (struct read_log_state){ + .generation_id = head->generation_id, + }; } - if (written_count - read_count > log->rl_size) { - /* - * Reading pointer is too far behind, - * start from the record following the write pointer. - */ - pr_debug("incfs: read pointer is behind, moving: %u/%u -> %u/%u / %u\n", - (u32)reader_state->next_index, - (u32)reader_state->current_pass_no, - (u32)live_state.next_index, - (u32)live_state.current_pass_no - 1, (u32)log->rl_size); + if (reader_state->current_record_no < tail->current_record_no) { + pr_debug("read ptr is behind, moving: %u/%u -> %u/%u\n", + (u32)reader_state->next_offset, + (u32)reader_state->current_pass_no, + (u32)tail->next_offset, (u32)tail->current_pass_no); - *reader_state = (struct read_log_state){ - .next_index = live_state.next_index, - .current_pass_no = live_state.current_pass_no - 1, - }; + *reader_state = *tail; } for (dst_idx = 0; dst_idx < reads_size; dst_idx++) { - if (reader_state->next_index == live_state.next_index && - reader_state->current_pass_no == live_state.current_pass_no) + if (reader_state->current_record_no == head->current_record_no) break; - fill_pending_read_from_log_record( - &reads[dst_idx], - &log->rl_ring_buf[reader_state->next_index], - reader_state, log->rl_size); + log_read_one_record(log, reader_state); - reader_state->next_index++; - if (reader_state->next_index == log->rl_size) { - reader_state->next_index = 0; - reader_state->current_pass_no++; - } + reads[dst_idx] = (struct incfs_pending_read_info){ + .file_id = reader_state->base_record.file_id, + .block_index = reader_state->base_record.block_index, + .serial_number = reader_state->current_record_no, + .timestamp_us = reader_state->base_record.absolute_ts_us + }; } + + spin_unlock(&log->rl_lock); return dst_idx; } diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index 82ccab3be4bb17bdb6bf22cd64dffebd59bd7978..2726867835a89b90ff062db78c4082cfa364854c 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -20,38 +20,78 @@ #define SEGMENTS_PER_FILE 3 -struct read_log_record { - u32 block_index : 31; - - u32 timed_out : 1; - - u64 timestamp_us; +enum LOG_RECORD_TYPE { + FULL, + SAME_FILE, + SAME_FILE_NEXT_BLOCK, + SAME_FILE_NEXT_BLOCK_SHORT, +}; +struct full_record { + enum LOG_RECORD_TYPE type : 2; /* FULL */ + u32 block_index : 30; incfs_uuid_t file_id; -} __packed; + u64 absolute_ts_us; +} __packed; /* 28 bytes */ + +struct same_file_record { + enum LOG_RECORD_TYPE type : 2; /* SAME_FILE */ + u32 block_index : 30; + u32 relative_ts_us; /* max 2^32 us ~= 1 hour (1:11:30) */ +} __packed; /* 12 bytes */ + +struct same_file_next_block { + enum LOG_RECORD_TYPE type : 2; /* SAME_FILE_NEXT_BLOCK */ + u32 relative_ts_us : 30; /* max 2^30 us ~= 15 min (17:50) */ +} __packed; /* 4 bytes */ + +struct same_file_next_block_short { + enum LOG_RECORD_TYPE type : 2; /* SAME_FILE_NEXT_BLOCK_SHORT */ + u16 relative_ts_us : 14; /* max 2^14 us ~= 16 ms */ +} __packed; /* 2 bytes */ + +union log_record { + struct full_record full_record; + struct same_file_record same_file_record; + struct same_file_next_block same_file_next_block; + struct same_file_next_block_short same_file_next_block_short; +}; struct read_log_state { - /* Next slot in rl_ring_buf to write to. */ - u32 next_index; + /* Log buffer generation id, incremented on configuration changes */ + u32 generation_id; + + /* Offset in rl_ring_buf to write into. */ + u32 next_offset; - /* Current number of writer pass over rl_ring_buf */ + /* Current number of writer passes over rl_ring_buf */ u32 current_pass_no; + + /* Current full_record to diff against */ + struct full_record base_record; + + /* Current record number counting from configuration change */ + u64 current_record_no; }; /* A ring buffer to save records about data blocks which were recently read. */ struct read_log { - struct read_log_record *rl_ring_buf; + void *rl_ring_buf; - struct read_log_state rl_state; + int rl_size; - spinlock_t rl_writer_lock; + struct read_log_state rl_head; - int rl_size; + struct read_log_state rl_tail; - /* - * A queue of waiters who want to be notified about reads. - */ + /* A lock to protect the above fields */ + spinlock_t rl_lock; + + /* A queue of waiters who want to be notified about reads */ wait_queue_head_t ml_notif_wq; + + /* A work item to wake up those waiters without slowing down readers */ + struct delayed_work ml_wakeup_work; }; struct mount_options { @@ -105,6 +145,12 @@ struct mount_info { /* Temporary buffer for read logger. */ struct read_log mi_log; + + void *log_xattr; + size_t log_xattr_size; + + void *pending_read_xattr; + size_t pending_read_xattr_size; }; struct data_file_block { @@ -177,16 +223,20 @@ struct data_file { /* File size in bytes */ loff_t df_size; - int df_block_count; /* File size in DATA_FILE_BLOCK_SIZE blocks */ + /* File header flags */ + u32 df_header_flags; + + /* File size in DATA_FILE_BLOCK_SIZE blocks */ + int df_data_block_count; + + /* Total number of blocks, data + hash */ + int df_total_block_count; struct file_attr n_attr; struct mtree *df_hash_tree; - struct ondisk_signature *df_signature; - - /* True, if file signature has already been validated. */ - bool df_signature_validated; + struct incfs_df_signature *df_signature; }; struct dir_file { @@ -213,6 +263,9 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb, struct mount_options *options, struct path *backing_dir_path); +int incfs_realloc_mount_info(struct mount_info *mi, + struct mount_options *options); + void incfs_free_mount_info(struct mount_info *mi); struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf); @@ -223,18 +276,20 @@ int incfs_scan_metadata_chain(struct data_file *df); struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf); void incfs_free_dir_file(struct dir_file *dir); -ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, +ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f, int index, int timeout_ms, struct mem_range tmp); +int incfs_get_filled_blocks(struct data_file *df, + struct incfs_get_filled_blocks_args *arg); + int incfs_read_file_signature(struct data_file *df, struct mem_range dst); int incfs_process_new_data_block(struct data_file *df, - struct incfs_new_data_block *block, u8 *data); + struct incfs_fill_block *block, u8 *data); int incfs_process_new_hash_block(struct data_file *df, - struct incfs_new_data_block *block, u8 *data); - + struct incfs_fill_block *block, u8 *data); bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number); @@ -253,14 +308,14 @@ int incfs_collect_logged_reads(struct mount_info *mi, int reads_size); struct read_log_state incfs_get_log_state(struct mount_info *mi); int incfs_get_uncollected_logs_count(struct mount_info *mi, - struct read_log_state state); + const struct read_log_state *state); static inline struct inode_info *get_incfs_node(struct inode *inode) { if (!inode) return NULL; - if (inode->i_sb->s_magic != INCFS_MAGIC_NUMBER) { + if (inode->i_sb->s_magic != (long) INCFS_MAGIC_NUMBER) { /* This inode doesn't belong to us. */ pr_warn_once("incfs: %s on an alien inode.", __func__); return NULL; diff --git a/fs/incfs/format.c b/fs/incfs/format.c index db71f527cf3637b357ef527e692a772b78fa4837..c56e559b68938ef4332acf6f0303a443941e8623 100644 --- a/fs/incfs/format.c +++ b/fs/incfs/format.c @@ -13,6 +13,7 @@ #include #include "format.h" +#include "data_mgmt.h" struct backing_file_context *incfs_alloc_bfc(struct file *backing_file) { @@ -93,7 +94,6 @@ static int append_zeros(struct backing_file_context *bfc, size_t len) { loff_t file_size = 0; loff_t new_last_byte_offset = 0; - int res = 0; if (!bfc) return -EFAULT; @@ -110,28 +110,18 @@ static int append_zeros(struct backing_file_context *bfc, size_t len) */ file_size = incfs_get_end_offset(bfc->bc_file); new_last_byte_offset = file_size + len - 1; - res = vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1); - if (res) - return res; - - res = vfs_fsync_range(bfc->bc_file, file_size, file_size + len, 1); - return res; + return vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1); } static int write_to_bf(struct backing_file_context *bfc, const void *buf, - size_t count, loff_t pos, bool sync) + size_t count, loff_t pos) { - ssize_t res = 0; + ssize_t res = incfs_kwrite(bfc->bc_file, buf, count, pos); - res = incfs_kwrite(bfc->bc_file, buf, count, pos); if (res < 0) return res; if (res != count) return -EIO; - - if (sync) - return vfs_fsync_range(bfc->bc_file, pos, pos + count, 1); - return 0; } @@ -185,7 +175,7 @@ static int append_md_to_backing_file(struct backing_file_context *bfc, /* Write the metadata record to the end of the backing file */ record_offset = file_pos; new_md_offset = cpu_to_le64(record_offset); - result = write_to_bf(bfc, record, record_size, file_pos, true); + result = write_to_bf(bfc, record, record_size, file_pos); if (result) return result; @@ -206,7 +196,7 @@ static int append_md_to_backing_file(struct backing_file_context *bfc, fh_first_md_offset); } result = write_to_bf(bfc, &new_md_offset, sizeof(new_md_offset), - file_pos, true); + file_pos); if (result) return result; @@ -214,12 +204,22 @@ static int append_md_to_backing_file(struct backing_file_context *bfc, return result; } +int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags) +{ + if (!bfc) + return -EFAULT; + + return write_to_bf(bfc, &flags, sizeof(flags), + offsetof(struct incfs_file_header, + fh_file_header_flags)); +} + /* * Reserve 0-filled space for the blockmap body, and append * incfs_blockmap metadata record pointing to it. */ int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, - u32 block_count, loff_t *map_base_off) + u32 block_count) { struct incfs_blockmap blockmap = {}; int result = 0; @@ -245,12 +245,9 @@ int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, /* Write blockmap metadata record pointing to the body written above. */ blockmap.m_base_offset = cpu_to_le64(file_end); result = append_md_to_backing_file(bfc, &blockmap.m_header); - if (result) { + if (result) /* Error, rollback file changes */ truncate_backing_file(bfc, file_end); - } else if (map_base_off) { - *map_base_off = file_end; - } return result; } @@ -283,7 +280,7 @@ int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, file_attr.fa_offset = cpu_to_le64(value_offset); file_attr.fa_crc = cpu_to_le32(crc); - result = write_to_bf(bfc, value.data, value.len, value_offset, true); + result = write_to_bf(bfc, value.data, value.len, value_offset); if (result) return result; @@ -299,9 +296,7 @@ int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, } int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, - u8 hash_alg, u32 tree_size, - struct mem_range root_hash, struct mem_range add_data, - struct mem_range sig) + struct mem_range sig, u32 tree_size) { struct incfs_file_signature sg = {}; int result = 0; @@ -311,8 +306,6 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, if (!bfc) return -EFAULT; - if (root_hash.len > sizeof(sg.sg_root_hash)) - return -E2BIG; LOCK_REQUIRED(bfc->bc_mutex); @@ -321,32 +314,19 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, sg.sg_header.h_md_entry_type = INCFS_MD_SIGNATURE; sg.sg_header.h_record_size = cpu_to_le16(sizeof(sg)); sg.sg_header.h_next_md_offset = cpu_to_le64(0); - sg.sg_hash_alg = hash_alg; if (sig.data != NULL && sig.len > 0) { loff_t pos = incfs_get_end_offset(bfc->bc_file); sg.sg_sig_size = cpu_to_le32(sig.len); sg.sg_sig_offset = cpu_to_le64(pos); - result = write_to_bf(bfc, sig.data, sig.len, pos, false); - if (result) - goto err; - } - - if (add_data.len > 0) { - loff_t pos = incfs_get_end_offset(bfc->bc_file); - - sg.sg_add_data_size = cpu_to_le32(add_data.len); - sg.sg_add_data_offset = cpu_to_le64(pos); - - result = write_to_bf(bfc, add_data.data, - add_data.len, pos, false); + result = write_to_bf(bfc, sig.data, sig.len, pos); if (result) goto err; } tree_area_pos = incfs_get_end_offset(bfc->bc_file); - if (hash_alg && tree_size > 0) { + if (tree_size > 0) { if (tree_size > 5 * INCFS_DATA_FILE_BLOCK_SIZE) { /* * If hash tree is big enough, it makes sense to @@ -369,15 +349,13 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, sg.sg_hash_tree_size = cpu_to_le32(tree_size); sg.sg_hash_tree_offset = cpu_to_le64(tree_area_pos); } - memcpy(sg.sg_root_hash, root_hash.data, root_hash.len); /* Write a hash tree metadata record pointing to the hash tree above. */ result = append_md_to_backing_file(bfc, &sg.sg_header); err: - if (result) { + if (result) /* Error, rollback file changes */ truncate_backing_file(bfc, rollback_pos); - } return result; } @@ -411,7 +389,7 @@ int incfs_write_fh_to_backing_file(struct backing_file_context *bfc, if (file_pos != 0) return -EEXIST; - return write_to_bf(bfc, &fh, sizeof(fh), file_pos, true); + return write_to_bf(bfc, &fh, sizeof(fh), file_pos); } /* Write a given data block and update file's blockmap to point it. */ @@ -440,7 +418,7 @@ int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, } /* Write the block data at the end of the backing file. */ - result = write_to_bf(bfc, block.data, block.len, data_offset, false); + result = write_to_bf(bfc, block.data, block.len, data_offset); if (result) return result; @@ -450,18 +428,25 @@ int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, bm_entry.me_data_size = cpu_to_le16((u16)block.len); bm_entry.me_flags = cpu_to_le16(flags); - result = write_to_bf(bfc, &bm_entry, sizeof(bm_entry), - bm_entry_off, false); - return result; + return write_to_bf(bfc, &bm_entry, sizeof(bm_entry), + bm_entry_off); } int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, - struct mem_range block, - int block_index, loff_t hash_area_off) + struct mem_range block, + int block_index, + loff_t hash_area_off, + loff_t bm_base_off, + loff_t file_size) { + struct incfs_blockmap_entry bm_entry = {}; + int result; loff_t data_offset = 0; loff_t file_end = 0; - + loff_t bm_entry_off = + bm_base_off + + sizeof(struct incfs_blockmap_entry) * + (block_index + get_blocks_count_for_size(file_size)); if (!bfc) return -EFAULT; @@ -475,7 +460,16 @@ int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, return -EINVAL; } - return write_to_bf(bfc, block.data, block.len, data_offset, false); + result = write_to_bf(bfc, block.data, block.len, data_offset); + if (result) + return result; + + bm_entry.me_data_offset_lo = cpu_to_le32((u32)data_offset); + bm_entry.me_data_offset_hi = cpu_to_le16((u16)(data_offset >> 32)); + bm_entry.me_data_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE); + bm_entry.me_flags = cpu_to_le16(INCFS_BLOCK_HASH); + + return write_to_bf(bfc, &bm_entry, sizeof(bm_entry), bm_entry_off); } /* Initialize a new image in a given backing file. */ @@ -505,8 +499,19 @@ int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index, loff_t bm_base_off, struct incfs_blockmap_entry *bm_entry) { - return incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1, - bm_base_off); + int error = incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1, + bm_base_off); + + if (error < 0) + return error; + + if (error == 0) + return -EIO; + + if (error != 1) + return -EFAULT; + + return 0; } int incfs_read_blockmap_entries(struct backing_file_context *bfc, @@ -530,15 +535,12 @@ int incfs_read_blockmap_entries(struct backing_file_context *bfc, bm_entry_off); if (result < 0) return result; - if (result < bytes_to_read) - return -EIO; - return 0; + return result / sizeof(*entries); } - int incfs_read_file_header(struct backing_file_context *bfc, loff_t *first_md_off, incfs_uuid_t *uuid, - u64 *file_size) + u64 *file_size, u32 *flags) { ssize_t bytes_read = 0; struct incfs_file_header fh = {}; @@ -572,6 +574,8 @@ int incfs_read_file_header(struct backing_file_context *bfc, *uuid = fh.fh_uuid; if (file_size) *file_size = le64_to_cpu(fh.fh_file_size); + if (flags) + *flags = le32_to_cpu(fh.fh_file_header_flags); return 0; } diff --git a/fs/incfs/format.h b/fs/incfs/format.h index a86881482e19110106b02033b744eb3d6877b10d..1a83349bb2eb705a25f09fe2e5747d6fcb2ad827 100644 --- a/fs/incfs/format.h +++ b/fs/incfs/format.h @@ -121,6 +121,10 @@ enum incfs_metadata_type { INCFS_MD_SIGNATURE = 3 }; +enum incfs_file_header_flags { + INCFS_FILE_COMPLETE = 1 << 0, +}; + /* Header included at the beginning of all metadata records on the disk. */ struct incfs_md_header { __u8 h_md_entry_type; @@ -159,8 +163,8 @@ struct incfs_file_header { /* INCFS_DATA_FILE_BLOCK_SIZE */ __le16 fh_data_block_size; - /* Padding, also reserved for future use. */ - __le32 fh_dummy; + /* File flags, from incfs_file_header_flags */ + __le32 fh_file_header_flags; /* Offset of the first metadata record */ __le64 fh_first_md_offset; @@ -178,6 +182,7 @@ struct incfs_file_header { enum incfs_block_map_entry_flags { INCFS_BLOCK_COMPRESSED_LZ4 = (1 << 0), + INCFS_BLOCK_HASH = (1 << 1), }; /* Block map entry pointing to an actual location of the data block. */ @@ -217,27 +222,27 @@ struct incfs_file_attr { __le32 fa_crc; } __packed; -/* Metadata record for file attribute. Type = INCFS_MD_SIGNATURE */ +/* Metadata record for file signature. Type = INCFS_MD_SIGNATURE */ struct incfs_file_signature { struct incfs_md_header sg_header; - __u8 sg_hash_alg; /* Value from incfs_hash_tree_algorithm */ + __le32 sg_sig_size; /* The size of the signature. */ + + __le64 sg_sig_offset; /* Signature's offset in the backing file */ __le32 sg_hash_tree_size; /* The size of the hash tree. */ __le64 sg_hash_tree_offset; /* Hash tree offset in the backing file */ - - __u8 sg_root_hash[INCFS_MAX_HASH_SIZE]; - - __le32 sg_sig_size; /* The size of the pkcs7 signature. */ - - __le64 sg_sig_offset; /* pkcs7 signature's offset in the backing file */ - - __le32 sg_add_data_size; /* The size of the additional data. */ - - __le64 sg_add_data_offset; /* Additional data's offset */ } __packed; +/* In memory version of above */ +struct incfs_df_signature { + u32 sig_size; + u64 sig_offset; + u32 hash_size; + u64 hash_offset; +}; + /* State of the backing file. */ struct backing_file_context { /* Protects writes to bc_file */ @@ -253,23 +258,6 @@ struct backing_file_context { loff_t bc_last_md_record_offset; }; - -/* Backing file locations of things required for signature validation. */ -struct ondisk_signature { - - loff_t add_data_offset; /* Additional data's offset */ - - loff_t sig_offset; /* pkcs7 signature's offset in the backing file */ - - loff_t mtree_offset; /* Backing file offset of the hash tree. */ - - u32 add_data_size; /* The size of the additional data. */ - - u32 sig_size; /* The size of the pkcs7 signature. */ - - u32 mtree_size; /* The size of the hash tree. */ -}; - struct metadata_handler { loff_t md_record_offset; loff_t md_prev_record_offset; @@ -301,7 +289,7 @@ void incfs_free_bfc(struct backing_file_context *bfc); /* Writing stuff */ int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, - u32 block_count, loff_t *map_base_off); + u32 block_count); int incfs_write_fh_to_backing_file(struct backing_file_context *bfc, incfs_uuid_t *uuid, u64 file_size); @@ -312,16 +300,19 @@ int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, u16 flags); int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, - struct mem_range block, - int block_index, loff_t hash_area_off); + struct mem_range block, + int block_index, + loff_t hash_area_off, + loff_t bm_base_off, + loff_t file_size); int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, struct mem_range value, struct incfs_file_attr *attr); int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, - u8 hash_alg, u32 tree_size, - struct mem_range root_hash, struct mem_range add_data, - struct mem_range sig); + struct mem_range sig, u32 tree_size); + +int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags); int incfs_make_empty_backing_file(struct backing_file_context *bfc, incfs_uuid_t *uuid, u64 file_size); @@ -329,7 +320,7 @@ int incfs_make_empty_backing_file(struct backing_file_context *bfc, /* Reading stuff */ int incfs_read_file_header(struct backing_file_context *bfc, loff_t *first_md_off, incfs_uuid_t *uuid, - u64 *file_size); + u64 *file_size, u32 *flags); int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index, loff_t bm_base_off, diff --git a/fs/incfs/integrity.c b/fs/incfs/integrity.c index feb212c38945721140b3147726080c14de1c6f4f..bce319ec2e520879abb69d3464ce87f65180e606 100644 --- a/fs/incfs/integrity.c +++ b/fs/incfs/integrity.c @@ -6,74 +6,9 @@ #include #include #include -#include #include "integrity.h" -int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, - struct mem_range root_hash, struct mem_range add_data) -{ - struct pkcs7_message *pkcs7 = NULL; - const void *data = NULL; - size_t data_len = 0; - const char *p; - int err; - - pkcs7 = pkcs7_parse_message(pkcs7_blob.data, pkcs7_blob.len); - if (IS_ERR(pkcs7)) { - pr_debug("PKCS#7 parsing error. ptr=%p size=%ld err=%ld\n", - pkcs7_blob.data, pkcs7_blob.len, -PTR_ERR(pkcs7)); - return PTR_ERR(pkcs7); - } - - err = pkcs7_get_content_data(pkcs7, &data, &data_len, NULL); - if (err || data_len == 0 || data == NULL) { - pr_debug("PKCS#7 message does not contain data\n"); - err = -EBADMSG; - goto out; - } - - if (root_hash.len == 0) { - pr_debug("Root hash is empty.\n"); - err = -EBADMSG; - goto out; - } - - if (data_len != root_hash.len + add_data.len) { - pr_debug("PKCS#7 data size doesn't match arguments.\n"); - err = -EKEYREJECTED; - goto out; - } - - p = data; - if (memcmp(p, root_hash.data, root_hash.len) != 0) { - pr_debug("Root hash mismatch.\n"); - err = -EKEYREJECTED; - goto out; - } - p += root_hash.len; - if (memcmp(p, add_data.data, add_data.len) != 0) { - pr_debug("Additional data mismatch.\n"); - err = -EKEYREJECTED; - goto out; - } - - err = pkcs7_verify(pkcs7, VERIFYING_UNSPECIFIED_SIGNATURE); - if (err) - pr_debug("PKCS#7 signature verification error: %d\n", -err); - - /* - * RSA signature verification sometimes returns unexpected error codes - * when signature doesn't match. - */ - if (err == -ERANGE || err == -EINVAL) - err = -EBADMSG; - -out: - pkcs7_free_message(pkcs7); - return err; -} - struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id) { static struct incfs_hash_alg sha256 = { @@ -113,11 +48,90 @@ struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id) return result; } +struct signature_info { + u32 version; + enum incfs_hash_tree_algorithm hash_algorithm; + u8 log2_blocksize; + struct mem_range salt; + struct mem_range root_hash; +}; + +static bool read_u32(u8 **p, u8 *top, u32 *result) +{ + if (*p + sizeof(u32) > top) + return false; + + *result = le32_to_cpu(*(__le32 *)*p); + *p += sizeof(u32); + return true; +} + +static bool read_u8(u8 **p, u8 *top, u8 *result) +{ + if (*p + sizeof(u8) > top) + return false; + + *result = *(u8 *)*p; + *p += sizeof(u8); + return true; +} + +static bool read_mem_range(u8 **p, u8 *top, struct mem_range *range) +{ + u32 len; + + if (!read_u32(p, top, &len) || *p + len > top) + return false; + + range->len = len; + range->data = *p; + *p += len; + return true; +} -struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, - int data_block_count, - struct mem_range root_hash) +static int incfs_parse_signature(struct mem_range signature, + struct signature_info *si) { + u8 *p = signature.data; + u8 *top = signature.data + signature.len; + u32 hash_section_size; + + if (signature.len > INCFS_MAX_SIGNATURE_SIZE) + return -EINVAL; + + if (!read_u32(&p, top, &si->version) || + si->version != INCFS_SIGNATURE_VERSION) + return -EINVAL; + + if (!read_u32(&p, top, &hash_section_size) || + p + hash_section_size > top) + return -EINVAL; + top = p + hash_section_size; + + if (!read_u32(&p, top, &si->hash_algorithm) || + si->hash_algorithm != INCFS_HASH_TREE_SHA256) + return -EINVAL; + + if (!read_u8(&p, top, &si->log2_blocksize) || si->log2_blocksize != 12) + return -EINVAL; + + if (!read_mem_range(&p, top, &si->salt)) + return -EINVAL; + + if (!read_mem_range(&p, top, &si->root_hash)) + return -EINVAL; + + if (p != top) + return -EINVAL; + + return 0; +} + +struct mtree *incfs_alloc_mtree(struct mem_range signature, + int data_block_count) +{ + int error; + struct signature_info si; struct mtree *result = NULL; struct incfs_hash_alg *hash_alg = NULL; int hash_per_block; @@ -129,11 +143,15 @@ struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, if (data_block_count <= 0) return ERR_PTR(-EINVAL); - hash_alg = incfs_get_hash_alg(id); + error = incfs_parse_signature(signature, &si); + if (error) + return ERR_PTR(error); + + hash_alg = incfs_get_hash_alg(si.hash_algorithm); if (IS_ERR(hash_alg)) return ERR_PTR(PTR_ERR(hash_alg)); - if (root_hash.len < hash_alg->digest_size) + if (si.root_hash.len < hash_alg->digest_size) return ERR_PTR(-EINVAL); result = kzalloc(sizeof(*result), GFP_NOFS); @@ -173,7 +191,7 @@ struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, } /* Root hash is stored separately from the rest of the tree. */ - memcpy(result->root_hash, root_hash.data, hash_alg->digest_size); + memcpy(result->root_hash, si.root_hash.data, hash_alg->digest_size); return result; err: @@ -198,16 +216,20 @@ int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data, return -EINVAL; desc->tfm = alg->shash; - return crypto_shash_digest(desc, data.data, data.len, digest.data); -} -void incfs_free_signature_info(struct signature_info *si) -{ - if (!si) - return; - kfree(si->root_hash.data); - kfree(si->additional_data.data); - kfree(si->signature.data); - kfree(si); + if (data.len < INCFS_DATA_FILE_BLOCK_SIZE) { + int err; + void *buf = kzalloc(INCFS_DATA_FILE_BLOCK_SIZE, GFP_NOFS); + + if (!buf) + return -ENOMEM; + + memcpy(buf, data.data, data.len); + err = crypto_shash_digest(desc, buf, INCFS_DATA_FILE_BLOCK_SIZE, + digest.data); + kfree(buf); + return err; + } + return crypto_shash_digest(desc, data.data, data.len, digest.data); } diff --git a/fs/incfs/integrity.h b/fs/incfs/integrity.h index da1c38486b2fee5a170094c52ddd7c0af4f89987..cf79b64da7367d13e45d5df713af47104b6cb05c 100644 --- a/fs/incfs/integrity.h +++ b/fs/incfs/integrity.h @@ -38,21 +38,10 @@ struct mtree { int depth; }; -struct signature_info { - struct mem_range root_hash; - - struct mem_range additional_data; - - struct mem_range signature; - - enum incfs_hash_tree_algorithm hash_alg; -}; - struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id); -struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, - int data_block_count, - struct mem_range root_hash); +struct mtree *incfs_alloc_mtree(struct mem_range signature, + int data_block_count); void incfs_free_mtree(struct mtree *tree); @@ -64,9 +53,4 @@ size_t incfs_get_mtree_hash_count(enum incfs_hash_tree_algorithm alg, int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data, struct mem_range digest); -int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, - struct mem_range root_hash, struct mem_range add_data); - -void incfs_free_signature_info(struct signature_info *si); - #endif /* _INCFS_INTEGRITY_H */ diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index e4790189abd3c1742f0199a47579433ca24fbf92..b5ec4edc3b7a42a0af1fb1a4d5f5a225a5f53dae 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -52,8 +52,6 @@ static int dir_rename(struct inode *old_dir, struct dentry *old_dentry, static int file_open(struct inode *inode, struct file *file); static int file_release(struct inode *inode, struct file *file); -static ssize_t file_write(struct file *f, const char __user *buf, - size_t size, loff_t *offset); static int read_single_page(struct file *f, struct page *page); static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg); @@ -73,8 +71,11 @@ static struct inode *alloc_inode(struct super_block *sb); static void free_inode(struct inode *inode); static void evict_inode(struct inode *inode); +static int incfs_setattr(struct dentry *dentry, struct iattr *ia); static ssize_t incfs_getxattr(struct dentry *d, const char *name, void *value, size_t size); +static ssize_t incfs_setxattr(struct dentry *d, const char *name, + const void *value, size_t size, int flags); static ssize_t incfs_listxattr(struct dentry *d, char *list, size_t size); static int show_options(struct seq_file *, struct dentry *); @@ -101,7 +102,8 @@ static const struct inode_operations incfs_dir_inode_ops = { .rename = dir_rename_wrap, .unlink = dir_unlink, .link = dir_link, - .rmdir = dir_rmdir + .rmdir = dir_rmdir, + .setattr = incfs_setattr, }; static const struct file_operations incfs_dir_fops = { @@ -127,7 +129,6 @@ static const struct address_space_operations incfs_address_space_ops = { static const struct file_operations incfs_file_ops = { .open = file_open, .release = file_release, - .write = file_write, .read_iter = generic_file_read_iter, .mmap = generic_file_mmap, .splice_read = generic_file_splice_read, @@ -136,6 +137,11 @@ static const struct file_operations incfs_file_ops = { .compat_ioctl = dispatch_ioctl }; +enum FILL_PERMISSION { + CANT_FILL = 0, + CAN_FILL = 1, +}; + static const struct file_operations incfs_pending_read_file_ops = { .read = pending_reads_read, .poll = pending_reads_poll, @@ -157,7 +163,7 @@ static const struct file_operations incfs_log_file_ops = { }; static const struct inode_operations incfs_file_inode_ops = { - .setattr = simple_setattr, + .setattr = incfs_setattr, .getattr = simple_getattr, .listxattr = incfs_listxattr }; @@ -169,9 +175,18 @@ static int incfs_handler_getxattr(const struct xattr_handler *xh, return incfs_getxattr(d, name, buffer, size); } +static int incfs_handler_setxattr(const struct xattr_handler *xh, + struct dentry *d, struct inode *inode, + const char *name, const void *buffer, + size_t size, int flags) +{ + return incfs_setxattr(d, name, buffer, size, flags); +} + static const struct xattr_handler incfs_xattr_handler = { .prefix = "", /* AKA all attributes */ .get = incfs_handler_getxattr, + .set = incfs_handler_setxattr, }; static const struct xattr_handler *incfs_xattr_ops[] = { @@ -194,6 +209,8 @@ struct inode_search { unsigned long ino; struct dentry *backing_dentry; + + size_t size; }; enum parse_parameter { @@ -336,8 +353,8 @@ static int inode_test(struct inode *inode, void *opaque) return (node->n_backing_inode == backing_inode) && inode->i_ino == search->ino; - } - return 1; + } else + return inode->i_ino == search->ino; } static int inode_set(struct inode *inode, void *opaque) @@ -350,16 +367,16 @@ static int inode_set(struct inode *inode, void *opaque) struct dentry *backing_dentry = search->backing_dentry; struct inode *backing_inode = d_inode(backing_dentry); - inode_init_owner(inode, NULL, backing_inode->i_mode); fsstack_copy_attr_all(inode, backing_inode); if (S_ISREG(inode->i_mode)) { - u64 size = read_size_attr(backing_dentry); + u64 size = search->size; inode->i_size = size; inode->i_blocks = get_blocks_count_for_size(size); inode->i_mapping->a_ops = &incfs_address_space_ops; inode->i_op = &incfs_file_inode_ops; inode->i_fop = &incfs_file_ops; + inode->i_mode &= ~0222; } else if (S_ISDIR(inode->i_mode)) { inode->i_size = 0; inode->i_blocks = 1; @@ -382,6 +399,7 @@ static int inode_set(struct inode *inode, void *opaque) pr_warn("incfs: ino conflict with backing FS %ld\n", backing_inode->i_ino); } + return 0; } else if (search->ino == INCFS_PENDING_READS_INODE) { /* It's an inode for .pending_reads pseudo file. */ @@ -427,7 +445,8 @@ static struct inode *fetch_regular_inode(struct super_block *sb, struct inode *backing_inode = d_inode(backing_dentry); struct inode_search search = { .ino = backing_inode->i_ino, - .backing_dentry = backing_dentry + .backing_dentry = backing_dentry, + .size = read_size_attr(backing_dentry), }; struct inode *inode = iget5_locked(sb, search.ino, inode_test, inode_set, &search); @@ -454,9 +473,6 @@ static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len, ssize_t result = 0; int i = 0; - if (!access_ok(VERIFY_WRITE, buf, len)) - return -EFAULT; - if (!incfs_fresh_pending_reads_exist(mi, last_known_read_sn)) return 0; @@ -574,22 +590,27 @@ static ssize_t log_read(struct file *f, char __user *buf, size_t len, { struct log_file_state *log_state = f->private_data; struct mount_info *mi = get_mount_info(file_superblock(f)); - struct incfs_pending_read_info *reads_buf = - (struct incfs_pending_read_info *)__get_free_page(GFP_NOFS); - size_t reads_to_collect = len / sizeof(*reads_buf); - size_t reads_per_page = PAGE_SIZE / sizeof(*reads_buf); int total_reads_collected = 0; + int rl_size; ssize_t result = 0; + struct incfs_pending_read_info *reads_buf; + ssize_t reads_to_collect = len / sizeof(*reads_buf); + ssize_t reads_per_page = PAGE_SIZE / sizeof(*reads_buf); + + rl_size = READ_ONCE(mi->mi_log.rl_size); + if (rl_size == 0) + return 0; + reads_buf = (struct incfs_pending_read_info *)__get_free_page(GFP_NOFS); if (!reads_buf) return -ENOMEM; - reads_to_collect = min_t(size_t, mi->mi_log.rl_size, reads_to_collect); + reads_to_collect = min_t(ssize_t, rl_size, reads_to_collect); while (reads_to_collect > 0) { struct read_log_state next_state = READ_ONCE(log_state->state); int reads_collected = incfs_collect_logged_reads( mi, &next_state, reads_buf, - min_t(size_t, reads_to_collect, reads_per_page)); + min_t(ssize_t, reads_to_collect, reads_per_page)); if (reads_collected <= 0) { result = total_reads_collected ? total_reads_collected * @@ -628,7 +649,7 @@ static __poll_t log_poll(struct file *file, poll_table *wait) __poll_t ret = 0; poll_wait(file, &mi->mi_log.ml_notif_wq, wait); - count = incfs_get_uncollected_logs_count(mi, log_state->state); + count = incfs_get_uncollected_logs_count(mi, &log_state->state); if (count >= mi->mi_options.read_log_wakeup_count) ret = EPOLLIN | EPOLLRDNORM; @@ -789,9 +810,6 @@ static int read_single_page(struct file *f, struct page *page) size = df->df_size; timeout_ms = df->df_mount_info->mi_options.read_timeout_ms; - pr_debug("incfs: %s %s %lld\n", __func__, - f->f_path.dentry->d_name.name, offset); - if (offset < size) { struct mem_range tmp = { .len = 2 * INCFS_DATA_FILE_BLOCK_SIZE @@ -800,7 +818,7 @@ static int read_single_page(struct file *f, struct page *page) tmp.data = (u8 *)__get_free_pages(GFP_NOFS, get_order(tmp.len)); bytes_to_read = min_t(loff_t, size - offset, PAGE_SIZE); read_result = incfs_read_data_file_block( - range(page_start, bytes_to_read), df, block_index, + range(page_start, bytes_to_read), f, block_index, timeout_ms, tmp); free_pages((unsigned long)tmp.data, get_order(tmp.len)); @@ -838,106 +856,39 @@ static char *file_id_to_str(incfs_uuid_t id) return result; } -static struct signature_info *incfs_copy_signature_info_from_user( - struct incfs_file_signature_info __user *original) +static struct mem_range incfs_copy_signature_info_from_user(u8 __user *original, + u64 size) { - struct incfs_file_signature_info usr_si; - struct signature_info *result; - int error; + u8 *result; if (!original) - return NULL; + return range(NULL, 0); - if (!access_ok(VERIFY_READ, original, sizeof(usr_si))) - return ERR_PTR(-EFAULT); + if (size > INCFS_MAX_SIGNATURE_SIZE) + return range(ERR_PTR(-EFAULT), 0); - if (copy_from_user(&usr_si, original, sizeof(usr_si)) > 0) - return ERR_PTR(-EFAULT); - - result = kzalloc(sizeof(*result), GFP_NOFS); + result = kzalloc(size, GFP_NOFS | __GFP_COMP); if (!result) - return ERR_PTR(-ENOMEM); - - result->hash_alg = usr_si.hash_tree_alg; - - if (result->hash_alg) { - void *p = kzalloc(INCFS_MAX_HASH_SIZE, GFP_NOFS); - - if (!p) { - error = -ENOMEM; - goto err; - } - - // TODO this sets the root_hash length to MAX_HASH_SIZE not - // the actual size. Fix, then set INCFS_MAX_HASH_SIZE back - // to 64 - result->root_hash = range(p, INCFS_MAX_HASH_SIZE); - if (copy_from_user(p, u64_to_user_ptr(usr_si.root_hash), - result->root_hash.len) > 0) { - error = -EFAULT; - goto err; - } - } - - if (usr_si.additional_data_size > INCFS_MAX_FILE_ATTR_SIZE) { - error = -E2BIG; - goto err; - } - - if (usr_si.additional_data && usr_si.additional_data_size) { - void *p = kzalloc(usr_si.additional_data_size, GFP_NOFS); - - if (!p) { - error = -ENOMEM; - goto err; - } - result->additional_data = range(p, - usr_si.additional_data_size); - if (copy_from_user(p, u64_to_user_ptr(usr_si.additional_data), - result->additional_data.len) > 0) { - error = -EFAULT; - goto err; - } - } + return range(ERR_PTR(-ENOMEM), 0); - if (usr_si.signature_size > INCFS_MAX_SIGNATURE_SIZE) { - error = -E2BIG; - goto err; + if (copy_from_user(result, original, size)) { + kfree(result); + return range(ERR_PTR(-EFAULT), 0); } - if (usr_si.signature && usr_si.signature_size) { - void *p = kzalloc(usr_si.signature_size, GFP_NOFS); - - if (!p) { - error = -ENOMEM; - goto err; - } - result->signature = range(p, usr_si.signature_size); - if (copy_from_user(p, u64_to_user_ptr(usr_si.signature), - result->signature.len) > 0) { - error = -EFAULT; - goto err; - } - } - - return result; - -err: - incfs_free_signature_info(result); - return ERR_PTR(-error); + return range(result, size); } static int init_new_file(struct mount_info *mi, struct dentry *dentry, - incfs_uuid_t *uuid, u64 size, struct mem_range attr, - struct incfs_file_signature_info __user *fsi) + incfs_uuid_t *uuid, u64 size, struct mem_range attr, + u8 __user *user_signature_info, u64 signature_size) { struct path path = {}; struct file *new_file; int error = 0; struct backing_file_context *bfc = NULL; u32 block_count; - struct mem_range mem_range = {NULL}; - struct signature_info *si = NULL; + struct mem_range raw_signature = { NULL }; struct mtree *hash_tree = NULL; if (!mi || !dentry || !uuid) @@ -948,7 +899,8 @@ static int init_new_file(struct mount_info *mi, struct dentry *dentry, .mnt = mi->mi_backing_dir_path.mnt, .dentry = dentry }; - new_file = dentry_open(&path, O_RDWR | O_NOATIME, mi->mi_owner); + new_file = dentry_open(&path, O_RDWR | O_NOATIME | O_LARGEFILE, + mi->mi_owner); if (IS_ERR(new_file)) { error = PTR_ERR(new_file); @@ -956,6 +908,7 @@ static int init_new_file(struct mount_info *mi, struct dentry *dentry, } bfc = incfs_alloc_bfc(new_file); + fput(new_file); if (IS_ERR(bfc)) { error = PTR_ERR(bfc); bfc = NULL; @@ -967,19 +920,6 @@ static int init_new_file(struct mount_info *mi, struct dentry *dentry, if (error) goto out; - block_count = (u32)get_blocks_count_for_size(size); - error = incfs_write_blockmap_to_backing_file(bfc, block_count, NULL); - if (error) - goto out; - - /* This fill has data, reserve space for the block map. */ - if (block_count > 0) { - error = incfs_write_blockmap_to_backing_file( - bfc, block_count, NULL); - if (error) - goto out; - } - if (attr.data && attr.len) { error = incfs_write_file_attr_to_backing_file(bfc, attr, NULL); @@ -987,53 +927,46 @@ static int init_new_file(struct mount_info *mi, struct dentry *dentry, goto out; } - if (fsi) { - si = incfs_copy_signature_info_from_user(fsi); + block_count = (u32)get_blocks_count_for_size(size); - if (IS_ERR(si)) { - error = PTR_ERR(si); - si = NULL; + if (user_signature_info) { + raw_signature = incfs_copy_signature_info_from_user( + user_signature_info, signature_size); + + if (IS_ERR(raw_signature.data)) { + error = PTR_ERR(raw_signature.data); + raw_signature.data = NULL; goto out; } - if (si->hash_alg) { - hash_tree = incfs_alloc_mtree(si->hash_alg, block_count, - si->root_hash); - if (IS_ERR(hash_tree)) { - error = PTR_ERR(hash_tree); - hash_tree = NULL; - goto out; - } - - // TODO This code seems wrong when len is zero - we - // should error out?? - if (si->signature.len > 0) - error = incfs_validate_pkcs7_signature( - si->signature, - si->root_hash, - si->additional_data); - if (error) - goto out; + hash_tree = incfs_alloc_mtree(raw_signature, block_count); + if (IS_ERR(hash_tree)) { + error = PTR_ERR(hash_tree); + hash_tree = NULL; + goto out; + } - error = incfs_write_signature_to_backing_file(bfc, - si->hash_alg, - hash_tree->hash_tree_area_size, - si->root_hash, si->additional_data, - si->signature); + error = incfs_write_signature_to_backing_file( + bfc, raw_signature, hash_tree->hash_tree_area_size); + if (error) + goto out; - if (error) - goto out; - } + block_count += get_blocks_count_for_size( + hash_tree->hash_tree_area_size); } + if (block_count) + error = incfs_write_blockmap_to_backing_file(bfc, block_count); + + if (error) + goto out; out: if (bfc) { mutex_unlock(&bfc->bc_mutex); incfs_free_bfc(bfc); } incfs_free_mtree(hash_tree); - incfs_free_signature_info(si); - kfree(mem_range.data); + kfree(raw_signature.data); if (error) pr_debug("incfs: %s error: %d\n", __func__, error); @@ -1114,8 +1047,6 @@ static int dir_relative_path_resolve( LOOKUP_FOLLOW | LOOKUP_DIRECTORY, result_path, NULL); out: - // TODO sys_close should be replaced with ksys_close on later kernel - // Add to compat or some such? sys_close(dir_fd); if (error) pr_debug("incfs: %s %d\n", __func__, error); @@ -1140,6 +1071,27 @@ static int validate_name(char *file_name) return 0; } +static int chmod(struct dentry *dentry, umode_t mode) +{ + struct inode *inode = dentry->d_inode; + struct inode *delegated_inode = NULL; + struct iattr newattrs; + int error; + +retry_deleg: + inode_lock(inode); + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; + error = notify_change(dentry, &newattrs, &delegated_inode); + inode_unlock(inode); + if (delegated_inode) { + error = break_deleg_wait(&delegated_inode); + if (!error) + goto retry_deleg; + } + return error; +} + static long ioctl_create_file(struct mount_info *mi, struct incfs_new_file_args __user *usr_args) { @@ -1159,10 +1111,7 @@ static long ioctl_create_file(struct mount_info *mi, error = -EFAULT; goto out; } - if (!access_ok(VERIFY_READ, usr_args, sizeof(args))) { - error = -EFAULT; - goto out; - } + if (copy_from_user(&args, usr_args, sizeof(args)) > 0) { error = -EFAULT; goto out; @@ -1240,8 +1189,8 @@ static long ioctl_create_file(struct mount_info *mi, /* Creating a file in the .index dir. */ index_dir_inode = d_inode(mi->mi_index_dir); inode_lock_nested(index_dir_inode, I_MUTEX_PARENT); - error = vfs_create(index_dir_inode, index_file_dentry, - args.mode, true); + error = vfs_create(index_dir_inode, index_file_dentry, args.mode | 0222, + true); inode_unlock(index_dir_inode); if (error) @@ -1251,6 +1200,12 @@ static long ioctl_create_file(struct mount_info *mi, goto out; } + error = chmod(index_file_dentry, args.mode | 0222); + if (error) { + pr_debug("incfs: chmod err: %d\n", error); + goto delete_index_file; + } + /* Save the file's ID as an xattr for easy fetching in future. */ error = vfs_setxattr(index_file_dentry, INCFS_XATTR_ID_NAME, file_id_str, strlen(file_id_str), XATTR_CREATE); @@ -1269,7 +1224,7 @@ static long ioctl_create_file(struct mount_info *mi, goto delete_index_file; } - /* Save the file's attrubute as an xattr */ + /* Save the file's attribute as an xattr */ if (args.file_attr_len && args.file_attr) { if (args.file_attr_len > INCFS_MAX_FILE_ATTR_SIZE) { error = -E2BIG; @@ -1282,12 +1237,6 @@ static long ioctl_create_file(struct mount_info *mi, goto delete_index_file; } - if (!access_ok(VERIFY_READ, u64_to_user_ptr(args.file_attr), - args.file_attr_len)) { - error = -EFAULT; - goto delete_index_file; - } - if (copy_from_user(attr_value, u64_to_user_ptr(args.file_attr), args.file_attr_len) > 0) { @@ -1306,9 +1255,9 @@ static long ioctl_create_file(struct mount_info *mi, /* Initializing a newly created file. */ error = init_new_file(mi, index_file_dentry, &args.file_id, args.size, - range(attr_value, args.file_attr_len), - (struct incfs_file_signature_info __user *) - args.signature_info); + range(attr_value, args.file_attr_len), + (u8 __user *)args.signature_info, + args.signature_size); if (error) goto delete_index_file; @@ -1336,6 +1285,123 @@ static long ioctl_create_file(struct mount_info *mi, return error; } +static long ioctl_fill_blocks(struct file *f, void __user *arg) +{ + struct incfs_fill_blocks __user *usr_fill_blocks = arg; + struct incfs_fill_blocks fill_blocks; + struct incfs_fill_block __user *usr_fill_block_array; + struct data_file *df = get_incfs_data_file(f); + const ssize_t data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE; + u8 *data_buf = NULL; + ssize_t error = 0; + int i = 0; + + if (!df) + return -EBADF; + + if ((uintptr_t)f->private_data != CAN_FILL) + return -EPERM; + + if (copy_from_user(&fill_blocks, usr_fill_blocks, sizeof(fill_blocks))) + return -EFAULT; + + usr_fill_block_array = u64_to_user_ptr(fill_blocks.fill_blocks); + data_buf = (u8 *)__get_free_pages(GFP_NOFS | __GFP_COMP, + get_order(data_buf_size)); + if (!data_buf) + return -ENOMEM; + + for (i = 0; i < fill_blocks.count; i++) { + struct incfs_fill_block fill_block = {}; + + if (copy_from_user(&fill_block, &usr_fill_block_array[i], + sizeof(fill_block)) > 0) { + error = -EFAULT; + break; + } + + if (fill_block.data_len > data_buf_size) { + error = -E2BIG; + break; + } + + if (copy_from_user(data_buf, u64_to_user_ptr(fill_block.data), + fill_block.data_len) > 0) { + error = -EFAULT; + break; + } + fill_block.data = 0; /* To make sure nobody uses it. */ + if (fill_block.flags & INCFS_BLOCK_FLAGS_HASH) { + error = incfs_process_new_hash_block(df, &fill_block, + data_buf); + } else { + error = incfs_process_new_data_block(df, &fill_block, + data_buf); + } + if (error) + break; + } + + if (data_buf) + free_pages((unsigned long)data_buf, get_order(data_buf_size)); + + /* + * Only report the error if no records were processed, otherwise + * just return how many were processed successfully. + */ + if (i == 0) + return error; + + return i; +} + +static long ioctl_permit_fill(struct file *f, void __user *arg) +{ + struct incfs_permit_fill __user *usr_permit_fill = arg; + struct incfs_permit_fill permit_fill; + long error = 0; + struct file *file = NULL; + + if (f->f_op != &incfs_pending_read_file_ops) + return -EPERM; + + if (copy_from_user(&permit_fill, usr_permit_fill, sizeof(permit_fill))) + return -EFAULT; + + file = fget(permit_fill.file_descriptor); + if (IS_ERR(file)) + return PTR_ERR(file); + + if (file->f_op != &incfs_file_ops) { + error = -EPERM; + goto out; + } + + if (file->f_inode->i_sb != f->f_inode->i_sb) { + error = -EPERM; + goto out; + } + + switch ((uintptr_t)file->private_data) { + case CANT_FILL: + file->private_data = (void *)CAN_FILL; + break; + + case CAN_FILL: + pr_debug("CAN_FILL already set"); + break; + + default: + pr_warn("Invalid file private data"); + error = -EFAULT; + goto out; + } + +out: + fput(file); + return error; +} + static long ioctl_read_file_signature(struct file *f, void __user *arg) { struct incfs_get_file_sig_args __user *args_usr_ptr = arg; @@ -1349,20 +1415,14 @@ static long ioctl_read_file_signature(struct file *f, void __user *arg) if (!df) return -EINVAL; - if (!access_ok(VERIFY_READ, args_usr_ptr, sizeof(args))) - return -EFAULT; if (copy_from_user(&args, args_usr_ptr, sizeof(args)) > 0) return -EINVAL; - if (!access_ok(VERIFY_WRITE, u64_to_user_ptr(args.file_signature), - args.file_signature_buf_size)) - return -EFAULT; - sig_buf_size = args.file_signature_buf_size; if (sig_buf_size > INCFS_MAX_SIGNATURE_SIZE) return -E2BIG; - sig_buffer = kzalloc(sig_buf_size, GFP_NOFS); + sig_buffer = kzalloc(sig_buf_size, GFP_NOFS | __GFP_COMP); if (!sig_buffer) return -ENOMEM; @@ -1390,6 +1450,30 @@ static long ioctl_read_file_signature(struct file *f, void __user *arg) return error; } +static long ioctl_get_filled_blocks(struct file *f, void __user *arg) +{ + struct incfs_get_filled_blocks_args __user *args_usr_ptr = arg; + struct incfs_get_filled_blocks_args args = {}; + struct data_file *df = get_incfs_data_file(f); + int error; + + if (!df) + return -EINVAL; + + if ((uintptr_t)f->private_data != CAN_FILL) + return -EPERM; + + if (copy_from_user(&args, args_usr_ptr, sizeof(args)) > 0) + return -EINVAL; + + error = incfs_get_filled_blocks(df, &args); + + if (copy_to_user(args_usr_ptr, &args, sizeof(args))) + return -EFAULT; + + return error; +} + static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg) { struct mount_info *mi = get_mount_info(file_superblock(f)); @@ -1397,8 +1481,14 @@ static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg) switch (req) { case INCFS_IOC_CREATE_FILE: return ioctl_create_file(mi, (void __user *)arg); + case INCFS_IOC_FILL_BLOCKS: + return ioctl_fill_blocks(f, (void __user *)arg); + case INCFS_IOC_PERMIT_FILL: + return ioctl_permit_fill(f, (void __user *)arg); case INCFS_IOC_READ_FILE_SIGNATURE: return ioctl_read_file_signature(f, (void __user *)arg); + case INCFS_IOC_GET_FILLED_BLOCKS: + return ioctl_get_filled_blocks(f, (void __user *)arg); default: return -EINVAL; } @@ -1457,6 +1547,7 @@ static struct dentry *dir_lookup(struct inode *dir_inode, struct dentry *dentry, err = IS_ERR(backing_dentry) ? PTR_ERR(backing_dentry) : -EFAULT; + backing_dentry = NULL; goto out; } else { struct inode *inode = NULL; @@ -1540,7 +1631,7 @@ static int dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) } inode_lock_nested(dir_node->n_backing_inode, I_MUTEX_PARENT); - err = vfs_mkdir(dir_node->n_backing_inode, backing_dentry, mode); + err = vfs_mkdir(dir_node->n_backing_inode, backing_dentry, mode | 0222); inode_unlock(dir_node->n_backing_inode); if (!err) { struct inode *inode = NULL; @@ -1604,6 +1695,7 @@ static int final_file_delete(struct mount_info *mi, if (d_really_is_positive(index_file_dentry)) error = incfs_unlink(index_file_dentry); out: + dput(index_file_dentry); if (error) pr_debug("incfs: delete_file_from_index err:%d\n", error); return error; @@ -1816,8 +1908,8 @@ static int file_open(struct inode *inode, struct file *file) int err = 0; get_incfs_backing_path(file->f_path.dentry, &backing_path); - backing_file = dentry_open(&backing_path, O_RDWR | O_NOATIME, - mi->mi_owner); + backing_file = dentry_open( + &backing_path, O_RDWR | O_NOATIME | O_LARGEFILE, mi->mi_owner); path_put(&backing_path); if (IS_ERR(backing_file)) { @@ -1826,9 +1918,10 @@ static int file_open(struct inode *inode, struct file *file) goto out; } - if (S_ISREG(inode->i_mode)) + if (S_ISREG(inode->i_mode)) { err = make_inode_ready_for_data_ops(mi, inode, backing_file); - else if (S_ISDIR(inode->i_mode)) { + file->private_data = (void *)CANT_FILL; + } else if (S_ISDIR(inode->i_mode)) { struct dir_file *dir = NULL; dir = incfs_open_dir_file(mi, backing_file); @@ -1863,77 +1956,6 @@ static int file_release(struct inode *inode, struct file *file) return 0; } -static ssize_t file_write(struct file *f, const char __user *buf, - size_t size, loff_t *offset) -{ - struct data_file *df = get_incfs_data_file(f); - const ssize_t data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE; - size_t block_count = size / sizeof(struct incfs_new_data_block); - struct incfs_new_data_block __user *usr_blocks = - (struct incfs_new_data_block __user *)buf; - u8 *data_buf = NULL; - ssize_t error = 0; - int i = 0; - - if (!df) - return -EBADF; - - if (!access_ok(VERIFY_READ, usr_blocks, size)) - return -EFAULT; - - data_buf = (u8 *)__get_free_pages(GFP_NOFS, get_order(data_buf_size)); - if (!data_buf) - return -ENOMEM; - - for (i = 0; i < block_count; i++) { - struct incfs_new_data_block block = {}; - - if (copy_from_user(&block, &usr_blocks[i], sizeof(block)) > 0) { - error = -EFAULT; - break; - } - - if (block.data_len > data_buf_size) { - error = -E2BIG; - break; - } - if (!access_ok(VERIFY_READ, u64_to_user_ptr(block.data), - block.data_len)) { - error = -EFAULT; - break; - } - if (copy_from_user(data_buf, u64_to_user_ptr(block.data), - block.data_len) > 0) { - error = -EFAULT; - break; - } - block.data = 0; /* To make sure nobody uses it. */ - if (block.flags & INCFS_BLOCK_FLAGS_HASH) { - error = incfs_process_new_hash_block(df, &block, - data_buf); - } else { - error = incfs_process_new_data_block(df, &block, - data_buf); - } - if (error) - break; - } - - if (data_buf) - free_pages((unsigned long)data_buf, get_order(data_buf_size)); - *offset = 0; - - /* - * Only report the error if no records were processed, otherwise - * just return how many were processed successfully. - */ - if (i == 0) - return error; - - return i * sizeof(struct incfs_new_data_block); -} - - static int dentry_revalidate(struct dentry *d, unsigned int flags) { struct path backing_path = {}; @@ -1976,6 +1998,7 @@ static void dentry_release(struct dentry *d) if (di) path_put(&di->backing_path); + kfree(d->d_fsdata); d->d_fsdata = NULL; } @@ -2016,15 +2039,117 @@ static void evict_inode(struct inode *inode) clear_inode(inode); } +static int incfs_setattr(struct dentry *dentry, struct iattr *ia) +{ + struct dentry_info *di = get_incfs_dentry(dentry); + struct dentry *backing_dentry; + struct inode *backing_inode; + int error; + + if (ia->ia_valid & ATTR_SIZE) + return -EINVAL; + + if (!di) + return -EINVAL; + backing_dentry = di->backing_path.dentry; + if (!backing_dentry) + return -EINVAL; + + backing_inode = d_inode(backing_dentry); + + /* incfs files are readonly, but the backing files must be writeable */ + if (S_ISREG(backing_inode->i_mode)) { + if ((ia->ia_valid & ATTR_MODE) && (ia->ia_mode & 0222)) + return -EINVAL; + + ia->ia_mode |= 0222; + } + + inode_lock(d_inode(backing_dentry)); + error = notify_change(backing_dentry, ia, NULL); + inode_unlock(d_inode(backing_dentry)); + + if (error) + return error; + + if (S_ISREG(backing_inode->i_mode)) + ia->ia_mode &= ~0222; + + return simple_setattr(dentry, ia); +} + static ssize_t incfs_getxattr(struct dentry *d, const char *name, void *value, size_t size) { struct dentry_info *di = get_incfs_dentry(d); + struct mount_info *mi = get_mount_info(d->d_sb); + char *stored_value; + size_t stored_size; - if (!di || !di->backing_path.dentry) + if (di && di->backing_path.dentry) + return vfs_getxattr(di->backing_path.dentry, name, value, size); + + if (strcmp(name, "security.selinux")) + return -ENODATA; + + if (!strcmp(d->d_iname, INCFS_PENDING_READS_FILENAME)) { + stored_value = mi->pending_read_xattr; + stored_size = mi->pending_read_xattr_size; + } else if (!strcmp(d->d_iname, INCFS_LOG_FILENAME)) { + stored_value = mi->log_xattr; + stored_size = mi->log_xattr_size; + } else { + return -ENODATA; + } + + if (!stored_value) + return -ENODATA; + + if (stored_size > size) + return -E2BIG; + + memcpy(value, stored_value, stored_size); + return stored_size; + +} + + +static ssize_t incfs_setxattr(struct dentry *d, const char *name, + const void *value, size_t size, int flags) +{ + struct dentry_info *di = get_incfs_dentry(d); + struct mount_info *mi = get_mount_info(d->d_sb); + void **stored_value; + size_t *stored_size; + + if (di && di->backing_path.dentry) + return vfs_setxattr(di->backing_path.dentry, name, value, size, + flags); + + if (strcmp(name, "security.selinux")) + return -ENODATA; + + if (size > INCFS_MAX_FILE_ATTR_SIZE) + return -E2BIG; + + if (!strcmp(d->d_iname, INCFS_PENDING_READS_FILENAME)) { + stored_value = &mi->pending_read_xattr; + stored_size = &mi->pending_read_xattr_size; + } else if (!strcmp(d->d_iname, INCFS_LOG_FILENAME)) { + stored_value = &mi->log_xattr; + stored_size = &mi->log_xattr_size; + } else { return -ENODATA; + } + + kfree (*stored_value); + *stored_value = kzalloc(size, GFP_NOFS); + if (!*stored_value) + return -ENOMEM; - return vfs_getxattr(di->backing_path.dentry, name, value, size); + memcpy(*stored_value, value, size); + *stored_size = size; + return 0; } static ssize_t incfs_listxattr(struct dentry *d, char *list, size_t size) @@ -2124,7 +2249,7 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, path_put(&backing_dir_path); sb->s_flags |= SB_ACTIVE; - pr_debug("infs: mount\n"); + pr_debug("incfs: mount\n"); return dget(sb->s_root); err: sb->s_fs_info = NULL; @@ -2145,12 +2270,11 @@ static int incfs_remount_fs(struct super_block *sb, int *flags, char *data) if (err) return err; - if (mi->mi_options.read_timeout_ms != options.read_timeout_ms) { - mi->mi_options.read_timeout_ms = options.read_timeout_ms; - pr_debug("incfs: new timeout_ms=%d", options.read_timeout_ms); - } + err = incfs_realloc_mount_info(mi, &options); + if (err) + return err; - pr_debug("infs: remount\n"); + pr_debug("incfs: remount\n"); return 0; } @@ -2158,7 +2282,7 @@ void incfs_kill_sb(struct super_block *sb) { struct mount_info *mi = sb->s_fs_info; - pr_debug("infs: unmount\n"); + pr_debug("incfs: unmount\n"); incfs_free_mount_info(mi); generic_shutdown_super(sb); } diff --git a/fs/inode.c b/fs/inode.c index c7e140686a348f6c813e59d82714a65e56f3110a..8c25e0df7a0e3332a1289b9c1932e6eb2bc75f50 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -135,6 +136,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) inode->i_sb = sb; inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; + atomic64_set(&inode->i_sequence, 0); atomic_set(&inode->i_count, 1); inode->i_op = &empty_iops; inode->i_fop = &no_open_fops; @@ -2165,7 +2167,7 @@ int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags, !capable(CAP_LINUX_IMMUTABLE)) return -EPERM; - return 0; + return fscrypt_prepare_setflags(inode, oldflags, flags); } EXPORT_SYMBOL(vfs_ioc_setflags_prepare); diff --git a/fs/iomap.c b/fs/iomap.c index 3f5b1655cfce48c05d6f9978b3cb38c26cd12906..1e573a59ea71add536449185a0a023cdfc64b635 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -825,10 +826,13 @@ static blk_qc_t iomap_dio_zero(struct iomap_dio *dio, struct iomap *iomap, loff_t pos, unsigned len) { + struct inode *inode = file_inode(dio->iocb->ki_filp); struct page *page = ZERO_PAGE(0); struct bio *bio; bio = bio_alloc(GFP_KERNEL, 1); + fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits, + GFP_KERNEL); bio_set_dev(bio, iomap->bdev); bio->bi_iter.bi_sector = iomap->blkno + ((pos - iomap->offset) >> 9); @@ -908,6 +912,8 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, return 0; bio = bio_alloc(GFP_KERNEL, nr_pages); + fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits, + GFP_KERNEL); bio_set_dev(bio, iomap->bdev); bio->bi_iter.bi_sector = iomap->blkno + ((pos - iomap->offset) >> 9); diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index fe4fe155b7fbe9e2ca6bf923f17d387a6c4f8a25..15d129b7494b0e6861f5ef0242c0a18365a1aa1b 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -168,7 +168,7 @@ void __jbd2_log_wait_for_space(journal_t *journal) "journal space in %s\n", __func__, journal->j_devname); WARN_ON(1); - jbd2_journal_abort(journal, 0); + jbd2_journal_abort(journal, -EIO); } write_lock(&journal->j_state_lock); } else { diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 7dd61339259215927d047204390bebeeab5f52ab..6870103a0f59cfdcc6f649ba910fe1767e89f42c 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -783,7 +783,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) err = journal_submit_commit_record(journal, commit_transaction, &cbh, crc32_sum); if (err) - __jbd2_journal_abort_hard(journal); + jbd2_journal_abort(journal, err); } blk_finish_plug(&plug); @@ -876,7 +876,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) err = journal_submit_commit_record(journal, commit_transaction, &cbh, crc32_sum); if (err) - __jbd2_journal_abort_hard(journal); + jbd2_journal_abort(journal, err); } if (cbh) err = journal_wait_on_commit_record(journal, cbh); @@ -973,29 +973,34 @@ void jbd2_journal_commit_transaction(journal_t *journal) * it. */ /* - * A buffer which has been freed while still being journaled by - * a previous transaction. - */ - if (buffer_freed(bh)) { + * A buffer which has been freed while still being journaled + * by a previous transaction, refile the buffer to BJ_Forget of + * the running transaction. If the just committed transaction + * contains "add to orphan" operation, we can completely + * invalidate the buffer now. We are rather through in that + * since the buffer may be still accessible when blocksize < + * pagesize and it is attached to the last partial page. + */ + if (buffer_freed(bh) && !jh->b_next_transaction) { + struct address_space *mapping; + + clear_buffer_freed(bh); + clear_buffer_jbddirty(bh); + /* - * If the running transaction is the one containing - * "add to orphan" operation (b_next_transaction != - * NULL), we have to wait for that transaction to - * commit before we can really get rid of the buffer. - * So just clear b_modified to not confuse transaction - * credit accounting and refile the buffer to - * BJ_Forget of the running transaction. If the just - * committed transaction contains "add to orphan" - * operation, we can completely invalidate the buffer - * now. We are rather through in that since the - * buffer may be still accessible when blocksize < - * pagesize and it is attached to the last partial - * page. + * Block device buffers need to stay mapped all the + * time, so it is enough to clear buffer_jbddirty and + * buffer_freed bits. For the file mapping buffers (i.e. + * journalled data) we need to unmap buffer and clear + * more bits. We also need to be careful about the check + * because the data page mapping can get cleared under + * our hands. Note that if mapping == NULL, we don't + * need to make buffer unmapped because the page is + * already detached from the mapping and buffers cannot + * get reused. */ - jh->b_modified = 0; - if (!jh->b_next_transaction) { - clear_buffer_freed(bh); - clear_buffer_jbddirty(bh); + mapping = READ_ONCE(bh->b_page->mapping); + if (mapping && !sb_is_blkdev_sb(mapping->host->i_sb)) { clear_buffer_mapped(bh); clear_buffer_new(bh); clear_buffer_req(bh); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index d3cce5c86fd905622b97d606bd311db82980d8b3..6e054b368b5feb2bf01509390bdaec1b42aa3eeb 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1687,6 +1687,11 @@ int jbd2_journal_load(journal_t *journal) journal->j_devname); return -EFSCORRUPTED; } + /* + * clear JBD2_ABORT flag initialized in journal_init_common + * here to update log tail information with the newest seq. + */ + journal->j_flags &= ~JBD2_ABORT; /* OK, we've finished with the dynamic journal bits: * reinitialise the dynamic contents of the superblock in memory @@ -1694,7 +1699,6 @@ int jbd2_journal_load(journal_t *journal) if (journal_reset(journal)) goto recovery_error; - journal->j_flags &= ~JBD2_ABORT; journal->j_flags |= JBD2_LOADED; return 0; @@ -2115,8 +2119,7 @@ static void __journal_abort_soft (journal_t *journal, int errno) if (journal->j_flags & JBD2_ABORT) { write_unlock(&journal->j_state_lock); - if (!old_errno && old_errno != -ESHUTDOWN && - errno == -ESHUTDOWN) + if (old_errno != -ESHUTDOWN && errno == -ESHUTDOWN) jbd2_journal_update_sb_errno(journal); return; } @@ -2124,12 +2127,10 @@ static void __journal_abort_soft (journal_t *journal, int errno) __jbd2_journal_abort_hard(journal); - if (errno) { - jbd2_journal_update_sb_errno(journal); - write_lock(&journal->j_state_lock); - journal->j_flags |= JBD2_REC_ERR; - write_unlock(&journal->j_state_lock); - } + jbd2_journal_update_sb_errno(journal); + write_lock(&journal->j_state_lock); + journal->j_flags |= JBD2_REC_ERR; + write_unlock(&journal->j_state_lock); } /** @@ -2171,11 +2172,6 @@ static void __journal_abort_soft (journal_t *journal, int errno) * failure to disk. ext3_error, for example, now uses this * functionality. * - * Errors which originate from within the journaling layer will NOT - * supply an errno; a null errno implies that absolutely no further - * writes are done to the journal (unless there are any already in - * progress). - * */ void jbd2_journal_abort(journal_t *journal, int errno) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 7fe422eced89ba3c3dc1ea818566083b918708d5..a355ca418e788b8655897f3b51246b9c182ee9cf 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1050,8 +1050,8 @@ static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh, /* For undo access buffer must have data copied */ if (undo && !jh->b_committed_data) goto out; - if (jh->b_transaction != handle->h_transaction && - jh->b_next_transaction != handle->h_transaction) + if (READ_ONCE(jh->b_transaction) != handle->h_transaction && + READ_ONCE(jh->b_next_transaction) != handle->h_transaction) goto out; /* * There are two reasons for the barrier here: @@ -2231,14 +2231,16 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, return -EBUSY; } /* - * OK, buffer won't be reachable after truncate. We just set - * j_next_transaction to the running transaction (if there is - * one) and mark buffer as freed so that commit code knows it - * should clear dirty bits when it is done with the buffer. + * OK, buffer won't be reachable after truncate. We just clear + * b_modified to not confuse transaction credit accounting, and + * set j_next_transaction to the running transaction (if there + * is one) and mark buffer as freed so that commit code knows + * it should clear dirty bits when it is done with the buffer. */ set_buffer_freed(bh); if (journal->j_running_transaction && buffer_jbddirty(bh)) jh->b_next_transaction = journal->j_running_transaction; + jh->b_modified = 0; jbd2_journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); @@ -2464,8 +2466,8 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh) * our jh reference and thus __jbd2_journal_file_buffer() must not * take a new one. */ - jh->b_transaction = jh->b_next_transaction; - jh->b_next_transaction = NULL; + WRITE_ONCE(jh->b_transaction, jh->b_next_transaction); + WRITE_ONCE(jh->b_next_transaction, NULL); if (buffer_freed(bh)) jlist = BJ_Forget; else if (jh->b_modified) diff --git a/fs/libfs.c b/fs/libfs.c index 49623301e5f0b9a3d7756629b71dd7aa4746990b..4f2ac9ac0c9a8dccf613e4cb7c8a5e8429f2492a 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -16,6 +16,8 @@ #include #include #include /* sync_mapping_buffers */ +#include +#include #include @@ -802,7 +804,7 @@ int simple_attr_open(struct inode *inode, struct file *file, { struct simple_attr *attr; - attr = kmalloc(sizeof(*attr), GFP_KERNEL); + attr = kzalloc(sizeof(*attr), GFP_KERNEL); if (!attr) return -ENOMEM; @@ -842,9 +844,11 @@ ssize_t simple_attr_read(struct file *file, char __user *buf, if (ret) return ret; - if (*ppos) { /* continued read */ + if (*ppos && attr->get_buf[0]) { + /* continued read */ size = strlen(attr->get_buf); - } else { /* first read */ + } else { + /* first read */ u64 val; ret = attr->get(attr->data, &val); if (ret) @@ -1219,3 +1223,112 @@ bool is_empty_dir_inode(struct inode *inode) return (inode->i_fop == &empty_dir_operations) && (inode->i_op == &empty_dir_inode_operations); } + +#ifdef CONFIG_UNICODE +bool needs_casefold(const struct inode *dir) +{ + return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding && + (!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir)); +} +EXPORT_SYMBOL(needs_casefold); + +int generic_ci_d_compare(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name) +{ + const struct dentry *parent = READ_ONCE(dentry->d_parent); + const struct inode *inode = READ_ONCE(parent->d_inode); + const struct super_block *sb = dentry->d_sb; + const struct unicode_map *um = sb->s_encoding; + struct qstr entry = QSTR_INIT(str, len); + int ret; + + if (!inode || !needs_casefold(inode)) + goto fallback; + + ret = utf8_strncasecmp(um, name, &entry); + if (ret >= 0) + return ret; + + if (sb_has_enc_strict_mode(sb)) + return -EINVAL; +fallback: + if (len != name->len) + return 1; + return !!memcmp(str, name->name, len); +} +EXPORT_SYMBOL(generic_ci_d_compare); + +int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str) +{ + const struct inode *inode = READ_ONCE(dentry->d_inode); + struct super_block *sb = dentry->d_sb; + const struct unicode_map *um = sb->s_encoding; + int ret = 0; + + if (!inode || !needs_casefold(inode)) + return 0; + + ret = utf8_casefold_hash(um, dentry, str); + if (ret < 0) + goto err; + + return 0; +err: + if (sb_has_enc_strict_mode(sb)) + ret = -EINVAL; + else + ret = 0; + return ret; +} +EXPORT_SYMBOL(generic_ci_d_hash); + +static const struct dentry_operations generic_ci_dentry_ops = { + .d_hash = generic_ci_d_hash, + .d_compare = generic_ci_d_compare, +}; +#endif + +#ifdef CONFIG_FS_ENCRYPTION +static const struct dentry_operations generic_encrypted_dentry_ops = { + .d_revalidate = fscrypt_d_revalidate, +}; +#endif + +#if IS_ENABLED(CONFIG_UNICODE) && IS_ENABLED(CONFIG_FS_ENCRYPTION) +static const struct dentry_operations generic_encrypted_ci_dentry_ops = { + .d_hash = generic_ci_d_hash, + .d_compare = generic_ci_d_compare, + .d_revalidate = fscrypt_d_revalidate, +}; +#endif + +/** + * generic_set_encrypted_ci_d_ops - helper for setting d_ops for given dentry + * @dir: parent of dentry whose ops to set + * @dentry: detnry to set ops on + * + * This function sets the dentry ops for the given dentry to handle both + * casefolding and encryption of the dentry name. + */ +void generic_set_encrypted_ci_d_ops(struct inode *dir, struct dentry *dentry) +{ +#ifdef CONFIG_FS_ENCRYPTION + if (dentry->d_flags & DCACHE_ENCRYPTED_NAME) { +#ifdef CONFIG_UNICODE + if (dir->i_sb->s_encoding) { + d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops); + return; + } +#endif + d_set_d_op(dentry, &generic_encrypted_dentry_ops); + return; + } +#endif +#ifdef CONFIG_UNICODE + if (dir->i_sb->s_encoding) { + d_set_d_op(dentry, &generic_ci_dentry_ops); + return; + } +#endif +} +EXPORT_SYMBOL(generic_set_encrypted_ci_d_ops); diff --git a/fs/namei.c b/fs/namei.c index 7c876d8734ea9abfc7662e9ef61aadc755b8468a..1c626f56d21df71b3afeade1b69519964358e186 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1481,7 +1481,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) nd->path.dentry = parent; nd->seq = seq; if (unlikely(!path_connected(&nd->path))) - return -ENOENT; + return -ECHILD; break; } else { struct mount *mnt = real_mount(nd->path.mnt); @@ -3039,11 +3039,6 @@ int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, if (error) return error; error = dir->i_op->create(dir, dentry, mode, want_excl); - if (error) - return error; - error = security_inode_post_create(dir, dentry, mode); - if (error) - return error; if (!error) fsnotify_create(dir, dentry); return error; @@ -3876,11 +3871,6 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u return error; error = dir->i_op->mknod(dir, dentry, mode, dev); - if (error) - return error; - error = security_inode_post_create(dir, dentry, mode); - if (error) - return error; if (!error) fsnotify_create(dir, dentry); return error; diff --git a/fs/namespace.c b/fs/namespace.c index 68549a0d10547d3fda0b5ea5860c6280c4064b3f..53db6cdba8eae3f1206dbc348bd621852c9f8c60 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3275,8 +3275,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, /* make certain new is below the root */ if (!is_path_reachable(new_mnt, new.dentry, &root)) goto out4; - root_mp->m_count++; /* pin it so it won't go away */ lock_mount_hash(); + root_mp->m_count++; /* pin it so it won't go away */ detach_mnt(new_mnt, &parent_path); detach_mnt(root_mnt, &root_parent); if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 5f93cfacb3d14b9befc6ba33a91d79ccde044d89..ac3e06367cb689bc8c522fcab67bbf5c423b3f31 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -89,7 +89,7 @@ config NFS_V4 config NFS_SWAP bool "Provide swap over NFS support" default n - depends on NFS_FS + depends on NFS_FS && SWAP select SUNRPC_SWAP help This option enables swapon to work on files located on NFS mounts. diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index b8d55da2f04d5299c84ab640b44dc4c21de0bbf7..440ff8e7082b6321e523096f279ec7bf04e0b6a2 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -127,6 +127,8 @@ static struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp, restart: list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry(lo, &server->layouts, plh_layouts) { + if (!pnfs_layout_is_valid(lo)) + continue; if (stateid != NULL && !nfs4_stateid_match_other(stateid, &lo->plh_stateid)) continue; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b8c8ce34d768b645fc00966f850a60b6a2615b68..7dba2594421eab1e993d323430eea6d04eef610e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -169,6 +169,17 @@ typedef struct { bool eof; } nfs_readdir_descriptor_t; +static +void nfs_readdir_init_array(struct page *page) +{ + struct nfs_cache_array *array; + + array = kmap_atomic(page); + memset(array, 0, sizeof(struct nfs_cache_array)); + array->eof_index = -1; + kunmap_atomic(array); +} + /* * we are freeing strings created by nfs_add_to_readdir_array() */ @@ -181,6 +192,7 @@ void nfs_readdir_clear_array(struct page *page) array = kmap_atomic(page); for (i = 0; i < array->size; i++) kfree(array->array[i].string.name); + array->size = 0; kunmap_atomic(array); } @@ -617,6 +629,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, int status = -ENOMEM; unsigned int array_size = ARRAY_SIZE(pages); + nfs_readdir_init_array(page); + entry.prev_cookie = 0; entry.cookie = desc->last_cookie; entry.eof = 0; @@ -633,8 +647,6 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, } array = kmap(page); - memset(array, 0, sizeof(struct nfs_cache_array)); - array->eof_index = -1; status = nfs_readdir_alloc_pages(pages, array_size); if (status < 0) @@ -689,6 +701,7 @@ int nfs_readdir_filler(struct file *file, struct page* page) unlock_page(page); return 0; error: + nfs_readdir_clear_array(page); unlock_page(page); return ret; } @@ -696,8 +709,6 @@ int nfs_readdir_filler(struct file *file, struct page* page) static void cache_page_release(nfs_readdir_descriptor_t *desc) { - if (!desc->page->mapping) - nfs_readdir_clear_array(desc->page); put_page(desc->page); desc->page = NULL; } @@ -711,19 +722,28 @@ struct page *get_cache_page(nfs_readdir_descriptor_t *desc) /* * Returns 0 if desc->dir_cookie was found on page desc->page_index + * and locks the page to prevent removal from the page cache. */ static -int find_cache_page(nfs_readdir_descriptor_t *desc) +int find_and_lock_cache_page(nfs_readdir_descriptor_t *desc) { int res; desc->page = get_cache_page(desc); if (IS_ERR(desc->page)) return PTR_ERR(desc->page); - - res = nfs_readdir_search_array(desc); + res = lock_page_killable(desc->page); if (res != 0) - cache_page_release(desc); + goto error; + res = -EAGAIN; + if (desc->page->mapping != NULL) { + res = nfs_readdir_search_array(desc); + if (res == 0) + return 0; + } + unlock_page(desc->page); +error: + cache_page_release(desc); return res; } @@ -738,7 +758,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) desc->last_cookie = 0; } do { - res = find_cache_page(desc); + res = find_and_lock_cache_page(desc); } while (res == -EAGAIN); return res; } @@ -777,7 +797,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc) desc->eof = 1; kunmap(desc->page); - cache_page_release(desc); dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); return res; @@ -823,13 +842,13 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc) status = nfs_do_filldir(desc); + out_release: + nfs_readdir_clear_array(desc->page); + cache_page_release(desc); out: dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status); return status; - out_release: - cache_page_release(desc); - goto out; } /* The file offset position represents the dirent entry number. A @@ -894,6 +913,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) break; res = nfs_do_filldir(desc); + unlock_page(desc->page); + cache_page_release(desc); if (res < 0) break; } while (!desc->eof); diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 9cdac9945483b5c4c19c8c28669629e3a4da2570..e6ea4511c41ceba0d711458666346b445c878c8d 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -261,10 +261,10 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, data->ds_commit_index); /* verifier not set so always fail */ - if (verfp->committed < 0) + if (verfp->committed < 0 || data->res.verf->committed <= NFS_UNSTABLE) return 1; - return nfs_direct_cmp_verf(verfp, &data->verf); + return nfs_direct_cmp_verf(verfp, data->res.verf); } /** @@ -600,6 +600,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) l_ctx = nfs_get_lock_context(dreq->ctx); if (IS_ERR(l_ctx)) { result = PTR_ERR(l_ctx); + nfs_direct_req_release(dreq); goto out_release; } dreq->l_ctx = l_ctx; @@ -1023,6 +1024,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) l_ctx = nfs_get_lock_context(dreq->ctx); if (IS_ERR(l_ctx)) { result = PTR_ERR(l_ctx); + nfs_direct_req_release(dreq); goto out_release; } dreq->l_ctx = l_ctx; diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 7173a4ee862cb87af4cbab0314032c412a6bf3e8..5e9f9c70fe701590983e3e2e77887c48a93983b7 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -253,37 +253,45 @@ int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - struct posix_acl *alloc = NULL, *dfacl = NULL; + struct posix_acl *orig = acl, *dfacl = NULL, *alloc; int status; if (S_ISDIR(inode->i_mode)) { switch(type) { case ACL_TYPE_ACCESS: - alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT); + alloc = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(alloc)) goto fail; + dfacl = alloc; break; case ACL_TYPE_DEFAULT: - dfacl = acl; - alloc = acl = get_acl(inode, ACL_TYPE_ACCESS); + alloc = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(alloc)) goto fail; + dfacl = acl; + acl = alloc; break; } } if (acl == NULL) { - alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); if (IS_ERR(alloc)) goto fail; + acl = alloc; } status = __nfs3_proc_setacls(inode, acl, dfacl); - posix_acl_release(alloc); +out: + if (acl != orig) + posix_acl_release(acl); + if (dfacl != orig) + posix_acl_release(dfacl); return status; fail: - return PTR_ERR(alloc); + status = PTR_ERR(alloc); + goto out; } const struct xattr_handler *nfs3_xattr_handlers[] = { diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 6cd33bd5da87c355c47ade6823e2c2683941e1b2..f1cb0b7eb05f90e9abc779094504bdd728327ebd 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -2373,6 +2373,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, void *data) { struct nfs_commitres *result = data; + struct nfs_writeverf *verf = result->verf; enum nfs_stat status; int error; @@ -2385,7 +2386,9 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, result->op_status = status; if (status != NFS3_OK) goto out_status; - error = decode_writeverf3(xdr, &result->verf->verifier); + error = decode_writeverf3(xdr, &verf->verifier); + if (!error) + verf->committed = NFS_FILE_SYNC; out: return error; out_status: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3dd403943b07fd3e30f836c73b2cb19ffcbd8c58..4d45786738ab442104c4bbd23cd6604d836c0e7f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2923,6 +2923,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, exception.retry = 1; continue; } + if (status == -NFS4ERR_EXPIRED) { + nfs4_schedule_lease_recovery(server->nfs_client); + exception.retry = 1; + continue; + } if (status == -EAGAIN) { /* We must have found a delegation */ exception.retry = 1; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 525684b0056fc097e0aaff966004d7a3b7f8fd1d..0b2d051990e99593316b43a2d2d26bc7ded41f4b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4409,11 +4409,14 @@ static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifi static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res) { + struct nfs_writeverf *verf = res->verf; int status; status = decode_op_hdr(xdr, OP_COMMIT); if (!status) - status = decode_write_verifier(xdr, &res->verf->verifier); + status = decode_write_verifier(xdr, &verf->verifier); + if (!status) + verf->committed = NFS_FILE_SYNC; return status; } diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index ceb6892d9bbdcb3b332a499bb06fedb8e04e9f9f..7c01936be7c706f50e0c9bdae61aa815d24e7b8c 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -864,15 +864,6 @@ static void nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio, pgio->pg_mirror_count = mirror_count; } -/* - * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1) - */ -void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio) -{ - pgio->pg_mirror_count = 1; - pgio->pg_mirror_idx = 0; -} - static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio) { pgio->pg_mirror_count = 1; @@ -1301,6 +1292,14 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) } } +/* + * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1) + */ +void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio) +{ + nfs_pageio_complete(pgio); +} + int __init nfs_init_nfspagecache(void) { nfs_page_cachep = kmem_cache_create("nfs_page", diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index 4a3dd66175fed1732dc4a8c6f8c241e6391d6f53..b0ef37f3e2dd7f126394b2660322b08574ab9bd1 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c @@ -30,12 +30,11 @@ EXPORT_SYMBOL_GPL(pnfs_generic_rw_release); /* Fake up some data that will cause nfs_commit_release to retry the writes. */ void pnfs_generic_prepare_to_resend_writes(struct nfs_commit_data *data) { - struct nfs_page *first = nfs_list_entry(data->pages.next); + struct nfs_writeverf *verf = data->res.verf; data->task.tk_status = 0; - memcpy(&data->verf.verifier, &first->wb_verf, - sizeof(data->verf.verifier)); - data->verf.verifier.data[0]++; /* ensure verifier mismatch */ + memset(&verf->verifier, 0, sizeof(verf->verifier)); + verf->committed = NFS_UNSTABLE; } EXPORT_SYMBOL_GPL(pnfs_generic_prepare_to_resend_writes); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index ed3f5afc4ff7f2e12f3621bf3b4cdb962f958c27..7b6bda68aa86a3b5eca6574a484788c2becab445 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -422,6 +422,7 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list, } subreq->wb_head = subreq; + nfs_release_request(old_head); if (test_and_clear_bit(PG_INODE_REF, &subreq->wb_flags)) { nfs_release_request(subreq); @@ -1807,6 +1808,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) static void nfs_commit_release_pages(struct nfs_commit_data *data) { + const struct nfs_writeverf *verf = data->res.verf; struct nfs_page *req; int status = data->task.tk_status; struct nfs_commit_info cinfo; @@ -1833,7 +1835,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) /* Okay, COMMIT succeeded, apparently. Check the verifier * returned by the server against all stored verfs. */ - if (!nfs_write_verifier_cmp(&req->wb_verf, &data->verf.verifier)) { + if (verf->committed > NFS_UNSTABLE && + !nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier)) { /* We have a match */ if (req->wb_page) nfs_inode_remove_request(req); diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index ea45d954e8d7c53cbb3db6dcbf8ac3958b314a90..99add0cf20ff1857334ee7cf8ea1d9f65b49c34b 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -683,7 +683,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task) /* Client gets 2 lease periods to return it */ cutoff = ktime_add_ns(task->tk_start, - nn->nfsd4_lease * NSEC_PER_SEC * 2); + (u64)nn->nfsd4_lease * NSEC_PER_SEC * 2); if (ktime_before(now, cutoff)) { rpc_delay(task, HZ/100); /* 10 mili-seconds */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fc13236d1be1f9c84087e4abbb99a95836605b14..d5d1c70bb927b6d828b6ff0787fba4f2a8d09902 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -246,6 +246,8 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, if (!nbl) { nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); if (nbl) { + INIT_LIST_HEAD(&nbl->nbl_list); + INIT_LIST_HEAD(&nbl->nbl_lru); fh_copy_shallow(&nbl->nbl_fh, fh); locks_init_lock(&nbl->nbl_lock); nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, @@ -6040,7 +6042,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } if (fl_flags & FL_SLEEP) { - nbl->nbl_time = jiffies; + nbl->nbl_time = get_seconds(); spin_lock(&nn->blocked_locks_lock); list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 133d8bf62a5cdae4d0e9d1ec4466eee31d63991b..7872b1ead88584134550e843ec8117933302d643 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -591,7 +591,7 @@ static inline bool nfsd4_stateid_generation_after(stateid_t *a, stateid_t *b) struct nfsd4_blocked_lock { struct list_head nbl_list; struct list_head nbl_lru; - unsigned long nbl_time; + time_t nbl_time; struct file_lock nbl_lock; struct knfsd_fh nbl_fh; struct nfsd4_callback nbl_cb; diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index addd7c5f2d3e522a7a65bd51b0164ef705402605..bed54e8adcf99683fbd665565babe39633090c3f 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -7240,6 +7240,10 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; struct ocfs2_inline_data *idata = &di->id2.i_data; + /* No need to punch hole beyond i_size. */ + if (start >= i_size_read(inode)) + return 0; + if (end > i_size_read(inode)) end = i_size_read(inode); diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 497a4171ef61f6209a32303530b79c72439962cf..bfb50fc51528ffbf9d7c20c7b8b9872475991029 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -637,9 +637,11 @@ static inline void ocfs2_update_inode_fsync_trans(handle_t *handle, { struct ocfs2_inode_info *oi = OCFS2_I(inode); - oi->i_sync_tid = handle->h_transaction->t_tid; - if (datasync) - oi->i_datasync_tid = handle->h_transaction->t_tid; + if (!is_handle_aborted(handle)) { + oi->i_sync_tid = handle->h_transaction->t_tid; + if (datasync) + oi->i_datasync_tid = handle->h_transaction->t_tid; + } } #endif /* OCFS2_JOURNAL_H */ diff --git a/fs/open.c b/fs/open.c index c7776aa098bc76dc2d9c68df1213363c3af024e3..0628bd1ae2ad69356c706122d19e8bd263bebb99 100644 --- a/fs/open.c +++ b/fs/open.c @@ -838,9 +838,6 @@ static int do_dentry_open(struct file *f, * the return value of d_splice_alias(), then the caller needs to perform dput() * on it after finish_open(). * - * On successful return @file is a fully instantiated open file. After this, if - * an error occurs in ->atomic_open(), it needs to clean up with fput(). - * * Returns zero on success or -errno if the open failed. */ int finish_open(struct file *file, struct dentry *dentry, diff --git a/fs/orangefs/orangefs-debugfs.c b/fs/orangefs/orangefs-debugfs.c index 1c59dff530dee5d10eadcb671798367ee40e173b..34d1cc98260d23dd8d3df5d9f87613be06766c7c 100644 --- a/fs/orangefs/orangefs-debugfs.c +++ b/fs/orangefs/orangefs-debugfs.c @@ -305,6 +305,7 @@ static void *help_start(struct seq_file *m, loff_t *pos) static void *help_next(struct seq_file *m, void *v, loff_t *pos) { + (*pos)++; gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n"); return NULL; diff --git a/fs/pnode.c b/fs/pnode.c index 681916df422c777a8743608623258d1ffecbe501..1fc2e47d130827a3897d5309abcfbbd79ef77b34 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -266,14 +266,13 @@ static int propagate_one(struct mount *m) if (IS_ERR(child)) return PTR_ERR(child); child->mnt.mnt_flags &= ~MNT_LOCKED; + read_seqlock_excl(&mount_lock); mnt_set_mountpoint(m, mp, child); + if (m->mnt_master != dest_master) + SET_MNT_MARK(m->mnt_master); + read_sequnlock_excl(&mount_lock); last_dest = m; last_source = child; - if (m->mnt_master != dest_master) { - read_seqlock_excl(&mount_lock); - SET_MNT_MARK(m->mnt_master); - read_sequnlock_excl(&mount_lock); - } hlist_add_head(&child->mnt_hash, list); return count_mounts(m->mnt_ns, child); } diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index ce400f97370d3fd509f46103bedf98abb536feaf..aaa7486b6f0d9e42a850c9f154d3dcfdceb34e95 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -459,7 +459,7 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma) tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)start, size); kaddr = elfnotes_buf + start - elfcorebuf_sz; if (remap_vmalloc_range_partial(vma, vma->vm_start + len, - kaddr, tsz)) + kaddr, 0, tsz)) goto fail; size -= tsz; start += tsz; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 0037aea97d39a6c73eff9755d805bc2312b552a3..2946713cb00d6cfe327dd6e86ac3b452d6cc34fb 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -2250,7 +2250,8 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, /* also releases the path */ unfix_nodes(&s_ins_balance); #ifdef REISERQUOTA_DEBUG - reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE, + if (inode) + reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE, "reiserquota insert_item(): freeing %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(ih)); #endif diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5208d85dd30c55f711b7892601541e401c931ad3..9caf3948417c0c6e5b073c4da6e005d5eb70ad55 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1954,7 +1954,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) if (!sbi->s_jdev) { SWARN(silent, s, "", "Cannot allocate memory for " "journal device name"); - goto error; + goto error_unlocked; } } #ifdef CONFIG_QUOTA diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 4dd681e0d59d948374883a7e34ed8318d4537e23..edeca118cce5008ccec9d35ccae19513c62bcc36 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -87,6 +87,9 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, lower_dentry_mnt = lower_path.mnt; lower_parent_dentry = lock_parent(lower_dentry); + if (d_is_positive(lower_dentry)) + return -EEXIST; + /* set last 16bytes of mode field to 0664 */ mode = (mode & S_IFMT) | 00664; diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a9e28ae8091f7387c070434a2f34125a1c03ee8b..886aee2799203a948190d61a6c01db5d0da3fe37 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -257,7 +257,6 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct dentry *lower_dentry; const struct qstr *name; struct path lower_path; - struct qstr dname; struct dentry *ret_dentry = NULL; struct sdcardfs_sb_info *sbi; @@ -316,6 +315,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, /* no error: handle positive dentries */ if (!err) { +found: /* check if the dentry is an obb dentry * if true, the lower_inode must be replaced with * the inode of the graft path @@ -362,23 +362,26 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, if (err && err != -ENOENT) goto out; - /* instatiate a new negative dentry */ - dname.name = name->name; - dname.len = name->len; - - /* See if the low-level filesystem might want - * to use its own hash - */ - lower_dentry = lookup_one_len_unlocked(dname.name, lower_dir_dentry, - dname.len); - if (IS_ERR(lower_dentry)) - return lower_dentry; - - if (d_really_is_negative(lower_dentry)) - err = -ENOENT; + /* get a (very likely) new negative dentry */ + lower_dentry = lookup_one_len_unlocked(name->name, + lower_dir_dentry, name->len); + if (IS_ERR(lower_dentry)) { + err = PTR_ERR(lower_dentry); + goto out; + } lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); + + /* + * Check if someone sneakily filled in the dentry when + * we weren't looking. We'll check again in create. + */ + if (unlikely(d_inode_rcu(lower_dentry))) { + err = 0; + goto found; + } + sdcardfs_set_lower_path(dentry, &lower_path); /* diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig index dfc6fdf019d70dcb59c29f2aad5652fa7c43a46a..fe221d7d99d6cf8c631e338d257e20f209d94d89 100644 --- a/fs/ubifs/Kconfig +++ b/fs/ubifs/Kconfig @@ -7,6 +7,7 @@ config UBIFS_FS select CRYPTO if UBIFS_FS_ZLIB select CRYPTO_LZO if UBIFS_FS_LZO select CRYPTO_DEFLATE if UBIFS_FS_ZLIB + select FS_ENCRYPTION_ALGS if FS_ENCRYPTION depends on MTD_UBI help UBIFS is a file system for flash devices which works on top of UBI. diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 8464a3dd31074c53f8f0c03151848bbfcf5e0ebd..7d5c2cf95353cf2144939f0fb8c6d6d86558b671 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -208,6 +208,7 @@ static int dbg_check_name(const struct ubifs_info *c, return 0; } +static void ubifs_set_d_ops(struct inode *dir, struct dentry *dentry); static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { @@ -221,6 +222,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); err = fscrypt_prepare_lookup(dir, dentry, &nm); + ubifs_set_d_ops(dir, dentry); if (err == -ENOENT) return d_splice_alias(NULL, dentry); if (err) @@ -237,9 +239,9 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, goto out_fname; } - if (nm.hash) { - ubifs_assert(fname_len(&nm) == 0); - ubifs_assert(fname_name(&nm) == NULL); + if (fname_name(&nm) == NULL) { + if (nm.hash & ~UBIFS_S_KEY_HASH_MASK) + goto done; /* ENOENT */ dent_key_init_hash(c, &key, dir->i_ino, nm.hash); err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash); } else { @@ -537,7 +539,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) if (encrypted) { err = fscrypt_get_encryption_info(dir); - if (err && err != -ENOKEY) + if (err) return err; err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr); @@ -1684,3 +1686,19 @@ const struct file_operations ubifs_dir_operations = { .compat_ioctl = ubifs_compat_ioctl, #endif }; + +#ifdef CONFIG_FS_ENCRYPTION +static const struct dentry_operations ubifs_encrypted_dentry_ops = { + .d_revalidate = fscrypt_d_revalidate, +}; +#endif + +static void ubifs_set_d_ops(struct inode *dir, struct dentry *dentry) +{ +#ifdef CONFIG_FS_ENCRYPTION + if (dentry->d_flags & DCACHE_ENCRYPTED_NAME) { + d_set_d_op(dentry, &ubifs_encrypted_dentry_ops); + return; + } +#endif +} diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index ff44fd90d51ba414931f6139c19c3c14f59febb8..76fff889a2f7741bd000baba08a5083a076ea2db 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -797,7 +797,9 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu, if (page_offset > end_index) break; - page = find_or_create_page(mapping, page_offset, ra_gfp_mask); + page = pagecache_get_page(mapping, page_offset, + FGP_LOCK|FGP_ACCESSED|FGP_CREAT|FGP_NOWAIT, + ra_gfp_mask); if (!page) break; if (!PageUptodate(page)) diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 71c34400157492f64405464ba083165a095759a0..203067d3985518c1d785b42d67c14087c621d9b3 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -28,6 +28,11 @@ #include #include "ubifs.h" +/* Need to be kept consistent with checked flags in ioctl2ubifs() */ +#define UBIFS_SUPPORTED_IOCTL_FLAGS \ + (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \ + FS_IMMUTABLE_FL | FS_DIRSYNC_FL) + /** * ubifs_set_inode_flags - set VFS inode flags. * @inode: VFS inode to set flags for @@ -127,7 +132,8 @@ static int setflags(struct inode *inode, int flags) } } - ui->flags = ioctl2ubifs(flags); + ui->flags &= ~ioctl2ubifs(UBIFS_SUPPORTED_IOCTL_FLAGS); + ui->flags |= ioctl2ubifs(flags); ubifs_set_inode_flags(inode); inode->i_ctime = current_time(inode); release = ui->dirty; @@ -169,6 +175,9 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (get_user(flags, (int __user *) arg)) return -EFAULT; + if (flags & ~UBIFS_SUPPORTED_IOCTL_FLAGS) + return -EOPNOTSUPP; + if (!S_ISDIR(inode->i_mode)) flags &= ~FS_DIRSYNC_FL; diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 69051f7a960667502894a8ba3cd357a21be7e1ac..99d31a64f2a394786725996f217310b11536178f 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -583,7 +583,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, if (!xent) { dent->ch.node_type = UBIFS_DENT_NODE; - if (nm->hash) + if (fname_name(nm) == NULL) dent_key_init_hash(c, &dent_key, dir->i_ino, nm->hash); else dent_key_init(c, &dent_key, dir->i_ino, nm); @@ -630,7 +630,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, kfree(dent); if (deletion) { - if (nm->hash) + if (fname_name(nm) == NULL) err = ubifs_tnc_remove_dh(c, &dent_key, nm->minor_hash); else err = ubifs_tnc_remove_nm(c, &dent_key, nm); diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h index b1f7c0caa3acb60f53409d306da192b21b253e49..7547be512db2632153ce20822dd0063dcdc5cddd 100644 --- a/fs/ubifs/key.h +++ b/fs/ubifs/key.h @@ -162,7 +162,6 @@ static inline void dent_key_init(const struct ubifs_info *c, uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm)); ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); - ubifs_assert(!nm->hash && !nm->minor_hash); key->u32[0] = inum; key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); } diff --git a/fs/udf/super.c b/fs/udf/super.c index 242d960df9a17a2171a3824b2dea6405a05dec81..51de27685e185efd6539b8be69e05ae642359b53 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2467,17 +2467,29 @@ static unsigned int udf_count_free_table(struct super_block *sb, static unsigned int udf_count_free(struct super_block *sb) { unsigned int accum = 0; - struct udf_sb_info *sbi; + struct udf_sb_info *sbi = UDF_SB(sb); struct udf_part_map *map; + unsigned int part = sbi->s_partition; + int ptype = sbi->s_partmaps[part].s_partition_type; + + if (ptype == UDF_METADATA_MAP25) { + part = sbi->s_partmaps[part].s_type_specific.s_metadata. + s_phys_partition_ref; + } else if (ptype == UDF_VIRTUAL_MAP15 || ptype == UDF_VIRTUAL_MAP20) { + /* + * Filesystems with VAT are append-only and we cannot write to + * them. Let's just report 0 here. + */ + return 0; + } - sbi = UDF_SB(sb); if (sbi->s_lvid_bh) { struct logicalVolIntegrityDesc *lvid = (struct logicalVolIntegrityDesc *) sbi->s_lvid_bh->b_data; - if (le32_to_cpu(lvid->numOfPartitions) > sbi->s_partition) { + if (le32_to_cpu(lvid->numOfPartitions) > part) { accum = le32_to_cpu( - lvid->freeSpaceTable[sbi->s_partition]); + lvid->freeSpaceTable[part]); if (accum == 0xFFFFFFFF) accum = 0; } @@ -2486,7 +2498,7 @@ static unsigned int udf_count_free(struct super_block *sb) if (accum) return accum; - map = &sbi->s_partmaps[sbi->s_partition]; + map = &sbi->s_partmaps[part]; if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) { accum += udf_count_free_bitmap(sb, map->s_uspace.s_bitmap); diff --git a/fs/unicode/utf8-core.c b/fs/unicode/utf8-core.c index 71ca4d047d6543701dbbdcc2056348534a25e96f..d18789f276503136ea33ba25fedceeea796e9463 100644 --- a/fs/unicode/utf8-core.c +++ b/fs/unicode/utf8-core.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "utf8n.h" @@ -122,9 +123,29 @@ int utf8_casefold(const struct unicode_map *um, const struct qstr *str, } return -EINVAL; } - EXPORT_SYMBOL(utf8_casefold); +int utf8_casefold_hash(const struct unicode_map *um, const void *salt, + struct qstr *str) +{ + const struct utf8data *data = utf8nfdicf(um->version); + struct utf8cursor cur; + int c; + unsigned long hash = init_name_hash(salt); + + if (utf8ncursor(&cur, data, str->name, str->len) < 0) + return -EINVAL; + + while ((c = utf8byte(&cur))) { + if (c < 0) + return c; + hash = partial_name_hash((unsigned char)c, hash); + } + str->hash = end_name_hash(hash); + return 0; +} +EXPORT_SYMBOL(utf8_casefold_hash); + int utf8_normalize(const struct unicode_map *um, const struct qstr *str, unsigned char *dest, size_t dlen) { diff --git a/fs/verity/enable.c b/fs/verity/enable.c index eabc6ac1990641fc6b4c54108d32328a9bee95c6..15e7d14ec2ffc7e09b77dff8b235b351baa2f3f5 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -8,18 +8,48 @@ #include "fsverity_private.h" #include +#include #include #include #include #include -static int build_merkle_tree_level(struct inode *inode, unsigned int level, +/* + * Read a file data page for Merkle tree construction. Do aggressive readahead, + * since we're sequentially reading the entire file. + */ +static struct page *read_file_data_page(struct file *filp, pgoff_t index, + struct file_ra_state *ra, + unsigned long remaining_pages) +{ + struct page *page; + + page = find_get_page_flags(filp->f_mapping, index, FGP_ACCESSED); + if (!page || !PageUptodate(page)) { + if (page) + put_page(page); + else + page_cache_sync_readahead(filp->f_mapping, ra, filp, + index, remaining_pages); + page = read_mapping_page(filp->f_mapping, index, NULL); + if (IS_ERR(page)) + return page; + } + if (PageReadahead(page)) + page_cache_async_readahead(filp->f_mapping, ra, filp, page, + index, remaining_pages); + return page; +} + +static int build_merkle_tree_level(struct file *filp, unsigned int level, u64 num_blocks_to_hash, const struct merkle_tree_params *params, u8 *pending_hashes, struct ahash_request *req) { + struct inode *inode = file_inode(filp); const struct fsverity_operations *vops = inode->i_sb->s_vop; + struct file_ra_state ra = { 0 }; unsigned int pending_size = 0; u64 dst_block_num; u64 i; @@ -36,6 +66,8 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level, dst_block_num = 0; /* unused */ } + file_ra_state_init(&ra, filp->f_mapping); + for (i = 0; i < num_blocks_to_hash; i++) { struct page *src_page; @@ -45,7 +77,8 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level, if (level == 0) { /* Leaf: hashing a data block */ - src_page = read_mapping_page(inode->i_mapping, i, NULL); + src_page = read_file_data_page(filp, i, &ra, + num_blocks_to_hash - i); if (IS_ERR(src_page)) { err = PTR_ERR(src_page); fsverity_err(inode, @@ -54,9 +87,14 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level, return err; } } else { + unsigned long num_ra_pages = + min_t(unsigned long, num_blocks_to_hash - i, + inode->i_sb->s_bdi->io_pages); + /* Non-leaf: hashing hash block from level below */ src_page = vops->read_merkle_tree_page(inode, - params->level_start[level - 1] + i); + params->level_start[level - 1] + i, + num_ra_pages); if (IS_ERR(src_page)) { err = PTR_ERR(src_page); fsverity_err(inode, @@ -103,17 +141,18 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level, } /* - * Build the Merkle tree for the given inode using the given parameters, and + * Build the Merkle tree for the given file using the given parameters, and * return the root hash in @root_hash. * * The tree is written to a filesystem-specific location as determined by the * ->write_merkle_tree_block() method. However, the blocks that comprise the * tree are the same for all filesystems. */ -static int build_merkle_tree(struct inode *inode, +static int build_merkle_tree(struct file *filp, const struct merkle_tree_params *params, u8 *root_hash) { + struct inode *inode = file_inode(filp); u8 *pending_hashes; struct ahash_request *req; u64 blocks; @@ -126,9 +165,11 @@ static int build_merkle_tree(struct inode *inode, return 0; } + /* This allocation never fails, since it's mempool-backed. */ + req = fsverity_alloc_hash_request(params->hash_alg, GFP_KERNEL); + pending_hashes = kmalloc(params->block_size, GFP_KERNEL); - req = ahash_request_alloc(params->hash_alg->tfm, GFP_KERNEL); - if (!pending_hashes || !req) + if (!pending_hashes) goto out; /* @@ -139,7 +180,7 @@ static int build_merkle_tree(struct inode *inode, blocks = (inode->i_size + params->block_size - 1) >> params->log_blocksize; for (level = 0; level <= params->num_levels; level++) { - err = build_merkle_tree_level(inode, level, blocks, params, + err = build_merkle_tree_level(filp, level, blocks, params, pending_hashes, req); if (err) goto out; @@ -150,7 +191,7 @@ static int build_merkle_tree(struct inode *inode, err = 0; out: kfree(pending_hashes); - ahash_request_free(req); + fsverity_free_hash_request(params->hash_alg, req); return err; } @@ -175,8 +216,7 @@ static int enable_verity(struct file *filp, /* Get the salt if the user provided one */ if (arg->salt_size && - copy_from_user(desc->salt, - (const u8 __user *)(uintptr_t)arg->salt_ptr, + copy_from_user(desc->salt, u64_to_user_ptr(arg->salt_ptr), arg->salt_size)) { err = -EFAULT; goto out; @@ -185,8 +225,7 @@ static int enable_verity(struct file *filp, /* Get the signature if the user provided one */ if (arg->sig_size && - copy_from_user(desc->signature, - (const u8 __user *)(uintptr_t)arg->sig_ptr, + copy_from_user(desc->signature, u64_to_user_ptr(arg->sig_ptr), arg->sig_size)) { err = -EFAULT; goto out; @@ -227,7 +266,7 @@ static int enable_verity(struct file *filp, */ pr_debug("Building Merkle tree...\n"); BUILD_BUG_ON(sizeof(desc->root_hash) < FS_VERITY_MAX_DIGEST_SIZE); - err = build_merkle_tree(inode, ¶ms, desc->root_hash); + err = build_merkle_tree(filp, ¶ms, desc->root_hash); if (err) { fsverity_err(inode, "Error %d building Merkle tree", err); goto rollback; diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index e74c79b64d8898e4778cfe704ae536c77e5daa6b..4b2c8aed0563103ad04f8870a8db7e95f13a51cc 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -16,6 +16,7 @@ #include #include +#include struct ahash_request; @@ -37,11 +38,12 @@ struct fsverity_hash_alg { const char *name; /* crypto API name, e.g. sha256 */ unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */ unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */ + mempool_t *req_pool; /* mempool with a preallocated hash request */ }; /* Merkle tree parameters: hash algorithm, initial hash state, and topology */ struct merkle_tree_params { - const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */ + struct fsverity_hash_alg *hash_alg; /* the hash algorithm */ const u8 *hashstate; /* initial hash state or NULL */ unsigned int digest_size; /* same as hash_alg->digest_size */ unsigned int block_size; /* size of data and tree blocks */ @@ -50,6 +52,7 @@ struct merkle_tree_params { unsigned int log_arity; /* log2(hashes_per_block) */ unsigned int num_levels; /* number of levels in Merkle tree */ u64 tree_size; /* Merkle tree size in bytes */ + unsigned long level0_blocks; /* number of blocks in tree level 0 */ /* * Starting block index for each tree level, ordered from leaf level (0) @@ -114,14 +117,18 @@ struct fsverity_signed_digest { extern struct fsverity_hash_alg fsverity_hash_algs[]; -const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, - unsigned int num); -const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, +struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, + unsigned int num); +struct ahash_request *fsverity_alloc_hash_request(struct fsverity_hash_alg *alg, + gfp_t gfp_flags); +void fsverity_free_hash_request(struct fsverity_hash_alg *alg, + struct ahash_request *req); +const u8 *fsverity_prepare_hash_state(struct fsverity_hash_alg *alg, const u8 *salt, size_t salt_size); int fsverity_hash_page(const struct merkle_tree_params *params, const struct inode *inode, struct ahash_request *req, struct page *page, u8 *out); -int fsverity_hash_buffer(const struct fsverity_hash_alg *alg, +int fsverity_hash_buffer(struct fsverity_hash_alg *alg, const void *data, size_t size, u8 *out); void __init fsverity_check_hash_algs(void); diff --git a/fs/verity/hash_algs.c b/fs/verity/hash_algs.c index 31e6d7d2389ab00a1a7d8a4b6bc4c3af03e21a85..6682e4e6b601fdf84002bee63a119d5b67b42ab7 100644 --- a/fs/verity/hash_algs.c +++ b/fs/verity/hash_algs.c @@ -24,6 +24,8 @@ struct fsverity_hash_alg fsverity_hash_algs[] = { }, }; +static DEFINE_MUTEX(fsverity_hash_alg_init_mutex); + /** * fsverity_get_hash_alg() - validate and prepare a hash algorithm * @inode: optional inode for logging purposes @@ -36,8 +38,8 @@ struct fsverity_hash_alg fsverity_hash_algs[] = { * * Return: pointer to the hash alg on success, else an ERR_PTR() */ -const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, - unsigned int num) +struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, + unsigned int num) { struct fsverity_hash_alg *alg; struct crypto_ahash *tfm; @@ -50,10 +52,15 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, } alg = &fsverity_hash_algs[num]; - /* pairs with cmpxchg() below */ - tfm = READ_ONCE(alg->tfm); - if (likely(tfm != NULL)) + /* pairs with smp_store_release() below */ + if (likely(smp_load_acquire(&alg->tfm) != NULL)) return alg; + + mutex_lock(&fsverity_hash_alg_init_mutex); + + if (alg->tfm != NULL) + goto out_unlock; + /* * Using the shash API would make things a bit simpler, but the ahash * API is preferable as it allows the use of crypto accelerators. @@ -64,12 +71,14 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, fsverity_warn(inode, "Missing crypto API support for hash algorithm \"%s\"", alg->name); - return ERR_PTR(-ENOPKG); + alg = ERR_PTR(-ENOPKG); + goto out_unlock; } fsverity_err(inode, "Error allocating hash algorithm \"%s\": %ld", alg->name, PTR_ERR(tfm)); - return ERR_CAST(tfm); + alg = ERR_CAST(tfm); + goto out_unlock; } err = -EINVAL; @@ -78,18 +87,63 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, if (WARN_ON(alg->block_size != crypto_ahash_blocksize(tfm))) goto err_free_tfm; + alg->req_pool = mempool_create_kmalloc_pool(1, + sizeof(struct ahash_request) + + crypto_ahash_reqsize(tfm)); + if (!alg->req_pool) { + err = -ENOMEM; + goto err_free_tfm; + } + pr_info("%s using implementation \"%s\"\n", alg->name, crypto_ahash_driver_name(tfm)); - /* pairs with READ_ONCE() above */ - if (cmpxchg(&alg->tfm, NULL, tfm) != NULL) - crypto_free_ahash(tfm); - - return alg; + /* pairs with smp_load_acquire() above */ + smp_store_release(&alg->tfm, tfm); + goto out_unlock; err_free_tfm: crypto_free_ahash(tfm); - return ERR_PTR(err); + alg = ERR_PTR(err); +out_unlock: + mutex_unlock(&fsverity_hash_alg_init_mutex); + return alg; +} + +/** + * fsverity_alloc_hash_request() - allocate a hash request object + * @alg: the hash algorithm for which to allocate the request + * @gfp_flags: memory allocation flags + * + * This is mempool-backed, so this never fails if __GFP_DIRECT_RECLAIM is set in + * @gfp_flags. However, in that case this might need to wait for all + * previously-allocated requests to be freed. So to avoid deadlocks, callers + * must never need multiple requests at a time to make forward progress. + * + * Return: the request object on success; NULL on failure (but see above) + */ +struct ahash_request *fsverity_alloc_hash_request(struct fsverity_hash_alg *alg, + gfp_t gfp_flags) +{ + struct ahash_request *req = mempool_alloc(alg->req_pool, gfp_flags); + + if (req) + ahash_request_set_tfm(req, alg->tfm); + return req; +} + +/** + * fsverity_free_hash_request() - free a hash request object + * @alg: the hash algorithm + * @req: the hash request object to free + */ +void fsverity_free_hash_request(struct fsverity_hash_alg *alg, + struct ahash_request *req) +{ + if (req) { + ahash_request_zero(req); + mempool_free(req, alg->req_pool); + } } /** @@ -101,7 +155,7 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, * Return: NULL if the salt is empty, otherwise the kmalloc()'ed precomputed * initial hash state on success or an ERR_PTR() on failure. */ -const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, +const u8 *fsverity_prepare_hash_state(struct fsverity_hash_alg *alg, const u8 *salt, size_t salt_size) { u8 *hashstate = NULL; @@ -119,11 +173,8 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, if (!hashstate) return ERR_PTR(-ENOMEM); - req = ahash_request_alloc(alg->tfm, GFP_KERNEL); - if (!req) { - err = -ENOMEM; - goto err_free; - } + /* This allocation never fails, since it's mempool-backed. */ + req = fsverity_alloc_hash_request(alg, GFP_KERNEL); /* * Zero-pad the salt to the next multiple of the input size of the hash @@ -158,7 +209,7 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, if (err) goto err_free; out: - ahash_request_free(req); + fsverity_free_hash_request(alg, req); kfree(padded_salt); return hashstate; @@ -229,7 +280,7 @@ int fsverity_hash_page(const struct merkle_tree_params *params, * * Return: 0 on success, -errno on failure */ -int fsverity_hash_buffer(const struct fsverity_hash_alg *alg, +int fsverity_hash_buffer(struct fsverity_hash_alg *alg, const void *data, size_t size, u8 *out) { struct ahash_request *req; @@ -237,9 +288,8 @@ int fsverity_hash_buffer(const struct fsverity_hash_alg *alg, DECLARE_CRYPTO_WAIT(wait); int err; - req = ahash_request_alloc(alg->tfm, GFP_KERNEL); - if (!req) - return -ENOMEM; + /* This allocation never fails, since it's mempool-backed. */ + req = fsverity_alloc_hash_request(alg, GFP_KERNEL); sg_init_one(&sg, data, size); ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP | @@ -249,7 +299,7 @@ int fsverity_hash_buffer(const struct fsverity_hash_alg *alg, err = crypto_wait_req(crypto_ahash_digest(req), &wait); - ahash_request_free(req); + fsverity_free_hash_request(alg, req); return err; } diff --git a/fs/verity/open.c b/fs/verity/open.c index 4cdd75acbc97c9666929c7289fa8e3ff0c76af6e..25b29065d897cb558105ec725211eb46a39a342d 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -31,7 +31,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, unsigned int log_blocksize, const u8 *salt, size_t salt_size) { - const struct fsverity_hash_alg *hash_alg; + struct fsverity_hash_alg *hash_alg; int err; u64 blocks; u64 offset; @@ -102,6 +102,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, /* temporarily using level_start[] to store blocks in level */ params->level_start[params->num_levels++] = blocks; } + params->level0_blocks = params->level_start[0]; /* Compute the starting block of each level */ offset = 0; @@ -126,7 +127,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, * Compute the file measurement by hashing the fsverity_descriptor excluding the * signature and with the sig_size field set to 0. */ -static int compute_file_measurement(const struct fsverity_hash_alg *hash_alg, +static int compute_file_measurement(struct fsverity_hash_alg *hash_alg, struct fsverity_descriptor *desc, u8 *measurement) { diff --git a/fs/verity/verify.c b/fs/verity/verify.c index cf09852e5227f2205d966cd92d4b2c1bab82020e..5324270cd7d474f1506c481a9b613568e722717b 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -84,7 +84,8 @@ static inline int cmp_hashes(const struct fsverity_info *vi, * Return: true if the page is valid, else false. */ static bool verify_page(struct inode *inode, const struct fsverity_info *vi, - struct ahash_request *req, struct page *data_page) + struct ahash_request *req, struct page *data_page, + unsigned long level0_ra_pages) { const struct merkle_tree_params *params = &vi->tree_params; const unsigned int hsize = params->digest_size; @@ -117,8 +118,8 @@ static bool verify_page(struct inode *inode, const struct fsverity_info *vi, pr_debug_ratelimited("Level %d: hindex=%lu, hoffset=%u\n", level, hindex, hoffset); - hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, - hindex); + hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, hindex, + level == 0 ? level0_ra_pages : 0); if (IS_ERR(hpage)) { err = PTR_ERR(hpage); fsverity_err(inode, @@ -191,13 +192,12 @@ bool fsverity_verify_page(struct page *page) struct ahash_request *req; bool valid; - req = ahash_request_alloc(vi->tree_params.hash_alg->tfm, GFP_NOFS); - if (unlikely(!req)) - return false; + /* This allocation never fails, since it's mempool-backed. */ + req = fsverity_alloc_hash_request(vi->tree_params.hash_alg, GFP_NOFS); - valid = verify_page(inode, vi, req, page); + valid = verify_page(inode, vi, req, page, 0); - ahash_request_free(req); + fsverity_free_hash_request(vi->tree_params.hash_alg, req); return valid; } @@ -222,25 +222,42 @@ void fsverity_verify_bio(struct bio *bio) { struct inode *inode = bio->bi_io_vec->bv_page->mapping->host; const struct fsverity_info *vi = inode->i_verity_info; + const struct merkle_tree_params *params = &vi->tree_params; struct ahash_request *req; struct bio_vec *bv; int i; - - req = ahash_request_alloc(vi->tree_params.hash_alg->tfm, GFP_NOFS); - if (unlikely(!req)) { + unsigned long max_ra_pages = 0; + + /* This allocation never fails, since it's mempool-backed. */ + req = fsverity_alloc_hash_request(params->hash_alg, GFP_NOFS); + + if (bio->bi_opf & REQ_RAHEAD) { + /* + * If this bio is for data readahead, then we also do readahead + * of the first (largest) level of the Merkle tree. Namely, + * when a Merkle tree page is read, we also try to piggy-back on + * some additional pages -- up to 1/4 the number of data pages. + * + * This improves sequential read performance, as it greatly + * reduces the number of I/O requests made to the Merkle tree. + */ bio_for_each_segment_all(bv, bio, i) - SetPageError(bv->bv_page); - return; + max_ra_pages++; + max_ra_pages /= 4; } bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; + unsigned long level0_index = page->index >> params->log_arity; + unsigned long level0_ra_pages = + min(max_ra_pages, params->level0_blocks - level0_index); - if (!PageError(page) && !verify_page(inode, vi, req, page)) + if (!PageError(page) && + !verify_page(inode, vi, req, page, level0_ra_pages)) SetPageError(page); } - ahash_request_free(req); + fsverity_free_hash_request(params->hash_alg, req); } EXPORT_SYMBOL_GPL(fsverity_verify_bio); #endif /* CONFIG_BLOCK */ diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index cb4833d0646787d03e746d8bd7ec5ea3dbc814af..7cfbe2b0f8867ba060ee9c1f5dd2eb90f6f73d8b 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -3035,7 +3035,8 @@ xfs_rename( &dfops, &first_block, spaceres); /* - * Set up the target. + * Check for expected errors before we dirty the transaction + * so we can return an error without a transaction abort. */ if (target_ip == NULL) { /* @@ -3047,6 +3048,46 @@ xfs_rename( if (error) goto out_trans_cancel; } + } else { + /* + * If target exists and it's a directory, check that whether + * it can be destroyed. + */ + if (S_ISDIR(VFS_I(target_ip)->i_mode) && + (!xfs_dir_isempty(target_ip) || + (VFS_I(target_ip)->i_nlink > 2))) { + error = -EEXIST; + goto out_trans_cancel; + } + } + + /* + * Directory entry creation below may acquire the AGF. Remove + * the whiteout from the unlinked list first to preserve correct + * AGI/AGF locking order. This dirties the transaction so failures + * after this point will abort and log recovery will clean up the + * mess. + * + * For whiteouts, we need to bump the link count on the whiteout + * inode. After this point, we have a real link, clear the tmpfile + * state flag from the inode so it doesn't accidentally get misused + * in future. + */ + if (wip) { + ASSERT(VFS_I(wip)->i_nlink == 0); + error = xfs_iunlink_remove(tp, wip); + if (error) + goto out_trans_cancel; + + xfs_bumplink(tp, wip); + xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE); + VFS_I(wip)->i_state &= ~I_LINKABLE; + } + + /* + * Set up the target. + */ + if (target_ip == NULL) { /* * If target does not exist and the rename crosses * directories, adjust the target directory link count @@ -3067,22 +3108,6 @@ xfs_rename( goto out_bmap_cancel; } } else { /* target_ip != NULL */ - /* - * If target exists and it's a directory, check that both - * target and source are directories and that target can be - * destroyed, or that neither is a directory. - */ - if (S_ISDIR(VFS_I(target_ip)->i_mode)) { - /* - * Make sure target dir is empty. - */ - if (!(xfs_dir_isempty(target_ip)) || - (VFS_I(target_ip)->i_nlink > 2)) { - error = -EEXIST; - goto out_trans_cancel; - } - } - /* * Link the source inode under the target name. * If the source inode is a directory and we are moving @@ -3175,32 +3200,6 @@ xfs_rename( if (error) goto out_bmap_cancel; - /* - * For whiteouts, we need to bump the link count on the whiteout inode. - * This means that failures all the way up to this point leave the inode - * on the unlinked list and so cleanup is a simple matter of dropping - * the remaining reference to it. If we fail here after bumping the link - * count, we're shutting down the filesystem so we'll never see the - * intermediate state on disk. - */ - if (wip) { - ASSERT(VFS_I(wip)->i_nlink == 0); - error = xfs_bumplink(tp, wip); - if (error) - goto out_bmap_cancel; - error = xfs_iunlink_remove(tp, wip); - if (error) - goto out_bmap_cancel; - xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE); - - /* - * Now we have a real link, clear the "I'm a tmpfile" state - * flag from the inode so it doesn't accidentally get misused in - * future. - */ - VFS_I(wip)->i_state &= ~I_LINKABLE; - } - xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); if (new_parent) diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 4e768e606998abe5e4f2587cdf5e834930c280b2..360e32220f93d631e6a317c329d1362f0307e1a4 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -608,6 +608,7 @@ xfs_log_mount( xfs_daddr_t blk_offset, int num_bblks) { + bool fatal = xfs_sb_version_hascrc(&mp->m_sb); int error = 0; int min_logfsbs; @@ -659,9 +660,20 @@ xfs_log_mount( XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks), XFS_MAX_LOG_BYTES); error = -EINVAL; + } else if (mp->m_sb.sb_logsunit > 1 && + mp->m_sb.sb_logsunit % mp->m_sb.sb_blocksize) { + xfs_warn(mp, + "log stripe unit %u bytes must be a multiple of block size", + mp->m_sb.sb_logsunit); + error = -EINVAL; + fatal = true; } if (error) { - if (xfs_sb_version_hascrc(&mp->m_sb)) { + /* + * Log check errors are always fatal on v5; or whenever bad + * metadata leads to a crash. + */ + if (fatal) { xfs_crit(mp, "AAIEEE! Log failed size checks. Abort!"); ASSERT(0); goto out_free_log; diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 37e603bf159137dfd38a1210b5d0bb31e5f4829f..db7f9fdd20a30d3761a316aac0496b8377e7d049 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -1125,6 +1125,7 @@ xfs_reflink_remap_extent( uirec.br_startblock = irec->br_startblock + rlen; uirec.br_startoff = irec->br_startoff + rlen; uirec.br_blockcount = unmap_len - rlen; + uirec.br_state = irec->br_state; unmap_len = rlen; /* If this isn't a real mapping, we're done. */ diff --git a/gen_headers_arm.bp b/gen_headers_arm.bp index d56ace0fe65abce18a735bf0ce8200d9b316ac41..b81da02ec256d985b2d7251734f8526474e7430e 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -927,6 +927,7 @@ gen_headers_out_arm = [ "linux/usb/g_printer.h", "linux/usb/gadgetfs.h", "linux/usb/midi.h", + "linux/usb/raw_gadget.h", "linux/usb/tmc.h", "linux/usb/usb_ctrl_qti.h", "linux/usb/video.h", @@ -943,6 +944,7 @@ gen_headers_out_arm = [ "linux/netfilter/ipset/ip_set_bitmap.h", "linux/netfilter/ipset/ip_set_hash.h", "linux/netfilter/ipset/ip_set_list.h", + "linux/msm_eth.h", // From arch/arm/include/uapi/**/*.h diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index c2beed537f2fd535c2d0bac3c7b88b473d6b10c3..946a1be542bfb0d36a627d8fda053cdc9dbe86b9 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -922,6 +922,7 @@ gen_headers_out_arm64 = [ "linux/usb/g_printer.h", "linux/usb/gadgetfs.h", "linux/usb/midi.h", + "linux/usb/raw_gadget.h", "linux/usb/tmc.h", "linux/usb/usb_ctrl_qti.h", "linux/usb/video.h", @@ -938,6 +939,7 @@ gen_headers_out_arm64 = [ "linux/netfilter/ipset/ip_set_bitmap.h", "linux/netfilter/ipset/ip_set_hash.h", "linux/netfilter/ipset/ip_set_list.h", + "linux/msm_eth.h", // From arch/arm64/include/uapi/**/*.h diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 4f077edb9b81b8086153609d6b4b22b4a22b96e0..71fadbe77e211bee751d292eb9a8e5e4862a3b20 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -556,11 +556,12 @@ typedef u64 acpi_integer; #define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) /* - * Algorithm to obtain access bit width. + * Algorithm to obtain access bit or byte width. * Can be used with access_width of struct acpi_generic_address and access_size of * struct acpi_resource_generic_register. */ #define ACPI_ACCESS_BIT_WIDTH(size) (1 << ((size) + 2)) +#define ACPI_ACCESS_BYTE_WIDTH(size) (1 << ((size) - 1)) /******************************************************************************* * diff --git a/include/acpi/processor.h b/include/acpi/processor.h index d591bb77f592b21a56a0496d223ac0455b31b359..f4bff23135479fba812e9b9c8c821e7cacefbebe 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -291,6 +291,14 @@ static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx } #endif +static inline int call_on_cpu(int cpu, long (*fn)(void *), void *arg, + bool direct) +{ + if (direct || (is_percpu_thread() && cpu == smp_processor_id())) + return fn(arg); + return work_on_cpu(cpu, fn, arg); +} + /* in processor_perflib.c */ #ifdef CONFIG_CPU_FREQ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index e60ea67cffa4a53900a36e9ae85f760e33f6fa8d..3972a2a9026817a65b2d549ae0982fe2e97093f0 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -65,11 +65,11 @@ * .data. We don't want to pull in .data..other sections, which Linux * has defined. Same for text and bss. */ -#ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION +#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG) #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* #define TEXT_CFI_MAIN .text.cfi .text.[0-9a-zA-Z_]*.cfi -#define DATA_MAIN .data .data.[0-9a-zA-Z_]* -#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* +#define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..compoundliteral* .data..L* +#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..compoundliteral* .bss..L* #else #define TEXT_MAIN .text #define TEXT_CFI_MAIN .text.cfi diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 5f821a9b3a1fa8110186c964a706805714a33966..49fdce1f5941950b8e86cede33894f25f186d7c4 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -343,6 +343,22 @@ struct ttm_bo_driver { uint32_t page_flags, struct page *dummy_read_page); + /** + * ttm_tt_create2 + * + * @bo: pointer to a struct ttm_buffer_object + * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags. + * @dummy_read_page: See struct ttm_bo_device. + * + * Create a struct ttm_tt to back data with system memory pages. + * No pages are actually allocated. + * Returns: + * NULL: Out of memory. + */ + struct ttm_tt *(*ttm_tt_create2)(struct ttm_buffer_object *bo, + uint32_t page_flags, + struct page *dummy_read_page); + /** * ttm_tt_populate * diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h index e0970a578188ccaf563340f115e2aaeadb65267e..a7207a965466322c20ab9dfe9e19698f6072599f 100644 --- a/include/keys/big_key-type.h +++ b/include/keys/big_key-type.h @@ -21,6 +21,6 @@ extern void big_key_free_preparse(struct key_preparsed_payload *prep); extern void big_key_revoke(struct key *key); extern void big_key_destroy(struct key *key); extern void big_key_describe(const struct key *big_key, struct seq_file *m); -extern long big_key_read(const struct key *key, char __user *buffer, size_t buflen); +extern long big_key_read(const struct key *key, char *buffer, size_t buflen); #endif /* _KEYS_BIG_KEY_TYPE_H */ diff --git a/include/keys/user-type.h b/include/keys/user-type.h index 12babe9915944f84a040199451124763d15d4bd0..0d8f3cd3056f01ef74acdf9e63c80d16755607f3 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h @@ -45,8 +45,7 @@ extern int user_update(struct key *key, struct key_preparsed_payload *prep); extern void user_revoke(struct key *key); extern void user_destroy(struct key *key); extern void user_describe(const struct key *user, struct seq_file *m); -extern long user_read(const struct key *key, - char __user *buffer, size_t buflen); +extern long user_read(const struct key *key, char *buffer, size_t buflen); static inline const struct user_key_payload *user_key_payload_rcu(const struct key *key) { diff --git a/include/linux/bio-crypt-ctx.h b/include/linux/bio-crypt-ctx.h new file mode 100644 index 0000000000000000000000000000000000000000..45d331bcc2e4386782ae974f63cb1802715ed7cd --- /dev/null +++ b/include/linux/bio-crypt-ctx.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#ifndef __LINUX_BIO_CRYPT_CTX_H +#define __LINUX_BIO_CRYPT_CTX_H + +#include + +enum blk_crypto_mode_num { + BLK_ENCRYPTION_MODE_INVALID, + BLK_ENCRYPTION_MODE_AES_256_XTS, + BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV, + BLK_ENCRYPTION_MODE_ADIANTUM, + BLK_ENCRYPTION_MODE_MAX, +}; + +#ifdef CONFIG_BLOCK +#include + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + +#define BLK_CRYPTO_MAX_KEY_SIZE 64 +#define BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE 128 + +/** + * struct blk_crypto_key - an inline encryption key + * @crypto_mode: encryption algorithm this key is for + * @data_unit_size: the data unit size for all encryption/decryptions with this + * key. This is the size in bytes of each individual plaintext and + * ciphertext. This is always a power of 2. It might be e.g. the + * filesystem block size or the disk sector size. + * @data_unit_size_bits: log2 of data_unit_size + * @size: size of this key in bytes (determined by @crypto_mode) + * @hash: hash of this key, for keyslot manager use only + * @is_hw_wrapped: @raw points to a wrapped key to be used by an inline + * encryption hardware that accepts wrapped keys. + * @raw: the raw bytes of this key. Only the first @size bytes are used. + * + * A blk_crypto_key is immutable once created, and many bios can reference it at + * the same time. It must not be freed until all bios using it have completed. + */ +struct blk_crypto_key { + enum blk_crypto_mode_num crypto_mode; + unsigned int data_unit_size; + unsigned int data_unit_size_bits; + unsigned int size; + + /* + * Hack to avoid breaking KMI: pack both hash and dun_bytes into the + * hash field... + */ +#define BLK_CRYPTO_KEY_HASH_MASK 0xffffff +#define BLK_CRYPTO_KEY_DUN_BYTES_SHIFT 24 + unsigned int hash; + + bool is_hw_wrapped; + u8 raw[BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE]; +}; + +#define BLK_CRYPTO_MAX_IV_SIZE 32 +#define BLK_CRYPTO_DUN_ARRAY_SIZE (BLK_CRYPTO_MAX_IV_SIZE/sizeof(u64)) + +static inline void +blk_crypto_key_set_hash_and_dun_bytes(struct blk_crypto_key *key, + u32 hash, unsigned int dun_bytes) +{ + key->hash = (dun_bytes << BLK_CRYPTO_KEY_DUN_BYTES_SHIFT) | + (hash & BLK_CRYPTO_KEY_HASH_MASK); +} + +static inline u32 +blk_crypto_key_hash(const struct blk_crypto_key *key) +{ + return key->hash & BLK_CRYPTO_KEY_HASH_MASK; +} + +static inline unsigned int +blk_crypto_key_dun_bytes(const struct blk_crypto_key *key) +{ + return key->hash >> BLK_CRYPTO_KEY_DUN_BYTES_SHIFT; +} + +/** + * struct bio_crypt_ctx - an inline encryption context + * @bc_key: the key, algorithm, and data unit size to use + * @bc_keyslot: the keyslot that has been assigned for this key in @bc_ksm, + * or -1 if no keyslot has been assigned yet. + * @bc_dun: the data unit number (starting IV) to use + * @bc_ksm: the keyslot manager into which the key has been programmed with + * @bc_keyslot, or NULL if this key hasn't yet been programmed. + * + * A bio_crypt_ctx specifies that the contents of the bio will be encrypted (for + * write requests) or decrypted (for read requests) inline by the storage device + * or controller, or by the crypto API fallback. + */ +struct bio_crypt_ctx { + const struct blk_crypto_key *bc_key; + int bc_keyslot; + + /* Data unit number */ + u64 bc_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + + /* + * The keyslot manager where the key has been programmed + * with keyslot. + */ + struct keyslot_manager *bc_ksm; +}; + +int bio_crypt_ctx_init(void); + +struct bio_crypt_ctx *bio_crypt_alloc_ctx(gfp_t gfp_mask); + +void bio_crypt_free_ctx(struct bio *bio); + +static inline bool bio_has_crypt_ctx(struct bio *bio) +{ + return bio->bi_crypt_context; +} + +void bio_crypt_clone(struct bio *dst, struct bio *src, gfp_t gfp_mask); + +static inline void bio_crypt_set_ctx(struct bio *bio, + const struct blk_crypto_key *key, + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE], + gfp_t gfp_mask) +{ + struct bio_crypt_ctx *bc = bio_crypt_alloc_ctx(gfp_mask); + + bc->bc_key = key; + memcpy(bc->bc_dun, dun, sizeof(bc->bc_dun)); + bc->bc_ksm = NULL; + bc->bc_keyslot = -1; + + bio->bi_crypt_context = bc; +} + +void bio_crypt_ctx_release_keyslot(struct bio_crypt_ctx *bc); + +int bio_crypt_ctx_acquire_keyslot(struct bio_crypt_ctx *bc, + struct keyslot_manager *ksm); + +struct request; +bool bio_crypt_should_process(struct request *rq); + +static inline bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc, + unsigned int bytes, + u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]) +{ + int i = 0; + unsigned int inc = bytes >> bc->bc_key->data_unit_size_bits; + + while (i < BLK_CRYPTO_DUN_ARRAY_SIZE) { + if (bc->bc_dun[i] + inc != next_dun[i]) + return false; + inc = ((bc->bc_dun[i] + inc) < inc); + i++; + } + + return true; +} + + +static inline void bio_crypt_dun_increment(u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE], + unsigned int inc) +{ + int i = 0; + + while (inc && i < BLK_CRYPTO_DUN_ARRAY_SIZE) { + dun[i] += inc; + inc = (dun[i] < inc); + i++; + } +} + +static inline void bio_crypt_advance(struct bio *bio, unsigned int bytes) +{ + struct bio_crypt_ctx *bc = bio->bi_crypt_context; + + if (!bc) + return; + + bio_crypt_dun_increment(bc->bc_dun, + bytes >> bc->bc_key->data_unit_size_bits); +} + +bool bio_crypt_ctx_compatible(struct bio *b_1, struct bio *b_2); + +bool bio_crypt_ctx_mergeable(struct bio *b_1, unsigned int b1_bytes, + struct bio *b_2); + +#else /* CONFIG_BLK_INLINE_ENCRYPTION */ +static inline int bio_crypt_ctx_init(void) +{ + return 0; +} + +static inline bool bio_has_crypt_ctx(struct bio *bio) +{ + return false; +} + +static inline void bio_crypt_clone(struct bio *dst, struct bio *src, + gfp_t gfp_mask) { } + +static inline void bio_crypt_free_ctx(struct bio *bio) { } + +static inline void bio_crypt_advance(struct bio *bio, unsigned int bytes) { } + +static inline bool bio_crypt_ctx_compatible(struct bio *b_1, struct bio *b_2) +{ + return true; +} + +static inline bool bio_crypt_ctx_mergeable(struct bio *b_1, + unsigned int b1_bytes, + struct bio *b_2) +{ + return true; +} + +#endif /* CONFIG_BLK_INLINE_ENCRYPTION */ + +#if IS_ENABLED(CONFIG_DM_DEFAULT_KEY) +static inline void bio_set_skip_dm_default_key(struct bio *bio) +{ + bio->bi_skip_dm_default_key = true; +} + +static inline bool bio_should_skip_dm_default_key(const struct bio *bio) +{ + return bio->bi_skip_dm_default_key; +} + +static inline void bio_clone_skip_dm_default_key(struct bio *dst, + const struct bio *src) +{ + dst->bi_skip_dm_default_key = src->bi_skip_dm_default_key; +} +#else /* CONFIG_DM_DEFAULT_KEY */ +static inline void bio_set_skip_dm_default_key(struct bio *bio) +{ +} + +static inline bool bio_should_skip_dm_default_key(const struct bio *bio) +{ + return false; +} + +static inline void bio_clone_skip_dm_default_key(struct bio *dst, + const struct bio *src) +{ +} +#endif /* !CONFIG_DM_DEFAULT_KEY */ + +#endif /* CONFIG_BLOCK */ + +#endif /* __LINUX_BIO_CRYPT_CTX_H */ diff --git a/include/linux/bio.h b/include/linux/bio.h index bcdbd29052e079b617961f52f70dc59bff6111fd..2e08e3731376e70f3cf4b6027b6f5c1e78b9b537 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_BLOCK @@ -69,9 +70,6 @@ ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) -#define bio_dun(bio) ((bio)->bi_iter.bi_dun) -#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */ -#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio)) /* * Return the data direction, READ or WRITE. @@ -181,11 +179,6 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, { iter->bi_sector += bytes >> 9; -#ifdef CONFIG_PFK - if (iter->bi_dun) - iter->bi_dun += bytes >> 12; -#endif - if (bio_no_advance_iter(bio)) { iter->bi_size -= bytes; iter->bi_done += bytes; diff --git a/include/linux/bitops.h b/include/linux/bitops.h index b767c7ad65c6e95dd0bbd667b9e4c5524fddc34b..c51574fab0b009e728ec74a1e65aa5218b1bc1c2 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -4,7 +4,8 @@ #include #include -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) extern unsigned int __sw_hweight8(unsigned int w); extern unsigned int __sw_hweight16(unsigned int w); diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h new file mode 100644 index 0000000000000000000000000000000000000000..6062002555e10685f5310e4f84c2beeefc1fa222 --- /dev/null +++ b/include/linux/blk-crypto.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __LINUX_BLK_CRYPTO_H +#define __LINUX_BLK_CRYPTO_H + +#include + +#define SECTOR_SHIFT 9 + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + +int blk_crypto_submit_bio(struct bio **bio_ptr); + +bool blk_crypto_endio(struct bio *bio); + +int blk_crypto_init_key(struct blk_crypto_key *blk_key, + const u8 *raw_key, unsigned int raw_key_size, + bool is_hw_wrapped, + enum blk_crypto_mode_num crypto_mode, + unsigned int dun_bytes, + unsigned int data_unit_size); + +int blk_crypto_start_using_mode(enum blk_crypto_mode_num crypto_mode, + unsigned int dun_bytes, + unsigned int data_unit_size, + bool is_hw_wrapped_key, + struct request_queue *q); + +int blk_crypto_evict_key(struct request_queue *q, + const struct blk_crypto_key *key); + +#else /* CONFIG_BLK_INLINE_ENCRYPTION */ + +static inline int blk_crypto_submit_bio(struct bio **bio_ptr) +{ + return 0; +} + +static inline bool blk_crypto_endio(struct bio *bio) +{ + return true; +} + +#endif /* CONFIG_BLK_INLINE_ENCRYPTION */ + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK + +int blk_crypto_fallback_init(void); + +#else /* CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK */ + +static inline int blk_crypto_fallback_init(void) +{ + return 0; +} + +#endif /* CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK */ + +#endif /* __LINUX_BLK_CRYPTO_H */ diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index d24227285a4402e0c64dfc5cfc7e61891f61f74c..41b2e8a10fdb5fed3f67d749dadac2146d31f7bf 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -17,6 +17,7 @@ struct block_device; struct io_context; struct cgroup_subsys_state; typedef void (bio_end_io_t) (struct bio *); +struct bio_crypt_ctx; /* * Block error status values. See block/blk-core:blk_errors for the details. @@ -95,18 +96,19 @@ struct bio { struct blk_issue_stat bi_issue_stat; #endif #endif + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + struct bio_crypt_ctx *bi_crypt_context; +#if IS_ENABLED(CONFIG_DM_DEFAULT_KEY) + bool bi_skip_dm_default_key; +#endif +#endif + union { #if defined(CONFIG_BLK_DEV_INTEGRITY) struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif }; -#ifdef CONFIG_PFK - /* Encryption key to use (NULL if none) */ - const struct blk_encryption_key *bi_crypt_key; -#endif -#ifdef CONFIG_DM_DEFAULT_KEY - int bi_crypt_skip; -#endif unsigned short bi_vcnt; /* how many bio_vec's */ @@ -121,9 +123,7 @@ struct bio { struct bio_vec *bi_io_vec; /* the actual vec list */ struct bio_set *bi_pool; -#ifdef CONFIG_PFK - struct inode *bi_dio_inode; -#endif + /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member @@ -248,13 +248,6 @@ enum req_flag_bits { __REQ_URGENT, /* urgent request */ __REQ_NOWAIT, /* Don't wait if request will block */ - - /* Android specific flags */ - __REQ_NOENCRYPT, /* - * ok to not encrypt (already encrypted at fs - * level) - */ - __REQ_NR_BITS, /* stops here */ }; @@ -272,7 +265,6 @@ enum req_flag_bits { #define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH) #define REQ_RAHEAD (1ULL << __REQ_RAHEAD) #define REQ_BACKGROUND (1ULL << __REQ_BACKGROUND) -#define REQ_NOENCRYPT (1ULL << __REQ_NOENCRYPT) #define REQ_NOUNMAP (1ULL << __REQ_NOUNMAP) #define REQ_NOWAIT (1ULL << __REQ_NOWAIT) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1673d238b60f3242c12bf026074c92943b241757..19c98d619b874c3cdd16d159d52a8b0a54cef489 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -43,6 +43,7 @@ struct pr_ops; struct rq_wb; struct blk_queue_stats; struct blk_stat_callback; +struct keyslot_manager; #define BLKDEV_MIN_RQ 4 #define BLKDEV_MAX_RQ 128 /* Default maximum */ @@ -154,7 +155,6 @@ struct request { unsigned int __data_len; /* total data len */ int tag; sector_t __sector; /* sector cursor */ - u64 __dun; /* dun for UFS */ struct bio *bio; struct bio *biotail; @@ -546,6 +546,11 @@ struct request_queue { */ unsigned int request_fn_active; +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + /* Inline crypto capabilities */ + struct keyslot_manager *ksm; +#endif + unsigned int rq_timeout; int poll_nsec; @@ -653,7 +658,6 @@ struct request_queue { #define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */ #define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */ #define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */ -#define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -753,8 +757,6 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_scsi_passthrough(q) \ test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags) -#define blk_queue_inlinecrypt(q) \ - test_bit(QUEUE_FLAG_INLINECRYPT, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ @@ -1035,11 +1037,6 @@ static inline sector_t blk_rq_pos(const struct request *rq) return rq->__sector; } -static inline sector_t blk_rq_dun(const struct request *rq) -{ - return rq->__dun; -} - static inline unsigned int blk_rq_bytes(const struct request *rq) { return rq->__data_len; diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h index 397c70578b90bede26428eddf2a44282cc33cceb..5f72fc4e3e136083957b979c6b9ed5ac3dd2ebfa 100644 --- a/include/linux/bluetooth-power.h +++ b/include/linux/bluetooth-power.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018,2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -59,6 +59,10 @@ struct bt_power_clk_data { struct bluetooth_power_platform_data { /* Bluetooth reset gpio */ int bt_gpio_sys_rst; + /* Bluetooth 3p3 gpio */ + int bt_gpio_3p3_en; + /* Bluetooth 1p3 gpio */ + int bt_gpio_1p3_en; struct device *slim_dev; /* VDDIO voltage regulator */ struct bt_power_vreg_data *vreg_info; diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index afa37f807f12c1065a44ba35ffe6c88423756fd2..2e1077ea77db07cdc0d06eba4de6083b2810444b 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -187,6 +187,8 @@ struct buffer_head *__getblk_gfp(struct block_device *bdev, sector_t block, void __brelse(struct buffer_head *); void __bforget(struct buffer_head *); void __breadahead(struct block_device *, sector_t block, unsigned int size); +void __breadahead_gfp(struct block_device *, sector_t block, unsigned int size, + gfp_t gfp); struct buffer_head *__bread_gfp(struct block_device *, sector_t block, unsigned size, gfp_t gfp); void invalidate_bh_lrus(void); @@ -319,6 +321,12 @@ sb_breadahead(struct super_block *sb, sector_t block) __breadahead(sb->s_bdev, block, sb->s_blocksize); } +static inline void +sb_breadahead_unmovable(struct super_block *sb, sector_t block) +{ + __breadahead_gfp(sb->s_bdev, block, sb->s_blocksize, 0); +} + static inline struct buffer_head * sb_getblk(struct super_block *sb, sector_t block) { diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 711236dba71d4c278310a77694ebb43bba3bed78..ec8a4d7af6bda55586bc0b0221b3dcfe6e5ab487 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -44,9 +44,6 @@ struct bvec_iter { unsigned int bi_bvec_done; /* number of bytes completed in current bvec */ -#ifdef CONFIG_PFK - u64 bi_dun; /* DUN setting for bio */ -#endif }; /* diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index de0f5fe284906fed5e87b4505ed57d6d5208ac15..a22949de5b4047a06b41c0459a982a61557a966a 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -61,6 +61,7 @@ struct css_task_iter { struct list_head *mg_tasks_head; struct list_head *dying_tasks_head; + struct list_head *cur_tasks_head; struct css_set *cur_cset; struct css_set *cur_dcset; struct task_struct *cur_task; diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 13377c71584afec8e4f1f15753db894729204bf6..b1ddba09711d07fd805f5ef5f32630cef5414ceb 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -331,7 +331,7 @@ unsigned long read_word_at_a_time(const void *addr) * compiler has support to do so. */ #define compiletime_assert(condition, msg) \ - _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__) + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) #define compiletime_assert_atomic_type(t) \ compiletime_assert(__native_word(t), \ diff --git a/include/linux/crypto-qti-common.h b/include/linux/crypto-qti-common.h new file mode 100644 index 0000000000000000000000000000000000000000..dd4122f4d9a87069769aff08ab5d22e1bbdb128d --- /dev/null +++ b/include/linux/crypto-qti-common.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CRYPTO_QTI_COMMON_H +#define _CRYPTO_QTI_COMMON_H + +#include +#include +#include +#include +#include + +#define RAW_SECRET_SIZE 32 +#define QTI_ICE_MAX_BIST_CHECK_COUNT 100 +#define QTI_ICE_TYPE_NAME_LEN 8 + +struct crypto_vops_qti_entry { + void __iomem *icemmio_base; + uint32_t ice_hw_version; + uint8_t ice_dev_type[QTI_ICE_TYPE_NAME_LEN]; + uint32_t flags; +}; + +#if IS_ENABLED(CONFIG_QTI_CRYPTO_COMMON) +// crypto-qti-common.c +int crypto_qti_init_crypto(struct device *dev, void __iomem *mmio_base, + void **priv_data); +int crypto_qti_enable(void *priv_data); +void crypto_qti_disable(void *priv_data); +int crypto_qti_resume(void *priv_data); +int crypto_qti_debug(void *priv_data); +int crypto_qti_keyslot_program(void *priv_data, + const struct blk_crypto_key *key, + unsigned int slot, u8 data_unit_mask, + int capid); +int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot); +int crypto_qti_derive_raw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size); + +#else +static inline int crypto_qti_init_crypto(struct device *dev, + void __iomem *mmio_base, + void **priv_data) +{ + return 0; +} +static inline int crypto_qti_enable(void *priv_data) +{ + return 0; +} +static inline void crypto_qti_disable(void *priv_data) +{ + return 0; +} +static inline int crypto_qti_resume(void *priv_data) +{ + return 0; +} +static inline int crypto_qti_debug(void *priv_data) +{ + return 0; +} +static inline int crypto_qti_keyslot_program(void *priv_data, + const struct blk_crypto_key *key, + unsigned int slot, + u8 data_unit_mask, + int capid) +{ + return 0; +} +static inline int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot) +{ + return 0; +} +static inline int crypto_qti_derive_raw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, + unsigned int secret_size) +{ + return 0; +} + +#endif /* CONFIG_QTI_CRYPTO_COMMON */ + +#endif /* _CRYPTO_QTI_COMMON_H */ diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h index 4635f95000a4c50bff074ac5bb2f174985f7477a..79a6e37a1d6f641bcd56e15af8d2b009cb321f88 100644 --- a/include/linux/devfreq_cooling.h +++ b/include/linux/devfreq_cooling.h @@ -75,7 +75,7 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *dfc); #else /* !CONFIG_DEVFREQ_THERMAL */ -struct thermal_cooling_device * +static inline struct thermal_cooling_device * of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, struct devfreq_cooling_power *dfc_power) { diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index be0eb0118992159e153512bf77cb8a0a65ac299d..52834cd273b437190a62f30b292070f2a56bbd52 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -321,6 +321,12 @@ struct dm_target { * on max_io_len boundary. */ bool split_discard_bios:1; + + /* + * Set if inline crypto capabilities from this target's underlying + * device(s) can be exposed via the device-mapper device. + */ + bool may_passthrough_inline_crypto:1; }; /* Each target can link one of these into the table */ diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 59e6a77064a304a6746a1651f630be9c4b8d3ed6..562dbc88b3cf6aa03eea90d7f93c4395162f136c 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -149,7 +149,7 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0xCC2 +#define APPS_EVENT_LAST_ID 0xCCD #define MSG_SSID_0 0 #define MSG_SSID_0_LAST 134 @@ -928,7 +928,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1CDD, /* EQUIP ID 1 */ + 0x1CE8, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 76647fd57a0e6410c11b8dceb8de9fe0fe2faa09..df0e14110eccbbe4c0756ec0311289b3a8a4ec07 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -417,6 +417,7 @@ struct dma_buf { char *buf_name; ktime_t ktime; const char *name; + spinlock_t name_lock; struct module *owner; struct list_head list_node; void *priv; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 087cbe77686802259b39a36edddfa22ef716cdaa..8089e28539f16e00aaaddbfe62c171f0bda0ae6a 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -677,6 +677,7 @@ struct dma_filter { * @fill_align: alignment shift for memset operations * @dev_id: unique device ID * @dev: struct device reference for dma mapping api + * @owner: owner module (automatically set based on the provided dev) * @src_addr_widths: bit mask of src addr widths the device supports * @dst_addr_widths: bit mask of dst addr widths the device supports * @directions: bit mask of slave direction the device supports since @@ -738,6 +739,7 @@ struct dma_device { int dev_id; struct device *dev; + struct module *owner; u32 src_addr_widths; u32 dst_addr_widths; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 28473899602817afd35ebe544c432a8d6044987b..a5dbb57a687fbaa1be44b06db341016e138a4f65 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -23,6 +23,7 @@ #define NULL_ADDR ((block_t)0) /* used as block_t addresses */ #define NEW_ADDR ((block_t)-1) /* used as block_t addresses */ +#define COMPRESS_ADDR ((block_t)-2) /* used as compressed data flag */ #define F2FS_BYTES_TO_BLK(bytes) ((bytes) >> F2FS_BLKSIZE_BITS) #define F2FS_BLK_TO_BYTES(blk) ((blk) << F2FS_BLKSIZE_BITS) @@ -37,9 +38,6 @@ #define F2FS_MAX_QUOTAS 3 #define F2FS_ENC_UTF8_12_1 1 -#define F2FS_ENC_STRICT_MODE_FL (1 << 0) -#define f2fs_has_strict_mode(sbi) \ - (sbi->s_encoding_flags & F2FS_ENC_STRICT_MODE_FL) #define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */ #define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */ @@ -124,6 +122,7 @@ struct f2fs_super_block { /* * For checkpoint */ +#define CP_RESIZEFS_FLAG 0x00004000 #define CP_DISABLED_QUICK_FLAG 0x00002000 #define CP_DISABLED_FLAG 0x00001000 #define CP_QUOTA_NEED_FSCK_FLAG 0x00000800 @@ -271,6 +270,10 @@ struct f2fs_inode { __le32 i_inode_checksum;/* inode meta checksum */ __le64 i_crtime; /* creation time */ __le32 i_crtime_nsec; /* creation time in nano scale */ + __le64 i_compr_blocks; /* # of compressed blocks */ + __u8 i_compress_algorithm; /* compress algorithm */ + __u8 i_log_cluster_size; /* log of cluster size */ + __le16 i_padding; /* padding */ __le32 i_extra_end[0]; /* for attribute size calculation */ } __packed; __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 9948a8fdde3f3d56486171a90b35467e5bd2c707..ae71a1faca40f5fa56ab0292c6a51d424c27793d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -647,6 +647,7 @@ struct inode { struct rcu_head i_rcu; }; u64 i_version; + atomic64_t i_sequence; /* see futex */ atomic_t i_count; atomic_t i_dio_count; atomic_t i_writecount; @@ -1312,6 +1313,12 @@ extern int send_sigurg(struct fown_struct *fown); #define SB_ACTIVE (1<<30) #define SB_NOUSER (1<<31) +/* These flags relate to encoding and casefolding */ +#define SB_ENC_STRICT_MODE_FL (1 << 0) + +#define sb_has_enc_strict_mode(sb) \ + (sb->s_encoding_flags & SB_ENC_STRICT_MODE_FL) + /* * Umount options */ @@ -1380,6 +1387,10 @@ struct super_block { #endif struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ +#ifdef CONFIG_UNICODE + struct unicode_map *s_encoding; + __u16 s_encoding_flags; +#endif struct list_head s_mounts; /* list of mounts; _not_ for fs use */ struct block_device *s_bdev; struct backing_dev_info *s_bdi; @@ -3060,8 +3071,6 @@ static inline void inode_dio_end(struct inode *inode) wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); } -struct inode *dio_bio_get_inode(struct bio *bio); - extern void inode_set_flags(struct inode *inode, unsigned int flags, unsigned int mask); @@ -3197,6 +3206,20 @@ extern int generic_file_fsync(struct file *, loff_t, loff_t, int); extern int generic_check_addressable(unsigned, u64); +#ifdef CONFIG_UNICODE +extern int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str); +extern int generic_ci_d_compare(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name); +extern bool needs_casefold(const struct inode *dir); +#else +static inline bool needs_casefold(const struct inode *dir) +{ + return 0; +} +#endif +extern void generic_set_encrypted_ci_d_ops(struct inode *dir, + struct dentry *dentry); + #ifdef CONFIG_MIGRATION extern int buffer_migrate_page(struct address_space *, struct page *, struct page *, diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index e65ce4237f52a43cf9b9115a166adc694f77c981..db99db6e9458a0b79b19e967fd3f49141b9c8138 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -20,10 +20,6 @@ #define FS_CRYPTO_BLOCK_SIZE 16 -/* iv sector for security/pfe/pfk_fscrypt.c and f2fs */ -#define PG_DUN(i, p) \ - (((((u64)(i)->i_ino) & 0xffffffff) << 32) | ((p)->index & 0xffffffff)) - struct fscrypt_info; struct fscrypt_str { @@ -69,6 +65,10 @@ struct fscrypt_operations { bool (*has_stable_inodes)(struct super_block *sb); void (*get_ino_and_lblk_bits)(struct super_block *sb, int *ino_bits_ret, int *lblk_bits_ret); + bool (*inline_crypt_enabled)(struct super_block *sb); + int (*get_num_devices)(struct super_block *sb); + void (*get_devices)(struct super_block *sb, + struct request_queue **devs); }; static inline bool fscrypt_has_encryption_key(const struct inode *inode) @@ -77,6 +77,21 @@ static inline bool fscrypt_has_encryption_key(const struct inode *inode) return READ_ONCE(inode->i_crypt_info) != NULL; } +/** + * fscrypt_needs_contents_encryption() - check whether an inode needs + * contents encryption + * + * Return: %true iff the inode is an encrypted regular file and the kernel was + * built with fscrypt support. + * + * If you need to know whether the encrypt bit is set even when the kernel was + * built without fscrypt support, you must use IS_ENCRYPTED() directly instead. + */ +static inline bool fscrypt_needs_contents_encryption(const struct inode *inode) +{ + return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode); +} + static inline bool fscrypt_dummy_context_enabled(struct inode *inode) { return inode->i_sb->s_cop->dummy_context && @@ -124,11 +139,13 @@ static inline struct page *fscrypt_pagecache_page(struct page *bounce_page) } extern void fscrypt_free_bounce_page(struct page *bounce_page); +extern int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags); /* policy.c */ extern int fscrypt_ioctl_set_policy(struct file *, const void __user *); extern int fscrypt_ioctl_get_policy(struct file *, void __user *); extern int fscrypt_ioctl_get_policy_ex(struct file *, void __user *); +extern int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg); extern int fscrypt_has_permitted_context(struct inode *, struct inode *); extern int fscrypt_inherit_context(struct inode *, struct inode *, void *, bool); @@ -160,82 +177,14 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) extern int fscrypt_fname_alloc_buffer(const struct inode *, u32, struct fscrypt_str *); extern void fscrypt_fname_free_buffer(struct fscrypt_str *); -extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, - const struct fscrypt_str *, struct fscrypt_str *); - -#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32 - -/* Extracts the second-to-last ciphertext block; see explanation below */ -#define FSCRYPT_FNAME_DIGEST(name, len) \ - ((name) + round_down((len) - FS_CRYPTO_BLOCK_SIZE - 1, \ - FS_CRYPTO_BLOCK_SIZE)) - -#define FSCRYPT_FNAME_DIGEST_SIZE FS_CRYPTO_BLOCK_SIZE - -/** - * fscrypt_digested_name - alternate identifier for an on-disk filename - * - * When userspace lists an encrypted directory without access to the key, - * filenames whose ciphertext is longer than FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE - * bytes are shown in this abbreviated form (base64-encoded) rather than as the - * full ciphertext (base64-encoded). This is necessary to allow supporting - * filenames up to NAME_MAX bytes, since base64 encoding expands the length. - * - * To make it possible for filesystems to still find the correct directory entry - * despite not knowing the full on-disk name, we encode any filesystem-specific - * 'hash' and/or 'minor_hash' which the filesystem may need for its lookups, - * followed by the second-to-last ciphertext block of the filename. Due to the - * use of the CBC-CTS encryption mode, the second-to-last ciphertext block - * depends on the full plaintext. (Note that ciphertext stealing causes the - * last two blocks to appear "flipped".) This makes accidental collisions very - * unlikely: just a 1 in 2^128 chance for two filenames to collide even if they - * share the same filesystem-specific hashes. - * - * However, this scheme isn't immune to intentional collisions, which can be - * created by anyone able to create arbitrary plaintext filenames and view them - * without the key. Making the "digest" be a real cryptographic hash like - * SHA-256 over the full ciphertext would prevent this, although it would be - * less efficient and harder to implement, especially since the filesystem would - * need to calculate it for each directory entry examined during a search. - */ -struct fscrypt_digested_name { - u32 hash; - u32 minor_hash; - u8 digest[FSCRYPT_FNAME_DIGEST_SIZE]; -}; - -/** - * fscrypt_match_name() - test whether the given name matches a directory entry - * @fname: the name being searched for - * @de_name: the name from the directory entry - * @de_name_len: the length of @de_name in bytes - * - * Normally @fname->disk_name will be set, and in that case we simply compare - * that to the name stored in the directory entry. The only exception is that - * if we don't have the key for an encrypted directory and a filename in it is - * very long, then we won't have the full disk_name and we'll instead need to - * match against the fscrypt_digested_name. - * - * Return: %true if the name matches, otherwise %false. - */ -static inline bool fscrypt_match_name(const struct fscrypt_name *fname, - const u8 *de_name, u32 de_name_len) -{ - if (unlikely(!fname->disk_name.name)) { - const struct fscrypt_digested_name *n = - (const void *)fname->crypto_buf.name; - if (WARN_ON_ONCE(fname->usr_fname->name[0] != '_')) - return false; - if (de_name_len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) - return false; - return !memcmp(FSCRYPT_FNAME_DIGEST(de_name, de_name_len), - n->digest, FSCRYPT_FNAME_DIGEST_SIZE); - } - - if (de_name_len != fname->disk_name.len) - return false; - return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len); -} +extern int fscrypt_fname_disk_to_usr(const struct inode *inode, + u32 hash, u32 minor_hash, + const struct fscrypt_str *iname, + struct fscrypt_str *oname); +extern bool fscrypt_match_name(const struct fscrypt_name *fname, + const u8 *de_name, u32 de_name_len); +extern u64 fscrypt_fname_siphash(const struct inode *dir, + const struct qstr *name); /* bio.c */ extern void fscrypt_decrypt_bio(struct bio *); @@ -253,6 +202,8 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir, unsigned int flags); extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry, struct fscrypt_name *fname); +extern int fscrypt_prepare_setflags(struct inode *inode, + unsigned int oldflags, unsigned int flags); extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, unsigned int max_len, struct fscrypt_str *disk_link); @@ -269,6 +220,11 @@ static inline bool fscrypt_has_encryption_key(const struct inode *inode) return false; } +static inline bool fscrypt_needs_contents_encryption(const struct inode *inode) +{ + return false; +} + static inline bool fscrypt_dummy_context_enabled(struct inode *inode) { return false; @@ -348,6 +304,11 @@ static inline int fscrypt_ioctl_get_policy_ex(struct file *filp, return -EOPNOTSUPP; } +static inline int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg) +{ + return -EOPNOTSUPP; +} + static inline int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) { @@ -452,7 +413,7 @@ static inline void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) return; } -static inline int fscrypt_fname_disk_to_usr(struct inode *inode, +static inline int fscrypt_fname_disk_to_usr(const struct inode *inode, u32 hash, u32 minor_hash, const struct fscrypt_str *iname, struct fscrypt_str *oname) @@ -469,6 +430,13 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len); } +static inline u64 fscrypt_fname_siphash(const struct inode *dir, + const struct qstr *name) +{ + WARN_ON_ONCE(1); + return 0; +} + /* bio.c */ static inline void fscrypt_decrypt_bio(struct bio *bio) { @@ -511,6 +479,13 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, return -EOPNOTSUPP; } +static inline int fscrypt_prepare_setflags(struct inode *inode, + unsigned int oldflags, + unsigned int flags) +{ + return 0; +} + static inline int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, unsigned int max_len, @@ -537,6 +512,93 @@ static inline const char *fscrypt_get_symlink(struct inode *inode, } #endif /* !CONFIG_FS_ENCRYPTION */ +/* inline_crypt.c */ +#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT +extern bool fscrypt_inode_uses_inline_crypto(const struct inode *inode); + +extern bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode); + +extern void fscrypt_set_bio_crypt_ctx(struct bio *bio, + const struct inode *inode, + u64 first_lblk, gfp_t gfp_mask); + +extern void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio, + const struct buffer_head *first_bh, + gfp_t gfp_mask); + +extern bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, + u64 next_lblk); + +extern bool fscrypt_mergeable_bio_bh(struct bio *bio, + const struct buffer_head *next_bh); + +bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter); + +int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, + int nr_pages); + +#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ +static inline bool fscrypt_inode_uses_inline_crypto(const struct inode *inode) +{ + return false; +} + +static inline bool fscrypt_inode_uses_fs_layer_crypto(const struct inode *inode) +{ + return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode); +} + +static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio, + const struct inode *inode, + u64 first_lblk, gfp_t gfp_mask) { } + +static inline void fscrypt_set_bio_crypt_ctx_bh( + struct bio *bio, + const struct buffer_head *first_bh, + gfp_t gfp_mask) { } + +static inline bool fscrypt_mergeable_bio(struct bio *bio, + const struct inode *inode, + u64 next_lblk) +{ + return true; +} + +static inline bool fscrypt_mergeable_bio_bh(struct bio *bio, + const struct buffer_head *next_bh) +{ + return true; +} + +static inline bool fscrypt_dio_supported(struct kiocb *iocb, + struct iov_iter *iter) +{ + const struct inode *inode = file_inode(iocb->ki_filp); + + return !fscrypt_needs_contents_encryption(inode); +} + +static inline int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, + int nr_pages) +{ + return nr_pages; +} +#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_DM_DEFAULT_KEY) +static inline bool +fscrypt_inode_should_skip_dm_default_key(const struct inode *inode) +{ + return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode); +} +#else +static inline bool +fscrypt_inode_should_skip_dm_default_key(const struct inode *inode) +{ + return false; +} +#endif + /** * fscrypt_require_key - require an inode's encryption key * @inode: the inode we need the key for @@ -635,8 +697,9 @@ static inline int fscrypt_prepare_rename(struct inode *old_dir, * filenames are presented in encrypted form. Therefore, we'll try to set up * the directory's encryption key, but even without it the lookup can continue. * - * This also installs a custom ->d_revalidate() method which will invalidate the - * dentry if it was created without the key and the key is later added. + * After calling this function, a filesystem should ensure that it's dentry + * operations contain fscrypt_d_revalidate if DCACHE_ENCRYPTED_NAME was set, + * so that the dentry can be invalidated if the key is later added. * * Return: 0 on success; -ENOENT if key is unavailable but the filename isn't a * correctly formed encoded ciphertext name, so a negative dentry should be @@ -745,33 +808,6 @@ static inline int fscrypt_encrypt_symlink(struct inode *inode, return 0; } -/* fscrypt_ice.c */ -#ifdef CONFIG_PFK -extern int fscrypt_using_hardware_encryption(const struct inode *inode); -extern void fscrypt_set_ice_dun(const struct inode *inode, - struct bio *bio, u64 dun); -extern void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip); -extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted, - int bi_crypt_skip); -#else -static inline int fscrypt_using_hardware_encryption(const struct inode *inode) -{ - return 0; -} - -static inline void fscrypt_set_ice_dun(const struct inode *inode, - struct bio *bio, u64 dun){} - -static inline void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip) -{} - -static inline bool fscrypt_mergeable_bio(struct bio *bio, - u64 dun, bool bio_encrypted, int bi_crypt_skip) -{ - return true; -} -#endif - /* If *pagep is a bounce page, free it and set *pagep to the pagecache page */ static inline void fscrypt_finalize_bounce_page(struct page **pagep) { diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 3b6b8ccebe7d2e33997338ea382f601946a26ab9..ecc604e61d61b9ffcc96946904f5608e837168b5 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -77,6 +77,10 @@ struct fsverity_operations { * * @inode: the inode * @index: 0-based index of the page within the Merkle tree + * @num_ra_pages: The number of Merkle tree pages that should be + * prefetched starting at @index if the page at @index + * isn't already cached. Implementations may ignore this + * argument; it's only a performance optimization. * * This can be called at any time on an open verity file, as well as * between ->begin_enable_verity() and ->end_enable_verity(). It may be @@ -87,7 +91,8 @@ struct fsverity_operations { * Return: the page on success, ERR_PTR() on failure */ struct page *(*read_merkle_tree_page)(struct inode *inode, - pgoff_t index); + pgoff_t index, + unsigned long num_ra_pages); /** * Write a Merkle tree block to the given inode. diff --git a/include/linux/futex.h b/include/linux/futex.h index a4b6cba699bfbd1dd9686741ff116d3c8702a1e7..6adb1ccac603854af0bbb6626e3f240244d23f38 100644 --- a/include/linux/futex.h +++ b/include/linux/futex.h @@ -34,23 +34,26 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, union futex_key { struct { + u64 i_seq; unsigned long pgoff; - struct inode *inode; - int offset; + unsigned int offset; } shared; struct { + union { + struct mm_struct *mm; + u64 __tmp; + }; unsigned long address; - struct mm_struct *mm; - int offset; + unsigned int offset; } private; struct { + u64 ptr; unsigned long word; - void *ptr; - int offset; + unsigned int offset; } both; }; -#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } } +#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = 0ULL } } #ifdef CONFIG_FUTEX enum { diff --git a/include/linux/hid.h b/include/linux/hid.h index 462005543529862d2e29c8af5af08d491485bff3..99c327842f12042adefd932045942f4ce0b72f74 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -478,7 +478,7 @@ struct hid_report_enum { }; #define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ -#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ +#define HID_MAX_BUFFER_SIZE 8192 /* 8kb */ #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ #define HID_OUTPUT_FIFO_SIZE 64 diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 2e179778576cf9fea66c1c080bb09b94b8fce2da..05bb8aad8c51e2cbf08da1244914ccbac39e9193 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -621,6 +621,15 @@ static inline bool ieee80211_is_qos_nullfunc(__le16 fc) cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); } +/** + * ieee80211_is_any_nullfunc - check if frame is regular or QoS nullfunc frame + * @fc: frame control bytes in little-endian byteorder + */ +static inline bool ieee80211_is_any_nullfunc(__le16 fc) +{ + return (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)); +} + /** * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU * @fc: frame control field in little-endian byteorder @@ -1538,6 +1547,106 @@ struct ieee80211_vht_operation { __le16 basic_mcs_set; } __packed; +/** + * struct ieee80211_he_cap_elem - HE capabilities element + * + * This structure is the "HE capabilities element" fixed fields as + * described in P802.11ax_D2.0 section 9.4.2.237.2 and 9.4.2.237.3 + */ +struct ieee80211_he_cap_elem { + u8 mac_cap_info[5]; + u8 phy_cap_info[9]; +} __packed; + +#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5 + +/** + * enum ieee80211_he_mcs_support - HE MCS support definitions + * @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the + * number of streams + * @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported + * @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported + * @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported + * + * These definitions are used in each 2-bit subfield of the rx_mcs_* + * and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are + * both split into 8 subfields by number of streams. These values indicate + * which MCSes are supported for the number of streams the value appears + * for. + */ +enum ieee80211_he_mcs_support { + IEEE80211_HE_MCS_SUPPORT_0_7 = 0, + IEEE80211_HE_MCS_SUPPORT_0_9 = 1, + IEEE80211_HE_MCS_SUPPORT_0_11 = 2, + IEEE80211_HE_MCS_NOT_SUPPORTED = 3, +}; + +/** + * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field + * + * This structure holds the data required for the Tx/Rx HE MCS NSS Support Field + * described in P802.11ax_D2.0 section 9.4.2.237.4 + * + * @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel + * widths less than 80MHz. + * @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel + * widths less than 80MHz. + * @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel + * width 160MHz. + * @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel + * width 160MHz. + * @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for + * channel width 80p80MHz. + * @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for + * channel width 80p80MHz. + */ +struct ieee80211_he_mcs_nss_supp { + __le16 rx_mcs_80; + __le16 tx_mcs_80; + __le16 rx_mcs_160; + __le16 tx_mcs_160; + __le16 rx_mcs_80p80; + __le16 tx_mcs_80p80; +} __packed; + +/** + * struct ieee80211_he_operation - HE capabilities element + * + * This structure is the "HE operation element" fields as + * described in P802.11ax_D2.0 section 9.4.2.238 + */ +struct ieee80211_he_operation { + __le32 he_oper_params; + __le16 he_mcs_nss_set; + /* Optional 0,1,3 or 4 bytes: depends on @he_oper_params */ + u8 optional[0]; +} __packed; + +/** + * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field + * + * This structure is the "MU AC Parameter Record" fields as + * described in P802.11ax_D2.0 section 9.4.2.240 + */ +struct ieee80211_he_mu_edca_param_ac_rec { + u8 aifsn; + u8 ecw_min_max; + u8 mu_edca_timer; +} __packed; + +/** + * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element + * + * This structure is the "MU EDCA Parameter Set element" fields as + * described in P802.11ax_D2.0 section 9.4.2.240 + */ +struct ieee80211_mu_edca_param_set { + u8 mu_qos_info; + struct ieee80211_he_mu_edca_param_ac_rec ac_be; + struct ieee80211_he_mu_edca_param_ac_rec ac_bk; + struct ieee80211_he_mu_edca_param_ac_rec ac_vi; + struct ieee80211_he_mu_edca_param_ac_rec ac_vo; +} __packed; /* 802.11ac VHT Capabilities */ #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 @@ -1576,6 +1685,328 @@ struct ieee80211_vht_operation { #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 +/* 802.11ax HE MAC capabilities */ +#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 +#define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02 +#define IEEE80211_HE_MAC_CAP0_TWT_RES 0x04 +#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP 0x00 +#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1 0x08 +#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2 0x10 +#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3 0x18 +#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK 0x18 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1 0x00 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2 0x20 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4 0x40 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8 0x60 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16 0x80 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32 0xa0 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64 0xc0 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED 0xe0 +#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK 0xe0 + +#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED 0x00 +#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128 0x01 +#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256 0x02 +#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512 0x03 +#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK 0x03 +#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US 0x00 +#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04 +#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08 +#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_1 0x00 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_2 0x10 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_3 0x20 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_4 0x30 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_5 0x40 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_6 0x50 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_7 0x60 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8 0x70 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_MASK 0x70 + +/* Link adaptation is split between byte HE_MAC_CAP1 and + * HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE + * in which case the following values apply: + * 0 = No feedback. + * 1 = reserved. + * 2 = Unsolicited feedback. + * 3 = both + */ +#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80 + +#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01 +#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02 +#define IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED 0x04 +#define IEEE80211_HE_MAC_CAP2_BSR 0x08 +#define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10 +#define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20 +#define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40 +#define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80 + +#define IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU 0x01 +#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02 +#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04 + +/* The maximum length of an A-MDPU is defined by the combination of the Maximum + * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the + * same field in the HE capabilities. + */ +#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_USE_VHT 0x00 +#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_1 0x08 +#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2 0x10 +#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_RESERVED 0x18 +#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK 0x18 +#define IEEE80211_HE_MAC_CAP3_A_AMSDU_FRAG 0x20 +#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40 +#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80 + +#define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 +#define IEEE80211_HE_MAC_CAP4_QTP 0x02 +#define IEEE80211_HE_MAC_CAP4_BQR 0x04 +#define IEEE80211_HE_MAC_CAP4_SR_RESP 0x08 +#define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 +#define IEEE80211_HE_MAC_CAP4_OPS 0x20 +#define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40 + +/* 802.11ax HE PHY capabilities */ +#define IEEE80211_HE_PHY_CAP0_DUAL_BAND 0x01 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 0x10 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x20 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x40 +#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0xfe + +#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01 +#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02 +#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ 0x04 +#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ 0x08 +#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK 0x0f +#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10 +#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20 +#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40 +/* Midamble RX Max NSTS is split between byte #2 and byte #3 */ +#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS 0x80 + +#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS 0x01 +#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02 +#define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04 +#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08 +#define IEEE80211_HE_PHY_CAP2_DOPPLER_TX 0x10 +#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20 + +/* Note that the meaning of UL MU below is different between an AP and a non-AP + * sta, where in the AP case it indicates support for Rx and in the non-AP sta + * case it indicates support for Tx. + */ +#define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO 0x40 +#define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO 0x80 + +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM 0x00 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK 0x01 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK 0x02 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM 0x03 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK 0x03 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 0x00 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2 0x04 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM 0x00 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK 0x08 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK 0x10 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00 +#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20 +#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40 +#define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80 + +#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01 +#define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER 0x02 + +/* Minimal allowed value of Max STS under 80MHz is 3 */ +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 0x10 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6 0x14 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7 0x18 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 0x1c +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK 0x1c + +/* Minimal allowed value of Max STS above 80MHz is 3 */ +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 0x60 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 0x80 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6 0xa0 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7 0xc0 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 0xe0 +#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK 0xe0 + +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1 0x00 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 0x01 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3 0x02 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4 0x03 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5 0x04 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6 0x05 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7 0x06 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8 0x07 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK 0x07 + +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1 0x00 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 0x08 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3 0x10 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4 0x18 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5 0x20 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6 0x28 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7 0x30 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8 0x38 +#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK 0x38 + +#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40 +#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80 + +#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01 +#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02 +#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04 +#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08 +#define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10 +#define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20 +#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40 +#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80 + +#define IEEE80211_HE_PHY_CAP7_SRP_BASED_SR 0x01 +#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR 0x02 +#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_3 0x18 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_4 0x20 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_5 0x28 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_6 0x30 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_7 0x38 +#define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK 0x38 +#define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ 0x40 +#define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ 0x80 + +#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI 0x01 +#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02 +#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04 +#define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08 +#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10 +#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_2X_AND_1XLTF 0x20 + +/* 802.11ax HE TX/RX MCS NSS Support */ +#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3) +#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS (6) +#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS (11) +#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK 0x07c0 +#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK 0xf800 + +/* TX/RX HE MCS Support field Highest MCS subfield encoding */ +enum ieee80211_he_highest_mcs_supported_subfield_enc { + HIGHEST_MCS_SUPPORTED_MCS7 = 0, + HIGHEST_MCS_SUPPORTED_MCS8, + HIGHEST_MCS_SUPPORTED_MCS9, + HIGHEST_MCS_SUPPORTED_MCS10, + HIGHEST_MCS_SUPPORTED_MCS11, +}; + +/* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */ +static inline u8 +ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap) +{ + u8 count = 4; + + if (he_cap->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + count += 4; + + if (he_cap->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + count += 4; + + return count; +} + +/* 802.11ax HE PPE Thresholds */ +#define IEEE80211_PPE_THRES_NSS_SUPPORT_2NSS (1) +#define IEEE80211_PPE_THRES_NSS_POS (0) +#define IEEE80211_PPE_THRES_NSS_MASK (7) +#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU \ + (BIT(5) | BIT(6)) +#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 0x78 +#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS (3) +#define IEEE80211_PPE_THRES_INFO_PPET_SIZE (3) + +/* + * Calculate 802.11ax HE capabilities IE PPE field size + * Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8* + */ +static inline u8 +ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) +{ + u8 n; + + if ((phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) + return 0; + + n = hweight8(ppe_thres_hdr & + IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); + n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_MASK) >> + IEEE80211_PPE_THRES_NSS_POS)); + + /* + * Each pair is 6 bits, and we need to add the 7 "header" bits to the + * total size. + */ + n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7; + n = DIV_ROUND_UP(n, 8); + + return n; +} + +/* HE Operation defines */ +#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x0000003f +#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK 0x000001c0 +#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET 6 +#define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000200 +#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x000ffc00 +#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 10 +#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x000100000 +#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x000200000 +#define IEEE80211_HE_OPERATION_MULTI_BSSID_AP 0x10000000 +#define IEEE80211_HE_OPERATION_TX_BSSID_INDICATOR 0x20000000 +#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x40000000 + +/* + * ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size + * @he_oper_ie: byte data of the He Operations IE, stating from the the byte + * after the ext ID byte. It is assumed that he_oper_ie has at least + * sizeof(struct ieee80211_he_operation) bytes, checked already in + * ieee802_11_parse_elems_crc() + * @return the actual size of the IE data (not including header), or 0 on error + */ +static inline u8 +ieee80211_he_oper_size(const u8 *he_oper_ie) +{ + struct ieee80211_he_operation *he_oper = (void *)he_oper_ie; + u8 oper_len = sizeof(struct ieee80211_he_operation); + u32 he_oper_params; + + /* Make sure the input is not NULL */ + if (!he_oper_ie) + return 0; + + /* Calc required length */ + he_oper_params = le32_to_cpu(he_oper->he_oper_params); + if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) + oper_len += 3; + if (he_oper_params & IEEE80211_HE_OPERATION_MULTI_BSSID_AP) + oper_len++; + + /* Add the first byte (extension ID) to the total length */ + oper_len++; + + return oper_len; +} + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -1991,6 +2422,11 @@ enum ieee80211_eid_ext { WLAN_EID_EXT_FILS_WRAPPED_DATA = 8, WLAN_EID_EXT_FILS_PUBLIC_KEY = 12, WLAN_EID_EXT_FILS_NONCE = 13, + WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14, + WLAN_EID_EXT_HE_CAPABILITY = 35, + WLAN_EID_EXT_HE_OPERATION = 36, + WLAN_EID_EXT_UORA = 37, + WLAN_EID_EXT_HE_MU_EDCA = 38, }; /* Action category code */ diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 39faaaf843e1efb864ad148c710ed9cec7a82381..c91cf2dee12abd9fe4225c7000dcc2c25fbef0ed 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -2,15 +2,10 @@ #ifndef _INET_DIAG_H_ #define _INET_DIAG_H_ 1 +#include #include -struct net; -struct sock; struct inet_hashinfo; -struct nlattr; -struct nlmsghdr; -struct sk_buff; -struct netlink_callback; struct inet_diag_handler { void (*dump)(struct sk_buff *skb, @@ -62,6 +57,17 @@ int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk); void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk); +static inline size_t inet_diag_msg_attrs_size(void) +{ + return nla_total_size(1) /* INET_DIAG_SHUTDOWN */ + + nla_total_size(1) /* INET_DIAG_TOS */ +#if IS_ENABLED(CONFIG_IPV6) + + nla_total_size(1) /* INET_DIAG_TCLASS */ + + nla_total_size(1) /* INET_DIAG_SKV6ONLY */ +#endif + + nla_total_size(4) /* INET_DIAG_MARK */ + + nla_total_size(4); /* INET_DIAG_CLASS_ID */ +} int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, struct inet_diag_msg *r, int ext, struct user_namespace *user_ns, bool net_admin); diff --git a/include/linux/intel-svm.h b/include/linux/intel-svm.h index 99bc5b3ae26e1622f07558c52510c5e351e3cad6..733eaf95e207cd7c91223b01aaf9652b8cac0422 100644 --- a/include/linux/intel-svm.h +++ b/include/linux/intel-svm.h @@ -130,7 +130,7 @@ static inline int intel_svm_unbind_mm(struct device *dev, int pasid) BUG(); } -static int intel_svm_is_pasid_valid(struct device *dev, int pasid) +static inline int intel_svm_is_pasid_valid(struct device *dev, int pasid) { return -EINVAL; } diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index dba15ca8e60bc8b0f0d0faf3ca13c2afcd87c231..1dcd9198beb7faf30a820f65e811ba3eb6d0bea0 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h @@ -8,6 +8,7 @@ enum { ICQ_EXITED = 1 << 2, + ICQ_DESTROYED = 1 << 3, }; /* diff --git a/include/linux/ipa.h b/include/linux/ipa.h index 654f68600adf4dce823dc2b45f00320c73aa038b..f2f4a6bd3d5facb7b1121034ee864caf62e03b63 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -1423,9 +1423,35 @@ struct ipa_socksv5_info { struct ipacm_socksv5_info dl_in; /* output: handle (index) */ - uint32_t handle; + uint16_t handle; }; +struct ipa_ipv6_nat_uc_tmpl { + uint16_t cmd_id; + uint16_t rsv; + uint32_t cmd_param; + uint16_t pkt_count; + uint16_t rsv2; + uint32_t byte_count; + uint64_t private_address_lsb; + uint64_t private_address_msb; + uint64_t public_address_lsb; + uint64_t public_address_msb; + uint16_t private_port; + uint16_t public_port; + uint32_t rsv3; + uint64_t rsv4; + uint64_t rsv5; + uint64_t rsv6; + uint64_t rsv7; + uint64_t rsv8; + uint64_t rsv9; + uint64_t rsv10; + uint64_t rsv11; + uint64_t rsv12; +} __packed; + + #if defined CONFIG_IPA || defined CONFIG_IPA3 diff --git a/include/linux/ipa_uc_offload.h b/include/linux/ipa_uc_offload.h index 2e0905b146053f18e66bc9a3c6c34cd5390bc3d3..e77f38b7c400386b8fbf8260b4260080981d5408 100644 --- a/include/linux/ipa_uc_offload.h +++ b/include/linux/ipa_uc_offload.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,7 @@ enum ipa_uc_offload_proto { IPA_UC_INVALID = 0, IPA_UC_WDI = 1, IPA_UC_NTN = 2, + IPA_UC_NTN_V2X = 3, IPA_UC_MAX_PROT_SIZE }; @@ -95,6 +96,7 @@ struct ntn_buff_smmu_map { * @num_buffers: Rx/Tx buffer pool size (in terms of elements) * @data_buff_size: size of the each data buffer allocated in DDR * @ntn_reg_base_ptr_pa: physical address of the Tx/Rx NTN Ring's + * @u8 db_mode: 0 means irq mode, 1 means db mode * tail pointer */ struct ipa_ntn_setup_info { @@ -117,6 +119,8 @@ struct ipa_ntn_setup_info { u32 data_buff_size; phys_addr_t ntn_reg_base_ptr_pa; + + u8 db_mode; }; /** @@ -182,10 +186,12 @@ struct ipa_uc_offload_conn_out_params { * struct ipa_perf_profile - To set BandWidth profile * * @client: type of "client" (IPA_CLIENT_ODU#_PROD/CONS) + * @proto: uC offload protocol type * @max_supported_bw_mbps: maximum bandwidth needed (in Mbps) */ struct ipa_perf_profile { enum ipa_client_type client; + enum ipa_uc_offload_proto proto; u32 max_supported_bw_mbps; }; diff --git a/include/linux/key-type.h b/include/linux/key-type.h index dfb3ba782d2c7d68cf24b26f4cdb5b4db46d8b2e..535b310a4c3b18759e74d322d6f3757cab99e1d1 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h @@ -125,7 +125,7 @@ struct key_type { * much is copied into the buffer * - shouldn't do the copy if the buffer is NULL */ - long (*read)(const struct key *key, char __user *buffer, size_t buflen); + long (*read)(const struct key *key, char *buffer, size_t buflen); /* handle request_key() for this type instead of invoking * /sbin/request-key (optional) diff --git a/include/linux/key.h b/include/linux/key.h index 3571b7a980cc7a071c5d1dbb3e420e573aa90da3..afe4d6b90cad5f7cbb996bcecdd6b043a7cc3ead 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -346,7 +346,7 @@ static inline key_serial_t key_serial(const struct key *key) extern void key_set_timeout(struct key *, unsigned); extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, - key_perm_t perm); + key_perm_t perm); /* * The permissions required on a key that we're looking up. diff --git a/include/linux/keyslot-manager.h b/include/linux/keyslot-manager.h new file mode 100644 index 0000000000000000000000000000000000000000..57000863beb75c12cc030eba88241a2c4a9b02d4 --- /dev/null +++ b/include/linux/keyslot-manager.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __LINUX_KEYSLOT_MANAGER_H +#define __LINUX_KEYSLOT_MANAGER_H + +#include + +/* Inline crypto feature bits. Must set at least one. */ +enum { + /* Support for standard software-specified keys */ + BLK_CRYPTO_FEATURE_STANDARD_KEYS = BIT(0), + + /* Support for hardware-wrapped keys */ + BLK_CRYPTO_FEATURE_WRAPPED_KEYS = BIT(1), +}; + +#ifdef CONFIG_BLK_INLINE_ENCRYPTION + +struct keyslot_manager; + +/** + * struct keyslot_mgmt_ll_ops - functions to manage keyslots in hardware + * @keyslot_program: Program the specified key into the specified slot in the + * inline encryption hardware. + * @keyslot_evict: Evict key from the specified keyslot in the hardware. + * The key is provided so that e.g. dm layers can evict + * keys from the devices that they map over. + * Returns 0 on success, -errno otherwise. + * @derive_raw_secret: (Optional) Derive a software secret from a + * hardware-wrapped key. Returns 0 on success, -EOPNOTSUPP + * if unsupported on the hardware, or another -errno code. + * + * This structure should be provided by storage device drivers when they set up + * a keyslot manager - this structure holds the function ptrs that the keyslot + * manager will use to manipulate keyslots in the hardware. + */ +struct keyslot_mgmt_ll_ops { + int (*keyslot_program)(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot); + int (*keyslot_evict)(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot); + int (*derive_raw_secret)(struct keyslot_manager *ksm, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, unsigned int secret_size); +}; + +struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, + const struct keyslot_mgmt_ll_ops *ksm_ops, + unsigned int features, + const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], + void *ll_priv_data); + +void keyslot_manager_set_max_dun_bytes(struct keyslot_manager *ksm, + unsigned int max_dun_bytes); + +int keyslot_manager_get_slot_for_key(struct keyslot_manager *ksm, + const struct blk_crypto_key *key); + +void keyslot_manager_get_slot(struct keyslot_manager *ksm, unsigned int slot); + +void keyslot_manager_put_slot(struct keyslot_manager *ksm, unsigned int slot); + +bool keyslot_manager_crypto_mode_supported(struct keyslot_manager *ksm, + enum blk_crypto_mode_num crypto_mode, + unsigned int dun_bytes, + unsigned int data_unit_size, + bool is_hw_wrapped_key); + +int keyslot_manager_evict_key(struct keyslot_manager *ksm, + const struct blk_crypto_key *key); + +void keyslot_manager_reprogram_all_keys(struct keyslot_manager *ksm); + +void *keyslot_manager_private(struct keyslot_manager *ksm); + +void keyslot_manager_destroy(struct keyslot_manager *ksm); + +struct keyslot_manager *keyslot_manager_create_passthrough( + const struct keyslot_mgmt_ll_ops *ksm_ops, + unsigned int features, + const unsigned int crypto_mode_supported[BLK_ENCRYPTION_MODE_MAX], + void *ll_priv_data); + +void keyslot_manager_intersect_modes(struct keyslot_manager *parent, + const struct keyslot_manager *child); + +int keyslot_manager_derive_raw_secret(struct keyslot_manager *ksm, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, unsigned int secret_size); + +#endif /* CONFIG_BLK_INLINE_ENCRYPTION */ + +#endif /* __LINUX_KEYSLOT_MANAGER_H */ diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7668c68ddb5b31c2d97435c719fcccfd17731024..2e06ca46f07c6495f87d3884b517778521b0da19 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -695,7 +695,7 @@ int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len); int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len); struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn); -unsigned long kvm_host_page_size(struct kvm *kvm, gfn_t gfn); +unsigned long kvm_host_page_size(struct kvm_vcpu *vcpu, gfn_t gfn); void mark_page_dirty(struct kvm *kvm, gfn_t gfn); struct kvm_memslots *kvm_vcpu_memslots(struct kvm_vcpu *vcpu); @@ -945,7 +945,7 @@ search_memslots(struct kvm_memslots *slots, gfn_t gfn) start = slot + 1; } - if (gfn >= memslots[start].base_gfn && + if (start < slots->used_slots && gfn >= memslots[start].base_gfn && gfn < memslots[start].base_gfn + memslots[start].npages) { atomic_set(&slots->lru_slot, start); return &memslots[start]; diff --git a/include/linux/libata.h b/include/linux/libata.h index c5188dc389c843863cfd0f603a89b232fa548621..93838d98e3f38cd6a675e38eb4259a251664a4da 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1229,6 +1229,7 @@ struct pci_bits { }; extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); +extern void ata_pci_shutdown_one(struct pci_dev *pdev); extern void ata_pci_remove_one(struct pci_dev *pdev); #ifdef CONFIG_PM diff --git a/include/linux/list_nulls.h b/include/linux/list_nulls.h index 3ef96743db8da3868744efc92d812c9b746bf9c7..1ecd35664e0d31e716e79a676ea856698dad6380 100644 --- a/include/linux/list_nulls.h +++ b/include/linux/list_nulls.h @@ -72,10 +72,10 @@ static inline void hlist_nulls_add_head(struct hlist_nulls_node *n, struct hlist_nulls_node *first = h->first; n->next = first; - n->pprev = &h->first; + WRITE_ONCE(n->pprev, &h->first); h->first = n; if (!is_a_nulls(first)) - first->pprev = &n->next; + WRITE_ONCE(first->pprev, &n->next); } static inline void __hlist_nulls_del(struct hlist_nulls_node *n) @@ -85,13 +85,13 @@ static inline void __hlist_nulls_del(struct hlist_nulls_node *n) WRITE_ONCE(*pprev, next); if (!is_a_nulls(next)) - next->pprev = pprev; + WRITE_ONCE(next->pprev, pprev); } static inline void hlist_nulls_del(struct hlist_nulls_node *n) { __hlist_nulls_del(n); - n->pprev = LIST_POISON2; + WRITE_ONCE(n->pprev, LIST_POISON2); } /** diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index f40789bd5c153654ff358140592147dc11b171c0..7e9f59aeadb6c3b70d75b6a5eed6a865a80ca2ed 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1475,8 +1475,6 @@ union security_list_options { size_t *len); int (*inode_create)(struct inode *dir, struct dentry *dentry, umode_t mode); - int (*inode_post_create)(struct inode *dir, struct dentry *dentry, - umode_t mode); int (*inode_link)(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); int (*inode_unlink)(struct inode *dir, struct dentry *dentry); @@ -1790,7 +1788,6 @@ struct security_hook_heads { struct list_head inode_free_security; struct list_head inode_init_security; struct list_head inode_create; - struct list_head inode_post_create; struct list_head inode_link; struct list_head inode_unlink; struct list_head inode_symlink; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 9c422c96b7183e6c2b506886d0ab6c18b724ccb9..9afb32481bff8e7889307b5de07ee9b2c92e5528 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -357,7 +357,7 @@ struct mhi_controller { /* worker for different state transitions */ struct work_struct st_worker; struct work_struct special_work; - struct workqueue_struct *special_wq; + struct workqueue_struct *wq; wait_queue_head_t state_event; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index ee92081416f3abd3a1a7fe2386ff6b43fd37815a..aded5a8a733dfadd272fdbde7494256e9ac8b983 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -12,6 +12,7 @@ #include #include #include +#include struct mmc_data; struct mmc_request; @@ -169,8 +170,8 @@ struct mmc_request { void (*recovery_notifier)(struct mmc_request *); struct mmc_host *host; struct mmc_cmdq_req *cmdq_req; - struct request *req; + struct request *req; /* Allow other commands during this ongoing data transfer or busy wait */ bool cap_cmd_during_tfr; ktime_t io_start; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 3c2b261b9c7925dbdb649c14af6e4f18e47eec52..ab2c6af4dca16d5d03b8d1810132162f7cdc8004 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -122,6 +122,13 @@ struct mmc_cmdq_host_ops { int (*halt)(struct mmc_host *host, bool halt); void (*reset)(struct mmc_host *host, bool soft); void (*dumpstate)(struct mmc_host *host); + /* + * Update the request queue with keyslot manager details. This keyslot + * manager will be used by block crypto to configure the crypto Engine + * for data encryption. + */ + void (*cqe_crypto_update_queue)(struct mmc_host *host, + struct request_queue *queue); }; struct mmc_host_ops { diff --git a/include/linux/nvme-fc-driver.h b/include/linux/nvme-fc-driver.h index e9c3b98df3e256268d48c6d829fd1d8bd5346dc1..a726f96010d59d9d99eda4e6d5d5ea9776ebdd18 100644 --- a/include/linux/nvme-fc-driver.h +++ b/include/linux/nvme-fc-driver.h @@ -279,8 +279,6 @@ struct nvme_fc_remote_port { * * Host/Initiator Transport Entrypoints/Parameters: * - * @module: The LLDD module using the interface - * * @localport_delete: The LLDD initiates deletion of a localport via * nvme_fc_deregister_localport(). However, the teardown is * asynchronous. This routine is called upon the completion of the @@ -394,8 +392,6 @@ struct nvme_fc_remote_port { * Value is Mandatory. Allowed to be zero. */ struct nvme_fc_port_template { - struct module *module; - /* initiator-based functions */ void (*localport_delete)(struct nvme_fc_local_port *); void (*remoteport_delete)(struct nvme_fc_remote_port *); diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 8712ff70995f42e4357eddb8bd9601bc42b246c0..980beb1d891d1ea56c30a61cc0717b0cd3913145 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -275,4 +275,35 @@ static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c) sizeof(*(p)->member) + __must_be_array((p)->member),\ sizeof(*(p))) +/** check_shl_overflow() - Calculate a left-shifted value and check overflow + * + * @a: Value to be shifted + * @s: How many bits left to shift + * @d: Pointer to where to store the result + * + * Computes *@d = (@a << @s) + * + * Returns true if '*d' cannot hold the result or when 'a << s' doesn't + * make sense. Example conditions: + * - 'a << s' causes bits to be lost when stored in *d. + * - 's' is garbage (e.g. negative) or so large that the result of + * 'a << s' is guaranteed to be 0. + * - 'a' is negative. + * - 'a << s' sets the sign bit, if any, in '*d'. + * + * '*d' will hold the results of the attempted shift, but is not + * considered "safe for use" if false is returned. + */ +#define check_shl_overflow(a, s, d) ({ \ + typeof(a) _a = a; \ + typeof(s) _s = s; \ + typeof(d) _d = d; \ + u64 _a_full = _a; \ + unsigned int _to_shift = \ + _s >= 0 && _s < 8 * sizeof(*d) ? _s : 0; \ + *_d = (_a_full << _to_shift); \ + (_to_shift != _s || *_d < 0 || _a < 0 || \ + (*_d >> _to_shift) != _a); \ +}) + #endif /* __LINUX_OVERFLOW_H */ diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 5de46a658548d5fb3352a3a5fa2195229f799fca..a02794afc4dc3691cdbef0fd24461171f6a6ee7c 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -265,7 +265,7 @@ static inline int TestClearPage##uname(struct page *page) { return 0; } __PAGEFLAG(Locked, locked, PF_NO_TAIL) PAGEFLAG(Waiters, waiters, PF_ONLY_HEAD) __CLEARPAGEFLAG(Waiters, waiters, PF_ONLY_HEAD) -PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND) +PAGEFLAG(Error, error, PF_NO_TAIL) TESTCLEARFLAG(Error, error, PF_NO_TAIL) PAGEFLAG(Referenced, referenced, PF_HEAD) TESTCLEARFLAG(Referenced, referenced, PF_HEAD) __SETPAGEFLAG(Referenced, referenced, PF_HEAD) diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index f7a04e1af11212df4b5c265e66788442462b1a27..abbc74621f380c554390466bfbb26874611b5708 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -63,6 +63,7 @@ struct pci_epc_ops { * @bitmap: bitmap to manage the PCI address space * @pages: number of bits representing the address region * @page_size: size of each page + * @lock: mutex to protect bitmap */ struct pci_epc_mem { phys_addr_t phys_base; @@ -70,6 +71,8 @@ struct pci_epc_mem { unsigned long *bitmap; size_t page_size; int pages; + /* mutex to protect against concurrent access for memory allocation*/ + struct mutex lock; }; /** diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h index 73a7bf30fe9a3fc299812cfbba6ea33a0fde39c5..3f3cece31148db1f2b6f1e52867d2bb51671e913 100644 --- a/include/linux/percpu_counter.h +++ b/include/linux/percpu_counter.h @@ -78,9 +78,9 @@ static inline s64 percpu_counter_read(struct percpu_counter *fbc) */ static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc) { - s64 ret = fbc->count; + /* Prevent reloads of fbc->count */ + s64 ret = READ_ONCE(fbc->count); - barrier(); /* Prevent reloads of fbc->count */ if (ret >= 0) return ret; return 0; diff --git a/include/linux/pfk.h b/include/linux/pfk.h deleted file mode 100644 index bba8fc2681b8d98b563a6b459a403b76da000d73..0000000000000000000000000000000000000000 --- a/include/linux/pfk.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef PFK_H_ -#define PFK_H_ - -#include - -struct ice_crypto_setting; - -#ifdef CONFIG_PFK - -/* - * Default key for inline encryption. - * - * For now only AES-256-XTS is supported, so this is a fixed length. But if - * ever needed, this should be made variable-length with a 'mode' and 'size'. - * (Remember to update pfk_allow_merge_bio() when doing so!) - */ -#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64 - -struct blk_encryption_key { - u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS]; -}; - -int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, - bool *is_pfe, bool async); -int pfk_load_key_end(const struct bio *bio, bool *is_pfe); -int pfk_remove_key(const unsigned char *key, size_t key_size); -int pfk_fbe_clear_key(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size); -bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2); -void pfk_clear_on_reset(void); - -#else -static inline int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async) -{ - return -ENODEV; -} - -static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe) -{ - return -ENODEV; -} - -static inline int pfk_remove_key(const unsigned char *key, size_t key_size) -{ - return -ENODEV; -} - -static inline bool pfk_allow_merge_bio(const struct bio *bio1, - const struct bio *bio2) -{ - return true; -} - -static inline int pfk_fbe_clear_key(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size) -{ - return -ENODEV; -} - -static inline void pfk_clear_on_reset(void) -{} - -#endif /* CONFIG_PFK */ - -#endif /* PFK_H */ diff --git a/include/linux/phy.h b/include/linux/phy.h index f6ec621991735a709af140cc901f25b6f361413c..f7c8e3476fa20d753d0de957cd5d960a5810ab97 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -376,6 +376,7 @@ struct phy_c45_device_ids { * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc. * has_fixups: Set to true if this phy has fixups/quirks. * suspended: Set to true if this phy has been suspended successfully. + * suspended_by_mdio_bus: Set to true if this phy was suspended by MDIO bus. * sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal. * loopback_enabled: Set true if this phy has been loopbacked successfully. * state: state of the PHY for management purposes @@ -415,6 +416,7 @@ struct phy_device { bool is_pseudo_fixed_link; bool has_fixups; bool suspended; + bool suspended_by_mdio_bus; bool sysfs_links; bool loopback_enabled; bool skip_sw_reset; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 891ef068d66f02bb256f075a43a24b7823a982c0..b8c434c34c8c7c97de9c4f2132236dca7f0db8e1 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -59,6 +59,7 @@ enum { POWER_SUPPLY_HEALTH_COLD, POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE, POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE, + POWER_SUPPLY_HEALTH_OVERCURRENT, POWER_SUPPLY_HEALTH_WARM, POWER_SUPPLY_HEALTH_COOL, POWER_SUPPLY_HEALTH_HOT, diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index e23f1e4de5280888cf3a2def080a1536c74c4351..8a2ecede870b89e017bcb6a569a1a905e4931414 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -382,6 +382,7 @@ struct se_geni_rsc { #define TX_EOT (BIT(1)) #define TX_SBE (BIT(2)) #define TX_RESET_DONE (BIT(3)) +#define TX_GENI_CANCEL_IRQ (BIT(14)) /* SE_DMA_RX_IRQ_STAT Register fields */ #define RX_DMA_DONE (BIT(0)) @@ -390,9 +391,20 @@ struct se_geni_rsc { #define RX_RESET_DONE (BIT(3)) #define RX_FLUSH_DONE (BIT(4)) #define RX_GENI_GP_IRQ (GENMASK(10, 5)) -#define RX_GENI_CANCEL_IRQ (BIT(11)) +/* + * QUPs which have HW version <=1.2 11th bit of + * DMA_RX_IRQ_STAT register denotes RX_GENI_CANCEL_IRQ bit. + */ +#define RX_GENI_CANCEL_IRQ(n) (((n.hw_major_ver <= 1) &&\ + (n.hw_minor_ver <= 2)) ? BIT(11) : BIT(14)) #define RX_GENI_GP_IRQ_EXT (GENMASK(13, 12)) +/* DMA DEBUG Register fields */ +#define DMA_TX_ACTIVE (BIT(0)) +#define DMA_RX_ACTIVE (BIT(1)) +#define DMA_TX_STATE (GENMASK(7, 4)) +#define DMA_RX_STATE (GENMASK(11, 8)) + #define DEFAULT_BUS_WIDTH (4) #define DEFAULT_SE_CLK (19200000) diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h index 2dd0a9ed5b361472fbb1794b3b77f96fc69780ce..733fad7dfbed96c0c55f3d6b2f44ca5cede61a86 100644 --- a/include/linux/qed/qed_chain.h +++ b/include/linux/qed/qed_chain.h @@ -97,6 +97,11 @@ struct qed_chain_u32 { u32 cons_idx; }; +struct addr_tbl_entry { + void *virt_addr; + dma_addr_t dma_map; +}; + struct qed_chain { /* fastpath portion of the chain - required for commands such * as produce / consume. @@ -107,10 +112,11 @@ struct qed_chain { /* Fastpath portions of the PBL [if exists] */ struct { - /* Table for keeping the virtual addresses of the chain pages, - * respectively to the physical addresses in the pbl table. + /* Table for keeping the virtual and physical addresses of the + * chain pages, respectively to the physical addresses + * in the pbl table. */ - void **pp_virt_addr_tbl; + struct addr_tbl_entry *pp_addr_tbl; union { struct qed_chain_pbl_u16 u16; @@ -287,7 +293,7 @@ qed_chain_advance_page(struct qed_chain *p_chain, *(u32 *)page_to_inc = 0; page_index = *(u32 *)page_to_inc; } - *p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index]; + *p_next_elem = p_chain->pbl.pp_addr_tbl[page_index].virt_addr; } } @@ -537,7 +543,7 @@ static inline void qed_chain_init_params(struct qed_chain *p_chain, p_chain->pbl_sp.p_phys_table = 0; p_chain->pbl_sp.p_virt_table = NULL; - p_chain->pbl.pp_virt_addr_tbl = NULL; + p_chain->pbl.pp_addr_tbl = NULL; } /** @@ -575,11 +581,11 @@ static inline void qed_chain_init_mem(struct qed_chain *p_chain, static inline void qed_chain_init_pbl_mem(struct qed_chain *p_chain, void *p_virt_pbl, dma_addr_t p_phys_pbl, - void **pp_virt_addr_tbl) + struct addr_tbl_entry *pp_addr_tbl) { p_chain->pbl_sp.p_phys_table = p_phys_pbl; p_chain->pbl_sp.p_virt_table = p_virt_pbl; - p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl; + p_chain->pbl.pp_addr_tbl = pp_addr_tbl; } /** @@ -644,7 +650,7 @@ static inline void *qed_chain_get_last_elem(struct qed_chain *p_chain) break; case QED_CHAIN_MODE_PBL: last_page_idx = p_chain->page_cnt - 1; - p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx]; + p_virt_addr = p_chain->pbl.pp_addr_tbl[last_page_idx].virt_addr; break; } /* p_virt_addr points at this stage to the last page of the chain */ @@ -716,7 +722,7 @@ static inline void qed_chain_pbl_zero_mem(struct qed_chain *p_chain) page_cnt = qed_chain_get_page_cnt(p_chain); for (i = 0; i < page_cnt; i++) - memset(p_chain->pbl.pp_virt_addr_tbl[i], 0, + memset(p_chain->pbl.pp_addr_tbl[i].virt_addr, 0, QED_CHAIN_PAGE_SIZE); } diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h index a10da545b3f670c91caced56b85200f788403dd5..cf64a9492256658b29f524c6f90015c652c4f6f6 100644 --- a/include/linux/rculist_nulls.h +++ b/include/linux/rculist_nulls.h @@ -34,7 +34,7 @@ static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n) { if (!hlist_nulls_unhashed(n)) { __hlist_nulls_del(n); - n->pprev = NULL; + WRITE_ONCE(n->pprev, NULL); } } @@ -66,7 +66,7 @@ static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n) static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n) { __hlist_nulls_del(n); - n->pprev = LIST_POISON2; + WRITE_ONCE(n->pprev, LIST_POISON2); } /** @@ -94,10 +94,10 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, struct hlist_nulls_node *first = h->first; n->next = first; - n->pprev = &h->first; + WRITE_ONCE(n->pprev, &h->first); rcu_assign_pointer(hlist_nulls_first_rcu(h), n); if (!is_a_nulls(first)) - first->pprev = &n->next; + WRITE_ONCE(first->pprev, &n->next); } /** diff --git a/include/linux/sched.h b/include/linux/sched.h index 0a6475eaa1c831a6bcc7e534bd8aeb133b485f71..0e460d26a8cd25f89e3b3d0b71a7358055ebfb43 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1046,8 +1046,8 @@ struct task_struct { struct seccomp seccomp; /* Thread group tracking: */ - u32 parent_exec_id; - u32 self_exec_id; + u64 parent_exec_id; + u64 self_exec_id; /* Protection against (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed, mempolicy: */ spinlock_t alloc_lock; diff --git a/include/linux/security.h b/include/linux/security.h index ecd3b0dd9c120d6c3cc5ffd0bb5cc6db6368f1f2..666c75c2269cae4426135974fc24a8e8b4f60a42 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -31,7 +31,6 @@ #include #include #include -#include struct linux_binprm; struct cred; @@ -271,8 +270,6 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const char **name, void **value, size_t *len); int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode); -int security_inode_post_create(struct inode *dir, struct dentry *dentry, - umode_t mode); int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); int security_inode_unlink(struct inode *dir, struct dentry *dentry); @@ -667,13 +664,6 @@ static inline int security_inode_create(struct inode *dir, return 0; } -static inline int security_inode_post_create(struct inode *dir, - struct dentry *dentry, - umode_t mode) -{ - return 0; -} - static inline int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) diff --git a/include/linux/selection.h b/include/linux/selection.h index 5b278ce99d8d0666ac77bc913133fd3933c1546b..35937a61da0610fd545910497e0b838cdc592445 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -13,8 +13,8 @@ struct tty_struct; -extern struct vc_data *sel_cons; struct tty_struct; +struct vc_data; extern void clear_selection(void); extern int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty); @@ -23,6 +23,8 @@ extern int sel_loadlut(char __user *p); extern int mouse_reporting(void); extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); +bool vc_is_sel(struct vc_data *vc); + extern int console_blanked; extern const unsigned char color_table[]; diff --git a/include/linux/serdev.h b/include/linux/serdev.h index d609e6dc5bad00bb54f9258c077dc3220cbcb938..49f6e382c94e121f050a335f1c2abf26853419e0 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -164,9 +164,21 @@ int serdev_device_add(struct serdev_device *); void serdev_device_remove(struct serdev_device *); struct serdev_controller *serdev_controller_alloc(struct device *, size_t); -int serdev_controller_add(struct serdev_controller *); +int serdev_controller_add_platform(struct serdev_controller *, bool); void serdev_controller_remove(struct serdev_controller *); +/** + * serdev_controller_add() - Add an serdev controller + * @ctrl: controller to be registered. + * + * Register a controller previously allocated via serdev_controller_alloc() with + * the serdev core. + */ +static inline int serdev_controller_add(struct serdev_controller *ctrl) +{ + return serdev_controller_add_platform(ctrl, false); +} + static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl) { struct serdev_device *serdev = ctrl->serdev; diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 341e1a12bfc78c99c62e21857c2f9e304800db52..b5a6719c5b04e0495973f440756b7fe56b33f75e 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -421,4 +421,9 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #define atomic_dec_and_lock(atomic, lock) \ __cond_lock(lock, _atomic_dec_and_lock(atomic, lock)) +extern int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock, + unsigned long *flags); +#define atomic_dec_and_lock_irqsave(atomic, lock, flags) \ + __cond_lock(lock, _atomic_dec_and_lock_irqsave(atomic, lock, &(flags))) + #endif /* __LINUX_SPINLOCK_H */ diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 39c4005a0396b507d246fdae574adb2659fa1560..3dc7d602ec152448dc20a6b4140d208f9b34c9a2 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -200,5 +200,8 @@ struct plat_stmmacenet_data { (struct sk_buff *skb); bool early_eth; bool crc_strip_en; + bool phy_intr_en; + int mac2mac_rgmii_speed; + bool mac2mac_en; }; #endif diff --git a/include/linux/swab.h b/include/linux/swab.h index e466fd159c857d6d7acec6da574c8647067e063a..bcff5149861a9eb0dc2fa3b8da4bf8a80e5dc343 100644 --- a/include/linux/swab.h +++ b/include/linux/swab.h @@ -7,6 +7,7 @@ # define swab16 __swab16 # define swab32 __swab32 # define swab64 __swab64 +# define swab __swab # define swahw32 __swahw32 # define swahb32 __swahb32 # define swab16p __swab16p diff --git a/include/linux/swapops.h b/include/linux/swapops.h index 1d3877c39a000a6e5a4fb7647a38de51c5c47c50..0b8c86096752778374006e9a403685911919ec65 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -377,7 +377,8 @@ static inline void num_poisoned_pages_inc(void) } #endif -#if defined(CONFIG_MEMORY_FAILURE) || defined(CONFIG_MIGRATION) +#if defined(CONFIG_MEMORY_FAILURE) || defined(CONFIG_MIGRATION) || \ + defined(CONFIG_DEVICE_PRIVATE) static inline int non_swap_entry(swp_entry_t entry) { return swp_type(entry) >= MAX_SWAPFILES; diff --git a/include/linux/tty.h b/include/linux/tty.h index 24c7182f115b19e9f5548a0f90d1cd603c4c9c54..3e9c74197a8ffbea1ca39e70ff980420484d208e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -224,6 +224,8 @@ struct tty_port_client_operations { void (*write_wakeup)(struct tty_port *port); }; +extern const struct tty_port_client_operations tty_port_default_client_ops; + struct tty_port { struct tty_bufhead buf; /* Locked internally */ struct tty_struct *tty; /* Back pointer */ diff --git a/include/linux/unicode.h b/include/linux/unicode.h index 990aa97d804962e65ed00e354ba6dd88e14f2bcd..74484d44c7554bdfea1f86a5cebe89809d1bd8e1 100644 --- a/include/linux/unicode.h +++ b/include/linux/unicode.h @@ -27,6 +27,9 @@ int utf8_normalize(const struct unicode_map *um, const struct qstr *str, int utf8_casefold(const struct unicode_map *um, const struct qstr *str, unsigned char *dest, size_t dlen); +int utf8_casefold_hash(const struct unicode_map *um, const void *salt, + struct qstr *str); + struct unicode_map *utf8_load(const char *version); void utf8_unload(struct unicode_map *um); diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 3eee06cb4157d53915b50238cb3c82597609b717..b58cee96cd43126eebaf8167e890e8f9210738ca 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -106,12 +106,13 @@ extern void vunmap(const void *addr); extern int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr, void *kaddr, - unsigned long size); + unsigned long pgoff, unsigned long size); extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, unsigned long pgoff); -void vmalloc_sync_all(void); - +void vmalloc_sync_mappings(void); +void vmalloc_sync_unmappings(void); + /* * Lowlevel-APIs (not for driver use!) */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 3fd07912909cddc74a30a5d3983d906563017e66..a3de234d3350540e9b46128b1e1452753d99451b 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -142,7 +142,7 @@ static inline bool vt_force_oops_output(struct vc_data *vc) return false; } -extern char vt_dont_switch; +extern bool vt_dont_switch; extern int default_utf8; extern int global_cursor_default; diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h index d84d8c301546bb14724ad858b209cebde035cd8d..54f5caaa5cde52672422c6593027feef2d926a98 100644 --- a/include/linux/wakeup_reason.h +++ b/include/linux/wakeup_reason.h @@ -20,13 +20,18 @@ #define MAX_SUSPEND_ABORT_LEN 256 -void log_wakeup_reason(int irq); -int check_wakeup_reason(int irq); - #ifdef CONFIG_SUSPEND +void log_irq_wakeup_reason(int irq); +void log_threaded_irq_wakeup_reason(int irq, int parent_irq); void log_suspend_abort_reason(const char *fmt, ...); +void log_abnormal_wakeup_reason(const char *fmt, ...); +void clear_wakeup_reasons(void); #else +static inline void log_irq_wakeup_reason(int irq) { } +static inline void log_threaded_irq_wakeup_reason(int irq, int parent_irq) { } static inline void log_suspend_abort_reason(const char *fmt, ...) { } +static inline void log_abnormal_wakeup_reason(const char *fmt, ...) { } +static inline void clear_wakeup_reasons(void) { } #endif #endif /* _LINUX_WAKEUP_REASON_H */ diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 8ffa94009d1a956d19894e84eee28ea75f3ae101..76002416cead9be57a9dbe5e0a21a18251e4fe22 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -268,7 +268,7 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, struct v4l2_subdev *__sd; \ \ __v4l2_device_call_subdevs_p(v4l2_dev, __sd, \ - !(grpid) || __sd->grp_id == (grpid), o, f , \ + (grpid) == 0 || __sd->grp_id == (grpid), o, f , \ ##args); \ } while (0) @@ -280,7 +280,7 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, ({ \ struct v4l2_subdev *__sd; \ __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, \ - !(grpid) || __sd->grp_id == (grpid), o, f , \ + (grpid) == 0 || __sd->grp_id == (grpid), o, f , \ ##args); \ }) @@ -294,8 +294,8 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, struct v4l2_subdev *__sd; \ \ __v4l2_device_call_subdevs_p(v4l2_dev, __sd, \ - !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f , \ - ##args); \ + (grpmsk) == 0 || (__sd->grp_id & (grpmsk)), o, \ + f , ##args); \ } while (0) /* @@ -308,8 +308,8 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, ({ \ struct v4l2_subdev *__sd; \ __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, \ - !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f , \ - ##args); \ + (grpmsk) == 0 || (__sd->grp_id & (grpmsk)), o, \ + f , ##args); \ }) /* diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h index d2125f0cc7cd5e3e5ea699d278fec33ed9d97e6e..1584c760b9937f50417a05fd41e2d61161a605e8 100644 --- a/include/media/v4l2-rect.h +++ b/include/media/v4l2-rect.h @@ -75,10 +75,10 @@ static inline void v4l2_rect_map_inside(struct v4l2_rect *r, r->left = boundary->left; if (r->top < boundary->top) r->top = boundary->top; - if (r->left + r->width > boundary->width) - r->left = boundary->width - r->width; - if (r->top + r->height > boundary->height) - r->top = boundary->height - r->height; + if (r->left + r->width > boundary->left + boundary->width) + r->left = boundary->left + boundary->width - r->width; + if (r->top + r->height > boundary->top + boundary->height) + r->top = boundary->top + boundary->height - r->height; } /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9f46a00215a8814eb4d506df3c3f0df6774a9c91..cf0b6f9eff5651732f6869a0757117c404c6706b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -65,6 +65,9 @@ /* Indicate backport support for key configuration for Beacon protection*/ #define CFG80211_BIGTK_CONFIGURATION_SUPPORT 1 +/* Indicate backport support for sband iftype data */ +#define CFG80211_SBAND_IFTYPE_DATA_BACKPORT 1 + /** * DOC: Introduction * @@ -325,6 +328,41 @@ struct ieee80211_sta_vht_cap { struct ieee80211_vht_mcs_info vht_mcs; }; +#define IEEE80211_HE_PPE_THRES_MAX_LEN 25 + +/** + * struct ieee80211_sta_he_cap - STA's HE capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11ax HE capabilities for a STA. + * + * @has_he: true iff HE data is valid. + * @he_cap_elem: Fixed portion of the HE capabilities element. + * @he_mcs_nss_supp: The supported NSS/MCS combinations. + * @ppe_thres: Holds the PPE Thresholds data. + */ +struct ieee80211_sta_he_cap { + bool has_he; + struct ieee80211_he_cap_elem he_cap_elem; + struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp; + u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN]; +}; + +/** + * struct ieee80211_sband_iftype_data + * + * This structure encapsulates sband data that is relevant for the + * interface types defined in @types_mask. Each type in the + * @types_mask must be unique across all instances of iftype_data. + * + * @types_mask: interface types mask + * @he_cap: holds the HE capabilities + */ +struct ieee80211_sband_iftype_data { + u16 types_mask; + struct ieee80211_sta_he_cap he_cap; +}; + /** * struct ieee80211_supported_band - frequency band definition * @@ -341,6 +379,11 @@ struct ieee80211_sta_vht_cap { * @n_bitrates: Number of bitrates in @bitrates * @ht_cap: HT capabilities in this band * @vht_cap: VHT capabilities in this band + * @n_iftype_data: number of iftype data entries + * @iftype_data: interface type data entries. Note that the bits in + * @types_mask inside this structure cannot overlap (i.e. only + * one occurrence of each type is allowed across all instances of + * iftype_data). */ struct ieee80211_supported_band { struct ieee80211_channel *channels; @@ -350,8 +393,55 @@ struct ieee80211_supported_band { int n_bitrates; struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_vht_cap vht_cap; + u16 n_iftype_data; + const struct ieee80211_sband_iftype_data *iftype_data; }; +/** + * ieee80211_get_sband_iftype_data - return sband data for a given iftype + * @sband: the sband to search for the STA on + * @iftype: enum nl80211_iftype + * + * Return: pointer to struct ieee80211_sband_iftype_data, or NULL is none found + */ +static inline const struct ieee80211_sband_iftype_data * +ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband, + u8 iftype) +{ + int i; + + if (WARN_ON(iftype >= NL80211_IFTYPE_MAX)) + return NULL; + + for (i = 0; i < sband->n_iftype_data; i++) { + const struct ieee80211_sband_iftype_data *data = + &sband->iftype_data[i]; + + if (data->types_mask & BIT(iftype)) + return data; + } + + return NULL; +} + +/** + * ieee80211_get_he_sta_cap - return HE capabilities for an sband's STA + * @sband: the sband to search for the STA on + * + * Return: pointer to the struct ieee80211_sta_he_cap, or NULL is none found + */ +static inline const struct ieee80211_sta_he_cap * +ieee80211_get_he_sta_cap(const struct ieee80211_supported_band *sband) +{ + const struct ieee80211_sband_iftype_data *data = + ieee80211_get_sband_iftype_data(sband, NL80211_IFTYPE_STATION); + + if (data && data->he_cap.has_he) + return &data->he_cap; + + return NULL; +} + /** * wiphy_read_of_freq_limits - read frequency limits from device tree * @@ -949,6 +1039,8 @@ enum station_parameters_apply_mask { * @opmode_notif: operating mode field from Operating Mode Notification * @opmode_notif_used: information if operating mode field is used * @support_p2p_ps: information if station supports P2P PS mechanism + * @he_capa: HE capabilities of station + * @he_capa_len: the length of the HE capabilities */ struct station_parameters { const u8 *supported_rates; @@ -976,6 +1068,8 @@ struct station_parameters { u8 opmode_notif; bool opmode_notif_used; int support_p2p_ps; + const struct ieee80211_he_cap_elem *he_capa; + u8 he_capa_len; }; /** @@ -1050,12 +1144,14 @@ int cfg80211_check_station_change(struct wiphy *wiphy, * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval * @RATE_INFO_FLAGS_60G: 60GHz MCS + * @RATE_INFO_FLAGS_HE_MCS: HE MCS information */ enum rate_info_flags { RATE_INFO_FLAGS_MCS = BIT(0), RATE_INFO_FLAGS_VHT_MCS = BIT(1), RATE_INFO_FLAGS_SHORT_GI = BIT(2), RATE_INFO_FLAGS_60G = BIT(3), + RATE_INFO_FLAGS_HE_MCS = BIT(4), }; /** @@ -1069,6 +1165,7 @@ enum rate_info_flags { * @RATE_INFO_BW_40: 40 MHz bandwidth * @RATE_INFO_BW_80: 80 MHz bandwidth * @RATE_INFO_BW_160: 160 MHz bandwidth + * @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation */ enum rate_info_bw { RATE_INFO_BW_20 = 0, @@ -1077,6 +1174,7 @@ enum rate_info_bw { RATE_INFO_BW_40, RATE_INFO_BW_80, RATE_INFO_BW_160, + RATE_INFO_BW_HE_RU, }; /** @@ -1085,10 +1183,14 @@ enum rate_info_bw { * Information about a receiving or transmitting bitrate * * @flags: bitflag of flags from &enum rate_info_flags - * @mcs: mcs index if struct describes a 802.11n bitrate + * @mcs: mcs index if struct describes an HT/VHT/HE rate * @legacy: bitrate in 100kbit/s for 802.11abg - * @nss: number of streams (VHT only) + * @nss: number of streams (VHT & HE only) * @bw: bandwidth (from &enum rate_info_bw) + * @he_gi: HE guard interval (from &enum nl80211_he_gi) + * @he_dcm: HE DCM value + * @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc, + * only valid if bw is %RATE_INFO_BW_HE_RU) */ struct rate_info { u8 flags; @@ -1096,6 +1198,9 @@ struct rate_info { u16 legacy; u8 nss; u8 bw; + u8 he_gi; + u8 he_dcm; + u8 he_ru_alloc; }; /** diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 648caf90ec07a3c001415489cb25c8624d729900..b8fd023ba625a1ead99acf06508a7b9a79805fff 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -102,6 +102,7 @@ struct fib_rule_notifier_info { [FRA_OIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ [FRA_PRIORITY] = { .type = NLA_U32 }, \ [FRA_FWMARK] = { .type = NLA_U32 }, \ + [FRA_TUN_ID] = { .type = NLA_U64 }, \ [FRA_FWMASK] = { .type = NLA_U32 }, \ [FRA_TABLE] = { .type = NLA_U32 }, \ [FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \ diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 227dc0a841728e3298ca50b2d15b0569817934f3..ddf916e5e57d5936012d519750ce9d1cc8ccca5c 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -5,6 +5,7 @@ #include #include #include +#include #include /** @@ -282,4 +283,12 @@ static inline void *skb_flow_dissector_target(struct flow_dissector *flow_dissec return ((char *)target_container) + flow_dissector->offset[key_id]; } +static inline void +flow_dissector_init_keys(struct flow_dissector_key_control *key_control, + struct flow_dissector_key_basic *key_basic) +{ + memset(key_control, 0, sizeof(*key_control)); + memset(key_basic, 0, sizeof(*key_basic)); +} + #endif diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index bee528135cf1c43e0a290a632d8e0705eaa6afd0..9f7f81117434b9b43ac0d998757a0f2673a703a4 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -207,6 +207,7 @@ static inline bool ipv6_anycast_destination(const struct dst_entry *dst, return rt->rt6i_flags & RTF_ANYCAST || (rt->rt6i_dst.plen < 127 && + !(rt->rt6i_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) && ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)); } diff --git a/include/net/tcp.h b/include/net/tcp.h index 99be79730770c02ddedcc68bcfcb299ab3670ad0..2392c6544696ca25a420fd2aab9f66bb356b8425 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -55,7 +55,7 @@ extern struct inet_hashinfo tcp_hashinfo; extern struct percpu_counter tcp_orphan_count; void tcp_time_wait(struct sock *sk, int state, int timeo); -#define MAX_TCP_HEADER (128 + MAX_HEADER) +#define MAX_TCP_HEADER L1_CACHE_ALIGN(128 + MAX_HEADER) #define MAX_TCP_OPTION_SPACE 40 #define TCP_MIN_SND_MSS 48 #define TCP_MIN_GSO_SIZE (TCP_MIN_SND_MSS - MAX_TCP_OPTION_SPACE) diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index f0a01a54bd153cbca39abc9cb8670c2597cdb231..df156f1d50b2d7e74297e2606ec5e4792f86d24e 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -638,7 +638,6 @@ struct iscsi_reject { #define ISCSI_REASON_BOOKMARK_INVALID 9 #define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10 #define ISCSI_REASON_NEGOTIATION_RESET 11 -#define ISCSI_REASON_WAITING_FOR_LOGOUT 12 /* Max. number of Key=Value pairs in a text message */ #define MAX_KEY_VALUE_PAIRS 8192 diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 0472647a9cf79963a92301885e73143cefeacadd..203fec0bd88cd28fc81ffc4765d35c2fe7a50204 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -666,9 +666,6 @@ struct Scsi_Host { /* The controller does not support WRITE SAME */ unsigned no_write_same:1; - /* Inline encryption support? */ - unsigned inlinecrypt_support:1; - unsigned use_blk_mq:1; unsigned use_cmd_list:1; diff --git a/include/soc/qcom/msm_tz_smmu.h b/include/soc/qcom/msm_tz_smmu.h index 54946b9f436a2091ec68acbb5f0f9aeef73d4675..ed7407a0b6c3d6ce9651d7469b4e9bfbcacddf35 100644 --- a/include/soc/qcom/msm_tz_smmu.h +++ b/include/soc/qcom/msm_tz_smmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ #define __MSM_TZ_SMMU_H__ #include +#include enum tz_smmu_device_id { TZ_DEVICE_START = 0, @@ -56,6 +57,21 @@ enum tz_smmu_device_id msm_dev_to_device_id(struct device *dev); int msm_tz_set_cb_format(enum tz_smmu_device_id sec_id, int cbndx); int msm_iommu_sec_pgtbl_init(void); int register_iommu_sec_ptbl(void); +bool arm_smmu_skip_write(void __iomem *addr); +extern void *get_smmu_from_addr(struct iommu_device *iommu, void __iomem *addr); +extern void *arm_smmu_get_by_addr(void __iomem *addr); +/* Donot write to smmu global space with CONFIG_MSM_TZ_SMMU */ +#undef writel_relaxed +#undef writeq_relaxed +#define writel_relaxed(v, c) do { \ + if (!arm_smmu_skip_write(c)) \ + ((void)__raw_writel((u32)cpu_to_le32(v), (c))); \ + } while (0) + +#define writeq_relaxed(v, c) do { \ + if (!arm_smmu_skip_write(c)) \ + ((void)__raw_writeq((u64)cpu_to_le64(v), (c))); \ + } while (0) #else static inline int msm_tz_smmu_atos_start(struct device *dev, int cb_num) diff --git a/include/soc/qcom/qrtr_ethernet.h b/include/soc/qcom/qrtr_ethernet.h new file mode 100644 index 0000000000000000000000000000000000000000..023453eaf0b41a442fb438c02c8028e31e519d33 --- /dev/null +++ b/include/soc/qcom/qrtr_ethernet.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * QRTR-Ethernet API header + */ + +#ifndef _QRTR_ETHERNET_H +#define _QRTR_ETHERNET_H + +#include + +/** + * qrtr_ethernet_cb_info - struct to pass transport layer information to qrtr + * @eth_send: function pointer to send qrtr packets to transport layer + */ +struct qrtr_ethernet_cb_info { + int (*eth_send)(struct sk_buff *skb); +}; + +/** + * eth_adapt_result - struct to pass on buffer from external ap to qrtr + * buf_addr - address of the buffer that holds the data from external ap + * bytes_xferd - size of the above buffer + */ +struct eth_adapt_result { + void *buf_addr; + size_t bytes_xferd; +}; + +#if IS_ENABLED(CONFIG_QRTR_ETHERNET) || IS_ENABLED(CONFIG_QTI_QRTR_ETHERNET) +void qcom_ethernet_init_cb(struct qrtr_ethernet_cb_info *cbinfo); +void qcom_ethernet_qrtr_dl_cb(struct eth_adapt_result *eth_res); +void qcom_ethernet_qrtr_status_cb(unsigned int event); +#else +static inline void qcom_ethernet_init_cb(struct qrtr_ethernet_cb_info *cbinfo) +{ +} +static inline void qcom_ethernet_qrtr_dl_cb(struct eth_adapt_result *eth_res) {} +static inline void qcom_ethernet_qrtr_status_cb(unsigned int event) {} +#endif /* CONFIG_QRTR_ETHERNET or CONFIG_QTI_QRTR_ETHERNET */ + +#endif /* _QRTR_ETHERNET_H */ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 55dc5e9732c9a535ee21e1451b8d0e0dbd91b4fe..b9e3927081d375cd766602027245da0e28f47c04 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -117,10 +117,10 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm429w") #define early_machine_is_sda429w() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda429w") -#define early_machine_is_qcm6125() \ - of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcm6125") -#define early_machine_is_qcs6125() \ - of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs6125") +#define early_machine_is_trinket_iot() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,trinket-iot") +#define early_machine_is_trinketp_iot() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,trinketp-iot") #else #define of_board_is_sim() 0 #define of_board_is_rumi() 0 @@ -168,8 +168,8 @@ #define early_machine_is_sda660() 0 #define early_machine_is_sdm429w() 0 #define early_machine_is_sda429w() 0 -#define early_machine_is_qcm6125() 0 -#define early_machine_is_qcs6125() 0 +#define early_machine_is_trinket_iot() 0 +#define early_machine_is_trinketp_iot() 0 #endif #define PLATFORM_SUBTYPE_MDM 1 @@ -220,8 +220,8 @@ enum msm_cpu { MSM_CPU_SDA660, MSM_CPU_SDM429W, MSM_CPU_SDA429W, - MSM_CPU_QCM6125, - MSM_CPU_QCS6125, + MSM_CPU_TRINKET_IOT, + MSM_CPU_TRINKETP_IOT, }; struct msm_soc_info { diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 9955e0b85de5f1bae0ec7b349ac8107cff129d43..f54a533ecc8dd4655c8b9b5498edc8be37d3a154 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -93,9 +93,9 @@ struct snd_rawmidi_substream { struct list_head list; /* list of all substream for given stream */ int stream; /* direction */ int number; /* substream number */ - unsigned int opened: 1, /* open flag */ - append: 1, /* append flag (merge more streams) */ - active_sensing: 1; /* send active sensing when close */ + bool opened; /* open flag */ + bool append; /* append flag (merge more streams) */ + bool active_sensing; /* send active sensing when close */ int use_count; /* use counter (for output) */ size_t bytes; struct snd_rawmidi *rmidi; diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index cf5f3fff1f1a7cb9930753c8abd88347ee66d048..fd7e4d1df9a15cbd136d9603610b16f7fc6f7afc 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -673,7 +673,7 @@ struct iscsi_session { atomic_t session_logout; atomic_t session_reinstatement; atomic_t session_stop_active; - atomic_t sleep_on_sess_wait_comp; + atomic_t session_close; /* connection list */ struct list_head sess_conn_list; struct list_head cr_active_list; diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 8b95c16b70454ac875ef5ee3ff8d9df16b78e48b..0978bdae2243b5d0b5f1e66ee89752f8daf866c3 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -40,7 +40,7 @@ enum afs_call_trace { EM(afs_call_trace_free, "FREE ") \ EM(afs_call_trace_put, "PUT ") \ EM(afs_call_trace_wake, "WAKE ") \ - E_(afs_call_trace_work, "WORK ") + E_(afs_call_trace_work, "QUEUE") /* * Export enum symbols via userspace. diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 32d0c1fe2bfa7d177ba63a1ca1613cd4f2144c0d..3ebada29a313e4dacb9d73e5446e33d5ae95e438 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -325,7 +325,7 @@ DECLARE_EVENT_CLASS( __entry->extent_type = btrfs_file_extent_type(l, fi); __entry->compression = btrfs_file_extent_compression(l, fi); __entry->extent_start = start; - __entry->extent_end = (start + btrfs_file_extent_inline_len(l, slot, fi)); + __entry->extent_end = (start + btrfs_file_extent_ram_bytes(l, fi)); ), TP_printk_btrfs( diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 4c282573437dac51ce85115bea68a5e77089fd2b..5b95f24125ed5131ff555b832e4bc69a2985243b 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -49,6 +49,7 @@ TRACE_DEFINE_ENUM(CP_SYNC); TRACE_DEFINE_ENUM(CP_RECOVERY); TRACE_DEFINE_ENUM(CP_DISCARD); TRACE_DEFINE_ENUM(CP_TRIMMED); +TRACE_DEFINE_ENUM(CP_PAUSE); #define show_block_type(type) \ __print_symbolic(type, \ @@ -134,13 +135,14 @@ TRACE_DEFINE_ENUM(CP_TRIMMED); { CP_SYNC, "Sync" }, \ { CP_RECOVERY, "Recovery" }, \ { CP_DISCARD, "Discard" }, \ - { CP_UMOUNT, "Umount" }, \ + { CP_PAUSE, "Pause" }, \ { CP_TRIMMED, "Trimmed" }) #define show_fsync_cpreason(type) \ __print_symbolic(type, \ { CP_NO_NEEDED, "no needed" }, \ { CP_NON_REGULAR, "non regular" }, \ + { CP_COMPRESSED, "compressed" }, \ { CP_HARDLINK, "hardlink" }, \ { CP_SB_NEED_CP, "sb needs cp" }, \ { CP_WRONG_PINO, "wrong pino" }, \ @@ -158,6 +160,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED); { F2FS_GOING_DOWN_METAFLUSH, "meta flush" }, \ { F2FS_GOING_DOWN_NEED_FSCK, "need fsck" }) +#define show_compress_algorithm(type) \ + __print_symbolic(type, \ + { COMPRESS_LZO, "LZO" }, \ + { COMPRESS_LZ4, "LZ4" }, \ + { COMPRESS_ZSTD, "ZSTD" }) + struct f2fs_sb_info; struct f2fs_io_info; struct extent_info; @@ -1720,6 +1728,171 @@ TRACE_EVENT(f2fs_shutdown, __entry->ret) ); +DECLARE_EVENT_CLASS(f2fs_zip_start, + + TP_PROTO(struct inode *inode, pgoff_t cluster_idx, + unsigned int cluster_size, unsigned char algtype), + + TP_ARGS(inode, cluster_idx, cluster_size, algtype), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(pgoff_t, idx) + __field(unsigned int, size) + __field(unsigned int, algtype) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->idx = cluster_idx; + __entry->size = cluster_size; + __entry->algtype = algtype; + ), + + TP_printk("dev = (%d,%d), ino = %lu, cluster_idx:%lu, " + "cluster_size = %u, algorithm = %s", + show_dev_ino(__entry), + __entry->idx, + __entry->size, + show_compress_algorithm(__entry->algtype)) +); + +DECLARE_EVENT_CLASS(f2fs_zip_end, + + TP_PROTO(struct inode *inode, pgoff_t cluster_idx, + unsigned int compressed_size, int ret), + + TP_ARGS(inode, cluster_idx, compressed_size, ret), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(pgoff_t, idx) + __field(unsigned int, size) + __field(unsigned int, ret) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->idx = cluster_idx; + __entry->size = compressed_size; + __entry->ret = ret; + ), + + TP_printk("dev = (%d,%d), ino = %lu, cluster_idx:%lu, " + "compressed_size = %u, ret = %d", + show_dev_ino(__entry), + __entry->idx, + __entry->size, + __entry->ret) +); + +DEFINE_EVENT(f2fs_zip_start, f2fs_compress_pages_start, + + TP_PROTO(struct inode *inode, pgoff_t cluster_idx, + unsigned int cluster_size, unsigned char algtype), + + TP_ARGS(inode, cluster_idx, cluster_size, algtype) +); + +DEFINE_EVENT(f2fs_zip_start, f2fs_decompress_pages_start, + + TP_PROTO(struct inode *inode, pgoff_t cluster_idx, + unsigned int cluster_size, unsigned char algtype), + + TP_ARGS(inode, cluster_idx, cluster_size, algtype) +); + +DEFINE_EVENT(f2fs_zip_end, f2fs_compress_pages_end, + + TP_PROTO(struct inode *inode, pgoff_t cluster_idx, + unsigned int compressed_size, int ret), + + TP_ARGS(inode, cluster_idx, compressed_size, ret) +); + +DEFINE_EVENT(f2fs_zip_end, f2fs_decompress_pages_end, + + TP_PROTO(struct inode *inode, pgoff_t cluster_idx, + unsigned int compressed_size, int ret), + + TP_ARGS(inode, cluster_idx, compressed_size, ret) +); + +TRACE_EVENT(f2fs_iostat, + + TP_PROTO(struct f2fs_sb_info *sbi, unsigned long long *iostat), + + TP_ARGS(sbi, iostat), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(unsigned long long, app_dio) + __field(unsigned long long, app_bio) + __field(unsigned long long, app_wio) + __field(unsigned long long, app_mio) + __field(unsigned long long, fs_dio) + __field(unsigned long long, fs_nio) + __field(unsigned long long, fs_mio) + __field(unsigned long long, fs_gc_dio) + __field(unsigned long long, fs_gc_nio) + __field(unsigned long long, fs_cp_dio) + __field(unsigned long long, fs_cp_nio) + __field(unsigned long long, fs_cp_mio) + __field(unsigned long long, app_drio) + __field(unsigned long long, app_brio) + __field(unsigned long long, app_rio) + __field(unsigned long long, app_mrio) + __field(unsigned long long, fs_drio) + __field(unsigned long long, fs_nrio) + __field(unsigned long long, fs_mrio) + __field(unsigned long long, fs_discard) + ), + + TP_fast_assign( + __entry->dev = sbi->sb->s_dev; + __entry->app_dio = iostat[APP_DIRECT_IO]; + __entry->app_bio = iostat[APP_BUFFERED_IO]; + __entry->app_wio = iostat[APP_WRITE_IO]; + __entry->app_mio = iostat[APP_MAPPED_IO]; + __entry->fs_dio = iostat[FS_DATA_IO]; + __entry->fs_nio = iostat[FS_NODE_IO]; + __entry->fs_mio = iostat[FS_META_IO]; + __entry->fs_gc_dio = iostat[FS_GC_DATA_IO]; + __entry->fs_gc_nio = iostat[FS_GC_NODE_IO]; + __entry->fs_cp_dio = iostat[FS_CP_DATA_IO]; + __entry->fs_cp_nio = iostat[FS_CP_NODE_IO]; + __entry->fs_cp_mio = iostat[FS_CP_META_IO]; + __entry->app_drio = iostat[APP_DIRECT_READ_IO]; + __entry->app_brio = iostat[APP_BUFFERED_READ_IO]; + __entry->app_rio = iostat[APP_READ_IO]; + __entry->app_mrio = iostat[APP_MAPPED_READ_IO]; + __entry->fs_drio = iostat[FS_DATA_READ_IO]; + __entry->fs_nrio = iostat[FS_NODE_READ_IO]; + __entry->fs_mrio = iostat[FS_META_READ_IO]; + __entry->fs_discard = iostat[FS_DISCARD]; + ), + + TP_printk("dev = (%d,%d), " + "app [write=%llu (direct=%llu, buffered=%llu), mapped=%llu], " + "fs [data=%llu, node=%llu, meta=%llu, discard=%llu], " + "gc [data=%llu, node=%llu], " + "cp [data=%llu, node=%llu, meta=%llu], " + "app [read=%llu (direct=%llu, buffered=%llu), mapped=%llu], " + "fs [data=%llu, node=%llu, meta=%llu]", + show_dev(__entry->dev), __entry->app_wio, __entry->app_dio, + __entry->app_bio, __entry->app_mio, __entry->fs_dio, + __entry->fs_nio, __entry->fs_mio, __entry->fs_discard, + __entry->fs_gc_dio, __entry->fs_gc_nio, __entry->fs_cp_dio, + __entry->fs_cp_nio, __entry->fs_cp_mio, + __entry->app_rio, __entry->app_drio, __entry->app_brio, + __entry->app_mrio, __entry->fs_drio, __entry->fs_nrio, + __entry->fs_mrio) +); + #endif /* _TRACE_F2FS_H */ /* This part must be outside protection */ diff --git a/include/trace/events/gpu_mem.h b/include/trace/events/gpu_mem.h new file mode 100644 index 0000000000000000000000000000000000000000..1897822a9150659127631d4220702bd639beef5f --- /dev/null +++ b/include/trace/events/gpu_mem.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * GPU memory trace points + * + * Copyright (C) 2020 Google, Inc. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM gpu_mem + +#if !defined(_TRACE_GPU_MEM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_GPU_MEM_H + +#include + +/* + * The gpu_memory_total event indicates that there's an update to either the + * global or process total gpu memory counters. + * + * This event should be emitted whenever the kernel device driver allocates, + * frees, imports, unimports memory in the GPU addressable space. + * + * @gpu_id: This is the gpu id. + * + * @pid: Put 0 for global total, while positive pid for process total. + * + * @size: Virtual size of the allocation in bytes. + * + */ +TRACE_EVENT(gpu_mem_total, + + TP_PROTO(uint32_t gpu_id, uint32_t pid, uint64_t size), + + TP_ARGS(gpu_id, pid, size), + + TP_STRUCT__entry( + __field(uint32_t, gpu_id) + __field(uint32_t, pid) + __field(uint64_t, size) + ), + + TP_fast_assign( + __entry->gpu_id = gpu_id; + __entry->pid = pid; + __entry->size = size; + ), + + TP_printk("gpu_id=%u pid=%u size=%llu", + __entry->gpu_id, + __entry->pid, + __entry->size) +); + +#endif /* _TRACE_GPU_MEM_H */ + +/* This part must be outside protection */ +#include diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index f06a789f34cd9993f3952da30723adf995790605..00da2d183dcaeffd173d7074b566f1088a9452c3 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -46,6 +46,7 @@ extern "C" { #define DRM_VIRTGPU_TRANSFER_TO_HOST 0x07 #define DRM_VIRTGPU_WAIT 0x08 #define DRM_VIRTGPU_GET_CAPS 0x09 +#define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x0a #define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01 #define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02 @@ -69,8 +70,11 @@ struct drm_virtgpu_execbuffer { __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */ }; + #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ #define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */ +#define VIRTGPU_PARAM_RESOURCE_BLOB 3 /* DRM_VIRTGPU_RESOURCE_CREATE_BLOB */ +#define VIRTGPU_PARAM_HOST_VISIBLE 4 struct drm_virtgpu_getparam { __u64 param; @@ -100,7 +104,13 @@ struct drm_virtgpu_resource_info { __u32 bo_handle; __u32 res_handle; __u32 size; - __u32 stride; + union { + __u32 stride; + __u32 strides[4]; /* strides[0] is accessible with stride. */ + }; + __u32 num_planes; + __u32 offsets[4]; + __u64 format_modifier; }; struct drm_virtgpu_3d_box { @@ -140,6 +150,31 @@ struct drm_virtgpu_get_caps { __u32 pad; }; +struct drm_virtgpu_resource_create_blob { +#define VIRTGPU_BLOB_MEM_GUEST 0x0001 +#define VIRTGPU_BLOB_MEM_HOST 0x0002 +#define VIRTGPU_BLOB_MEM_HOST_GUEST 0x0003 + +#define VIRTGPU_BLOB_FLAG_MAPPABLE 0x0001 +#define VIRTGPU_BLOB_FLAG_SHAREABLE 0x0002 +#define VIRTGPU_BLOB_FLAG_CROSS_DEVICE 0x0004 + /* zero is invalid blob_mem */ + __u32 blob_mem; + __u32 blob_flags; + __u32 bo_handle; + __u32 res_handle; + __u64 size; + + /* + * for 3D contexts with VIRTGPU_BLOB_MEM_HOSTGUEST and + * VIRTGPU_BLOB_MEM_HOST otherwise, must be zero. + */ + __u32 pad; + __u32 cmd_size; + __u64 cmd; + __u64 blob_id; +}; + #define DRM_IOCTL_VIRTGPU_MAP \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) @@ -175,6 +210,10 @@ struct drm_virtgpu_get_caps { DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \ struct drm_virtgpu_get_caps) +#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE_BLOB, \ + struct drm_virtgpu_resource_create_blob) + #if defined(__cplusplus) } #endif diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 393b5ae4e7d4c67a9872067121da1fb04442d670..b2b6ee53d578adca46f87659911a0252891ba554 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -8,6 +8,7 @@ #ifndef _UAPI_LINUX_FSCRYPT_H #define _UAPI_LINUX_FSCRYPT_H +#include #include /* Encryption policy flags */ @@ -18,7 +19,8 @@ #define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03 #define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04 #define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08 -#define FSCRYPT_POLICY_FLAGS_VALID 0x0F +#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 0x10 +#define FSCRYPT_POLICY_FLAGS_VALID 0x1F /* Encryption algorithms */ #define FSCRYPT_MODE_AES_256_XTS 1 @@ -26,9 +28,8 @@ #define FSCRYPT_MODE_AES_128_CBC 5 #define FSCRYPT_MODE_AES_128_CTS 6 #define FSCRYPT_MODE_ADIANTUM 9 -#define __FSCRYPT_MODE_MAX 9 #define FSCRYPT_MODE_PRIVATE 127 - +#define __FSCRYPT_MODE_MAX 127 /* * Legacy policy version; ad-hoc KDF and no key verification. * For new encrypted directories, use fscrypt_policy_v2 instead. @@ -126,6 +127,8 @@ struct fscrypt_add_key_arg { __u32 raw_size; __u32 key_id; __u32 __reserved[7]; + /* N.B.: "temporary" flag, not reserved upstream */ +#define __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED 0x00000001 __u32 __flags; __u8 raw[]; }; @@ -164,6 +167,7 @@ struct fscrypt_get_key_status_arg { #define FS_IOC_REMOVE_ENCRYPTION_KEY _IOWR('f', 24, struct fscrypt_remove_key_arg) #define FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS _IOWR('f', 25, struct fscrypt_remove_key_arg) #define FS_IOC_GET_ENCRYPTION_KEY_STATUS _IOWR('f', 26, struct fscrypt_get_key_status_arg) +#define FS_IOC_GET_ENCRYPTION_NONCE _IOR('f', 27, __u8[16]) /**********************************************************************/ diff --git a/include/uapi/linux/incrementalfs.h b/include/uapi/linux/incrementalfs.h index 8a06e2e48fc4f5e809fa86b98a892f7ba9c9b0fd..13c3d5173e14338abdd2eb4a01f468c3531e0a75 100644 --- a/include/uapi/linux/incrementalfs.h +++ b/include/uapi/linux/incrementalfs.h @@ -22,8 +22,9 @@ #define INCFS_DATA_FILE_BLOCK_SIZE 4096 #define INCFS_HEADER_VER 1 -// TODO: This value is assumed in incfs_copy_signature_info_from_user to be the -// actual signature length. Set back to 64 when fixed. +/* TODO: This value is assumed in incfs_copy_signature_info_from_user to be the + * actual signature length. Set back to 64 when fixed. + */ #define INCFS_MAX_HASH_SIZE 32 #define INCFS_MAX_FILE_ATTR_SIZE 512 @@ -34,6 +35,8 @@ #define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata") #define INCFS_MAX_SIGNATURE_SIZE 8096 +#define INCFS_SIGNATURE_VERSION 2 +#define INCFS_SIGNATURE_SECTIONS 2 #define INCFS_IOCTL_BASE_CODE 'g' @@ -45,7 +48,49 @@ /* Read file signature */ #define INCFS_IOC_READ_FILE_SIGNATURE \ - _IOWR(INCFS_IOCTL_BASE_CODE, 31, struct incfs_get_file_sig_args) + _IOR(INCFS_IOCTL_BASE_CODE, 31, struct incfs_get_file_sig_args) + +/* + * Fill in one or more data block. This may only be called on a handle + * passed as a parameter to INCFS_IOC_PERMIT_FILLING + * + * Returns number of blocks filled in, or error if none were + */ +#define INCFS_IOC_FILL_BLOCKS \ + _IOR(INCFS_IOCTL_BASE_CODE, 32, struct incfs_fill_blocks) + +/* + * Permit INCFS_IOC_FILL_BLOCKS on the given file descriptor + * May only be called on .pending_reads file + * + * Returns 0 on success or error + */ +#define INCFS_IOC_PERMIT_FILL \ + _IOW(INCFS_IOCTL_BASE_CODE, 33, struct incfs_permit_fill) + +/* + * Fills buffer with ranges of populated blocks + * + * Returns 0 if all ranges written + * error otherwise + * + * Either way, range_buffer_size_out is set to the number + * of bytes written. Should be set to 0 by caller. The ranges + * filled are valid, but if an error was returned there might + * be more ranges to come. + * + * Ranges are ranges of filled blocks: + * + * 1 2 7 9 + * + * means blocks 1, 2, 7, 8, 9 are filled, 0, 3, 4, 5, 6 and 10 on + * are not + * + * If hashing is enabled for the file, the hash blocks are simply + * treated as though they immediately followed the data blocks. + */ +#define INCFS_IOC_GET_FILLED_BLOCKS \ + _IOR(INCFS_IOCTL_BASE_CODE, 34, struct incfs_get_filled_blocks_args) enum incfs_compression_alg { COMPRESSION_NONE = 0, @@ -80,10 +125,9 @@ struct incfs_pending_read_info { }; /* - * A struct to be written into a control file to load a data or hash - * block to a data file. + * Description of a data or hash block to add to a data file. */ -struct incfs_new_data_block { +struct incfs_fill_block { /* Index of a data block. */ __u32 block_index; @@ -113,49 +157,33 @@ struct incfs_new_data_block { __aligned_u64 reserved3; }; -enum incfs_hash_tree_algorithm { - INCFS_HASH_TREE_NONE = 0, - INCFS_HASH_TREE_SHA256 = 1 -}; - -struct incfs_file_signature_info { - /* - * A pointer to file's root hash (if determined != 0) - * Actual hash size determined by hash_tree_alg. - * Size of the buffer should be at least INCFS_MAX_HASH_SIZE - * - * Equivalent to: u8 *root_hash; - */ - __aligned_u64 root_hash; - - /* - * A pointer to additional data that was attached to the root hash - * before signing. - * - * Equivalent to: u8 *additional_data; - */ - __aligned_u64 additional_data; - - /* Size of additional data. */ - __u32 additional_data_size; - - __u32 reserved1; - - /* - * A pointer to pkcs7 signature DER blob. - * - * Equivalent to: u8 *signature; - */ - __aligned_u64 signature; - +/* + * Description of a number of blocks to add to a data file + * + * Argument for INCFS_IOC_FILL_BLOCKS + */ +struct incfs_fill_blocks { + /* Number of blocks */ + __u64 count; - /* Size of pkcs7 signature DER blob */ - __u32 signature_size; + /* A pointer to an array of incfs_fill_block structs */ + __aligned_u64 fill_blocks; +}; - __u32 reserved2; +/* + * Permit INCFS_IOC_FILL_BLOCKS on the given file descriptor + * May only be called on .pending_reads file + * + * Argument for INCFS_IOC_PERMIT_FILL + */ +struct incfs_permit_fill { + /* File to permit fills on */ + __u32 file_descriptor; +}; - /* Value from incfs_hash_tree_algorithm */ - __u8 hash_tree_alg; +enum incfs_hash_tree_algorithm { + INCFS_HASH_TREE_NONE = 0, + INCFS_HASH_TREE_SHA256 = 1 }; /* @@ -211,10 +239,30 @@ struct incfs_new_file_args { __u32 reserved4; - /* struct incfs_file_signature_info *signature_info; */ + /* + * Points to an APK V4 Signature data blob + * Signature must have two sections + * Format is: + * u32 version + * u32 size_of_hash_info_section + * u8 hash_info_section[] + * u32 size_of_signing_info_section + * u8 signing_info_section[] + * + * Note that incfs does not care about what is in signing_info_section + * + * hash_info_section has following format: + * u32 hash_algorithm; // Must be SHA256 == 1 + * u8 log2_blocksize; // Must be 12 for 4096 byte blocks + * u32 salt_size; + * u8 salt[]; + * u32 hash_size; + * u8 root_hash[]; + */ __aligned_u64 signature_info; - __aligned_u64 reserved5; + /* Size of signature_info */ + __aligned_u64 signature_size; __aligned_u64 reserved6; }; @@ -241,4 +289,46 @@ struct incfs_get_file_sig_args { __u32 file_signature_len_out; }; +struct incfs_filled_range { + __u32 begin; + __u32 end; +}; + +/* + * Request ranges of filled blocks + * Argument for INCFS_IOC_GET_FILLED_BLOCKS + */ +struct incfs_get_filled_blocks_args { + /* + * A buffer to populate with ranges of filled blocks + * + * Equivalent to struct incfs_filled_ranges *range_buffer + */ + __aligned_u64 range_buffer; + + /* Size of range_buffer */ + __u32 range_buffer_size; + + /* Start index to read from */ + __u32 start_index; + + /* + * End index to read to. 0 means read to end. This is a range, + * so incfs will read from start_index to end_index - 1 + */ + __u32 end_index; + + /* Actual number of blocks in file */ + __u32 total_blocks_out; + + /* The number of data blocks in file */ + __u32 data_blocks_out; + + /* Number of bytes written to range buffer */ + __u32 range_buffer_size_out; + + /* Sector scanned up to, if the call was interrupted */ + __u32 index_out; +}; + #endif /* _UAPI_LINUX_INCREMENTALFS_H */ diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h index 7b8c9e19bad1c2bf72c21dcf6b358559d5e4b4ea..0f3cb13db8e93efe9d6319395f21849e896f7a02 100644 --- a/include/uapi/linux/keyctl.h +++ b/include/uapi/linux/keyctl.h @@ -65,7 +65,12 @@ /* keyctl structures */ struct keyctl_dh_params { - __s32 private; + union { +#ifndef __cplusplus + __s32 private; +#endif + __s32 priv; + }; __s32 prime; __s32 base; }; diff --git a/include/uapi/linux/msm_eth.h b/include/uapi/linux/msm_eth.h new file mode 100644 index 0000000000000000000000000000000000000000..e60214ad5d5af1ef0aca9b15b0051994ef805212 --- /dev/null +++ b/include/uapi/linux/msm_eth.h @@ -0,0 +1,37 @@ +#ifndef _UAPI_MSM_ETH_H_ +#define _UAPI_MSM_ETH_H_ + +#include + +/** + * defines eth_meta_event - Events for eth + * + * CV2X pipe connect: CV2X pipe connected + * CV2X pipe disconnect: CV2X pipe disconnected + */ +#define ETH_EVT_START 0 +#define ETH_EVT_CV2X_PIPE_CONNECTED (ETH_EVT_START + 1) +#define ETH_EVT_CV2X_PIPE_DISCONNECTED (ETH_EVT_CV2X_PIPE_CONNECTED + 1) +#define ETH_EVT_CV2X_MODE_NOT_ENABLED (ETH_EVT_CV2X_PIPE_DISCONNECTED + 1) + +/** + * struct eth_msg_meta - Format of the message meta-data. + * @msg_type: the type of the message + * @rsvd: reserved bits for future use. + * @msg_len: the length of the message in bytes + * + * For push model: + * Client in user-space should issue a read on the device (/dev/emac) with a + * sufficiently large buffer in a continuous loop, call will block when there is + * no message to read. Upon return, client can read the eth_msg_meta from start + * of buffer to find out type and length of message + * size of buffer supplied >= (size of largest message + size of metadata) + * + */ +struct eth_msg_meta { + __u8 msg_type; + __u8 rsvd; + __u16 msg_len; +}; + +#endif /* _UAPI_MSM_ETH_H_ */ diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 497526feb0caa7145dd8eccd8ac74d57e89cf504..c6c47e59ff4f37b2b304aa0c61d1476cbab41050 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -127,6 +127,8 @@ #define IPA_IOCTL_APP_CLOCK_VOTE 79 #define IPA_IOCTL_PDN_CONFIG 80 #define IPA_IOCTL_SET_MAC_FLT 81 +#define IPA_IOCTL_ADD_UC_ACT_ENTRY 82 +#define IPA_IOCTL_DEL_UC_ACT_ENTRY 83 /** * max size of the header to be inserted @@ -417,9 +419,12 @@ enum ipa_client_type { IPA_CLIENT_QDSS_PROD = 110, IPA_CLIENT_MHI_QDSS_CONS = 111, + + IPA_CLIENT_ETHERNET2_PROD = 112, + IPA_CLIENT_ETHERNET2_CONS = 113, }; -#define IPA_CLIENT_MAX (IPA_CLIENT_MHI_QDSS_CONS + 1) +#define IPA_CLIENT_MAX (IPA_CLIENT_ETHERNET2_CONS + 1) #define IPA_CLIENT_WLAN2_PROD IPA_CLIENT_A5_WLAN_AMPDU_PROD #define IPA_CLIENT_Q6_DL_NLO_DATA_PROD IPA_CLIENT_Q6_DL_NLO_DATA_PROD @@ -1184,9 +1189,10 @@ enum ipa_hdr_proc_type { IPA_HDR_PROC_L2TP_HEADER_REMOVE, IPA_HDR_PROC_ETHII_TO_ETHII_EX, IPA_HDR_PROC_L2TP_UDP_HEADER_ADD, - IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE + IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE, + IPA_HDR_PROC_SET_DSCP, }; -#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE + 1) +#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_SET_DSCP + 1) /** * struct ipa_rt_rule - attributes of a routing rule @@ -2339,13 +2345,17 @@ struct ipa_ioc_gsb_info { #define IPA_PCIE0_EP_ID 21 #define IPA_PCIE1_EP_ID 22 +#define IPA_ETH0_EP_ID 31 +#define IPA_ETH1_EP_ID 32 + enum ipa_peripheral_ep_type { IPA_DATA_EP_TYP_RESERVED = 0, IPA_DATA_EP_TYP_HSIC = 1, IPA_DATA_EP_TYP_HSUSB = 2, IPA_DATA_EP_TYP_PCIE = 3, IPA_DATA_EP_TYP_EMBEDDED = 4, - IPA_DATA_EP_TYP_BAM_DMUX, + IPA_DATA_EP_TYP_BAM_DMUX = 5, + IPA_DATA_EP_TYP_ETH, }; enum ipa_data_ep_prot_type { @@ -2514,6 +2524,73 @@ struct ipa_wan_msg { uint32_t ipv6_addr_gw[IPA_WAN_MSG_IPv6_ADDR_GW_LEN]; }; +/* uc activation command Ids */ +#define IPA_SOCKSV5_ADD_COM_ID 15 +#define IPA_IPv6_NAT_COM_ID 16 + +/** + * ipa_kernel_tests_socksv5_uc_tmpl - uc activation entry info + * @cmd_id: uc command id + * @cmd_param: uC command param + * @ipa_kernel_tests_ip_hdr_temp: ip header + * @src_port: source port + * @dst_port: destination port + * @ipa_sockv5_mask: uc attribute mask for options/etc + * @out_irs: 4B/4B Seq/Ack/SACK + * @out_iss + * @in_irs + * @in_iss + * @out_ircv_tsval: timestamp attributes + * @in_ircv_tsecr + * @out_ircv_tsecr + * @in_ircv_tsval + * @in_isnd_wscale: window scale attributes + * @out_isnd_wscale + * @in_ircv_wscale + * @out_ircv_wscale + * @direction: 1 for UL 0 for DL + * @handle: uc activation table index + */ +struct ipa_kernel_tests_socksv5_uc_tmpl { + uint16_t cmd_id; + uint32_t cmd_param; + __be32 ip_src_addr; + __be32 ip_dst_addr; + __be32 ipv6_src_addr[4]; + __be32 ipv6_dst_addr[4]; + + /* 2B src/dst port */ + uint16_t src_port; + uint16_t dst_port; + + /* attribute mask */ + uint32_t ipa_sockv5_mask; + + /* required update 4B/4B Seq/Ack/SACK */ + uint32_t out_irs; + uint32_t out_iss; + uint32_t in_irs; + uint32_t in_iss; + + /* option 10B: time-stamp */ + uint32_t out_ircv_tsval; + uint32_t in_ircv_tsecr; + uint32_t out_ircv_tsecr; + uint32_t in_ircv_tsval; + + /* option 2B: window-scaling/dynamic */ + uint16_t in_isnd_wscale : 4; + uint16_t out_isnd_wscale : 4; + uint16_t in_ircv_wscale : 4; + uint16_t out_ircv_wscale : 4; + + /* direction 1 = UL, 0 = DL */ + uint8_t direction; + + /* output: handle (index) */ + uint16_t handle; +}; + /** * struct ipacm_socksv5_info - To hold information about socksv5 connections * @ip_type: ip type @@ -2564,6 +2641,41 @@ struct ipa_socksv5_msg { uint16_t handle; }; +/** + * struct ipa_ioc_ipv6_nat_uc_act_entry - To hold information about IPv6 NAT + * uC entry + * @cmd_id[in]: IPv6 NAT uC CMD ID - used for identifying uc activation type + * @private_address_lsb[in]: client private address lsb + * @private_address_msb[in]: client private address msb + * @public_address_lsb[in]: client public address lsb + * @public_address_msb[in]: client public address msb + * @private_port[in]: client private port + * @public_port[in]: client public port + * @index[out]: uC activation entry index + */ +struct ipa_ioc_ipv6_nat_uc_act_entry { + uint16_t cmd_id; + uint64_t private_address_lsb; + uint64_t private_address_msb; + uint64_t public_address_lsb; + uint64_t public_address_msb; + uint32_t private_port; + uint32_t public_port; + uint16_t index; +}; + +/** + * union ipa_ioc_uc_activation_entry - To hold information about uC activation + * entry + * @socks[in]: fill here if entry is Socksv5 entry + * @ipv6_nat[in]: fill here if entry is IPv6 NAT entry + */ +union ipa_ioc_uc_activation_entry { + struct ipa_kernel_tests_socksv5_uc_tmpl socks; + struct ipa_ioc_ipv6_nat_uc_act_entry ipv6_nat; +}; + + /** * struct ipa_ioc_rm_dependency - parameters for add/delete dependency * @resource_name: name of dependent resource @@ -2739,12 +2851,14 @@ struct ipa_ioc_get_vlan_mode { * @vlan_id: vlan ID bridge is mapped to * @bridge_ipv4: bridge interface ipv4 address * @subnet_mask: bridge interface subnet mask + * @lan2lan_sw: indicate lan2lan traffic take sw-path or not */ struct ipa_ioc_bridge_vlan_mapping_info { char bridge_name[IPA_RESOURCE_NAME_MAX]; uint16_t vlan_id; uint32_t bridge_ipv4; uint32_t subnet_mask; + uint8_t lan2lan_sw; }; struct ipa_coalesce_info { @@ -3083,6 +3197,14 @@ struct ipa_ioc_mac_client_list_type { IPA_IOCTL_SET_MAC_FLT, \ struct ipa_ioc_mac_client_list_type) +#define IPA_IOC_ADD_UC_ACT_ENTRY _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ADD_UC_ACT_ENTRY, \ + union ipa_ioc_uc_activation_entry) + +#define IPA_IOC_DEL_UC_ACT_ENTRY _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_DEL_UC_ACT_ENTRY, \ + uint16_t) + /* * unique magic number of the Tethering bridge ioctls */ diff --git a/include/uapi/linux/msm_npu.h b/include/uapi/linux/msm_npu.h index b6509ec7a7b6763d735c0095185b36928c826f71..7deb6edbeaf17e4a6919b7e659f0ac35a305bf88 100644 --- a/include/uapi/linux/msm_npu.h +++ b/include/uapi/linux/msm_npu.h @@ -87,6 +87,7 @@ /* features supported by driver */ #define MSM_NPU_FEATURE_MULTI_EXECUTE 0x1 #define MSM_NPU_FEATURE_ASYNC_EXECUTE 0x2 +#define MSM_NPU_FEATURE_DSP_SID_MAPPED 0x8 #define PROP_PARAM_MAX_SIZE 8 diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index fb3cf792196f4ff4d0d447ae229ec05fa95903db..709a1f6cf8c990ce505607f2974e68952796ca7e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2786,7 +2786,6 @@ enum nl80211_attrs { NL80211_ATTR_HE_BSS_COLOR, NL80211_ATTR_IFTYPE_AKM_SUITES, - /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2836,7 +2835,8 @@ enum nl80211_attrs { #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 #define NL80211_HT_CAPABILITY_LEN 26 #define NL80211_VHT_CAPABILITY_LEN 12 - +#define NL80211_HE_MIN_CAPABILITY_LEN 16 +#define NL80211_HE_MAX_CAPABILITY_LEN 51 #define NL80211_MAX_NR_CIPHER_SUITES 5 #define NL80211_MAX_NR_AKM_SUITES 2 @@ -2963,6 +2963,38 @@ struct nl80211_sta_flag_update { __u32 set; } __attribute__((packed)); +/** + * enum nl80211_he_gi - HE guard interval + * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec + * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec + * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec + */ +enum nl80211_he_gi { + NL80211_RATE_INFO_HE_GI_0_8, + NL80211_RATE_INFO_HE_GI_1_6, + NL80211_RATE_INFO_HE_GI_3_2, +}; + +/** + * enum nl80211_he_ru_alloc - HE RU allocation values + * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation + * @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation + */ +enum nl80211_he_ru_alloc { + NL80211_RATE_INFO_HE_RU_ALLOC_26, + NL80211_RATE_INFO_HE_RU_ALLOC_52, + NL80211_RATE_INFO_HE_RU_ALLOC_106, + NL80211_RATE_INFO_HE_RU_ALLOC_242, + NL80211_RATE_INFO_HE_RU_ALLOC_484, + NL80211_RATE_INFO_HE_RU_ALLOC_996, + NL80211_RATE_INFO_HE_RU_ALLOC_2x996, +}; + /** * enum nl80211_rate_info - bitrate information * @@ -2995,6 +3027,13 @@ struct nl80211_sta_flag_update { * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is * a legacy rate and will be reported as the actual bitrate, i.e. * a quarter of the base (20 MHz) rate + * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11) + * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8) + * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier + * (u8, see &enum nl80211_he_gi) + * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1) + * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then + * non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc) * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -3011,6 +3050,11 @@ enum nl80211_rate_info { NL80211_RATE_INFO_160_MHZ_WIDTH, NL80211_RATE_INFO_10_MHZ_WIDTH, NL80211_RATE_INFO_5_MHZ_WIDTH, + NL80211_RATE_INFO_HE_MCS, + NL80211_RATE_INFO_HE_NSS, + NL80211_RATE_INFO_HE_GI, + NL80211_RATE_INFO_HE_DCM, + NL80211_RATE_INFO_HE_RU_ALLOC, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -3239,6 +3283,38 @@ enum nl80211_mpath_info { NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 }; +/** + * enum nl80211_band_iftype_attr - Interface type data attributes + * + * @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute + * for each interface type that supports the band data + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE + * capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE + * capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE + * capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as + * defined in HE capabilities IE + * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently + * defined + * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use + */ +enum nl80211_band_iftype_attr { + __NL80211_BAND_IFTYPE_ATTR_INVALID, + + NL80211_BAND_IFTYPE_ATTR_IFTYPES, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, + + /* keep last */ + __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, + NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1 +}; + /** * enum nl80211_band_attr - band attributes * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved @@ -3254,6 +3330,8 @@ enum nl80211_mpath_info { * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as * defined in 802.11ac * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE + * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using + * attributes from &enum nl80211_band_iftype_attr * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @__NL80211_BAND_ATTR_AFTER_LAST: internal use */ @@ -3269,6 +3347,7 @@ enum nl80211_band_attr { NL80211_BAND_ATTR_VHT_MCS_SET, NL80211_BAND_ATTR_VHT_CAPA, + NL80211_BAND_ATTR_IFTYPE_DATA, /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, diff --git a/include/uapi/linux/serio.h b/include/uapi/linux/serio.h index a0cac1d8670d8a89320adba86688aee6ef8a63b7..1937915be4137a3b122461495cd179f0c3105885 100644 --- a/include/uapi/linux/serio.h +++ b/include/uapi/linux/serio.h @@ -9,7 +9,7 @@ #ifndef _UAPI_SERIO_H #define _UAPI_SERIO_H - +#include #include #define SPIOCSTYPE _IOW('q', 0x01, unsigned long) @@ -18,10 +18,10 @@ /* * bit masks for use in "interrupt" flags (3rd argument) */ -#define SERIO_TIMEOUT BIT(0) -#define SERIO_PARITY BIT(1) -#define SERIO_FRAME BIT(2) -#define SERIO_OOB_DATA BIT(3) +#define SERIO_TIMEOUT _BITUL(0) +#define SERIO_PARITY _BITUL(1) +#define SERIO_FRAME _BITUL(2) +#define SERIO_OOB_DATA _BITUL(3) /* * Serio types diff --git a/include/uapi/linux/swab.h b/include/uapi/linux/swab.h index 23cd84868cc3bd8907994664c82407ca49a1d8d9..7272f85d6d6ab5e24dd806e7f88760eaafcd7326 100644 --- a/include/uapi/linux/swab.h +++ b/include/uapi/linux/swab.h @@ -4,6 +4,7 @@ #include #include +#include #include /* @@ -132,6 +133,15 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val) __fswab64(x)) #endif +static __always_inline unsigned long __swab(const unsigned long y) +{ +#if __BITS_PER_LONG == 64 + return __swab64(y); +#else /* __BITS_PER_LONG == 32 */ + return __swab32(y); +#endif +} + /** * __swahw32 - return a word-swapped 32-bit value * @x: value to wordswap diff --git a/include/uapi/linux/usb/charger.h b/include/uapi/linux/usb/charger.h index 5f72af35b3ed768fd3bc1e2d8ca3f4f6ecaea47f..ad22079125bff2ba34f03b74e6cfd5e2eb460479 100644 --- a/include/uapi/linux/usb/charger.h +++ b/include/uapi/linux/usb/charger.h @@ -14,18 +14,18 @@ * ACA (Accessory Charger Adapters) */ enum usb_charger_type { - UNKNOWN_TYPE, - SDP_TYPE, - DCP_TYPE, - CDP_TYPE, - ACA_TYPE, + UNKNOWN_TYPE = 0, + SDP_TYPE = 1, + DCP_TYPE = 2, + CDP_TYPE = 3, + ACA_TYPE = 4, }; /* USB charger state */ enum usb_charger_state { - USB_CHARGER_DEFAULT, - USB_CHARGER_PRESENT, - USB_CHARGER_ABSENT, + USB_CHARGER_DEFAULT = 0, + USB_CHARGER_PRESENT = 1, + USB_CHARGER_ABSENT = 2, }; #endif /* _UAPI__LINUX_USB_CHARGER_H */ diff --git a/include/uapi/linux/usb/raw_gadget.h b/include/uapi/linux/usb/raw_gadget.h new file mode 100644 index 0000000000000000000000000000000000000000..ea375082b3ac7ab9fa6ea6919ce35cb0ff9a6588 --- /dev/null +++ b/include/uapi/linux/usb/raw_gadget.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * USB Raw Gadget driver. + * + * See Documentation/usb/raw-gadget.rst for more details. + */ + +#ifndef _UAPI__LINUX_USB_RAW_GADGET_H +#define _UAPI__LINUX_USB_RAW_GADGET_H + +#include +#include +#include + +/* Maximum length of driver_name/device_name in the usb_raw_init struct. */ +#define UDC_NAME_LENGTH_MAX 128 + +/* + * struct usb_raw_init - argument for USB_RAW_IOCTL_INIT ioctl. + * @speed: The speed of the emulated USB device, takes the same values as + * the usb_device_speed enum: USB_SPEED_FULL, USB_SPEED_HIGH, etc. + * @driver_name: The name of the UDC driver. + * @device_name: The name of a UDC instance. + * + * The last two fields identify a UDC the gadget driver should bind to. + * For example, Dummy UDC has "dummy_udc" as its driver_name and "dummy_udc.N" + * as its device_name, where N in the index of the Dummy UDC instance. + * At the same time the dwc2 driver that is used on Raspberry Pi Zero, has + * "20980000.usb" as both driver_name and device_name. + */ +struct usb_raw_init { + __u8 driver_name[UDC_NAME_LENGTH_MAX]; + __u8 device_name[UDC_NAME_LENGTH_MAX]; + __u8 speed; +}; + +/* The type of event fetched with the USB_RAW_IOCTL_EVENT_FETCH ioctl. */ +enum usb_raw_event_type { + USB_RAW_EVENT_INVALID = 0, + + /* This event is queued when the driver has bound to a UDC. */ + USB_RAW_EVENT_CONNECT = 1, + + /* This event is queued when a new control request arrived to ep0. */ + USB_RAW_EVENT_CONTROL = 2, + + /* The list might grow in the future. */ +}; + +/* + * struct usb_raw_event - argument for USB_RAW_IOCTL_EVENT_FETCH ioctl. + * @type: The type of the fetched event. + * @length: Length of the data buffer. Updated by the driver and set to the + * actual length of the fetched event data. + * @data: A buffer to store the fetched event data. + * + * Currently the fetched data buffer is empty for USB_RAW_EVENT_CONNECT, + * and contains struct usb_ctrlrequest for USB_RAW_EVENT_CONTROL. + */ +struct usb_raw_event { + __u32 type; + __u32 length; + __u8 data[0]; +}; + +#define USB_RAW_IO_FLAGS_ZERO 0x0001 +#define USB_RAW_IO_FLAGS_MASK 0x0001 + +static inline int usb_raw_io_flags_valid(__u16 flags) +{ + return (flags & ~USB_RAW_IO_FLAGS_MASK) == 0; +} + +static inline int usb_raw_io_flags_zero(__u16 flags) +{ + return (flags & USB_RAW_IO_FLAGS_ZERO); +} + +/* + * struct usb_raw_ep_io - argument for USB_RAW_IOCTL_EP0/EP_WRITE/READ ioctls. + * @ep: Endpoint handle as returned by USB_RAW_IOCTL_EP_ENABLE for + * USB_RAW_IOCTL_EP_WRITE/READ. Ignored for USB_RAW_IOCTL_EP0_WRITE/READ. + * @flags: When USB_RAW_IO_FLAGS_ZERO is specified, the zero flag is set on + * the submitted USB request, see include/linux/usb/gadget.h for details. + * @length: Length of data. + * @data: Data to send for USB_RAW_IOCTL_EP0/EP_WRITE. Buffer to store received + * data for USB_RAW_IOCTL_EP0/EP_READ. + */ +struct usb_raw_ep_io { + __u16 ep; + __u16 flags; + __u32 length; + __u8 data[0]; +}; + +/* + * Initializes a Raw Gadget instance. + * Accepts a pointer to the usb_raw_init struct as an argument. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init) + +/* + * Instructs Raw Gadget to bind to a UDC and start emulating a USB device. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_RUN _IO('U', 1) + +/* + * A blocking ioctl that waits for an event and returns fetched event data to + * the user. + * Accepts a pointer to the usb_raw_event struct. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event) + +/* + * Queues an IN (OUT for READ) urb as a response to the last control request + * received on endpoint 0, provided that was an IN (OUT for READ) request and + * waits until the urb is completed. Copies received data to user for READ. + * Accepts a pointer to the usb_raw_ep_io struct as an argument. + * Returns length of trasferred data on success or negative error code on + * failure. + */ +#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io) +#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io) + +/* + * Finds an endpoint that supports the transfer type specified in the + * descriptor and enables it. + * Accepts a pointer to the usb_endpoint_descriptor struct as an argument. + * Returns enabled endpoint handle on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) + +/* Disables specified endpoint. + * Accepts endpoint handle as an argument. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32) + +/* + * Queues an IN (OUT for READ) urb as a response to the last control request + * received on endpoint usb_raw_ep_io.ep, provided that was an IN (OUT for READ) + * request and waits until the urb is completed. Copies received data to user + * for READ. + * Accepts a pointer to the usb_raw_ep_io struct as an argument. + * Returns length of trasferred data on success or negative error code on + * failure. + */ +#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io) +#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io) + +/* + * Switches the gadget into the configured state. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9) + +/* + * Constrains UDC VBUS power usage. + * Accepts current limit in 2 mA units as an argument. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32) + +#endif /* _UAPI__LINUX_USB_RAW_GADGET_H */ diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index 3d6d63f9237c190158f3863bc0e7e831e426ea89..f44af31f7990dd1d45347354f777e47e4ffe6596 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -40,8 +40,33 @@ #include -#define VIRTIO_GPU_F_VIRGL 0 -#define VIRTIO_GPU_F_EDID 1 +/* + * VIRTIO_GPU_CMD_CTX_* + * VIRTIO_GPU_CMD_*_3D + */ +#define VIRTIO_GPU_F_VIRGL 0 + +/* + * VIRTIO_GPU_CMD_GET_EDID + */ +#define VIRTIO_GPU_F_EDID 1 +/* + * VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID + */ +#define VIRTIO_GPU_F_RESOURCE_UUID 2 +/* + * VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB + */ +#define VIRTIO_GPU_F_RESOURCE_BLOB 3 +/* + * VIRTIO_GPU_CMD_RESOURCE_MAP + * VIRTIO_GPU_CMD_RESOURCE_UMAP + */ +#define VIRTIO_GPU_F_HOST_VISIBLE 4 +/* + * VIRTIO_GPU_CMD_CTX_CREATE_V2 + */ +#define VIRTIO_GPU_F_VULKAN 5 enum virtio_gpu_ctrl_type { VIRTIO_GPU_UNDEFINED = 0, @@ -58,6 +83,10 @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_CMD_GET_CAPSET_INFO, VIRTIO_GPU_CMD_GET_CAPSET, VIRTIO_GPU_CMD_GET_EDID, + VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID, + VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB, + VIRTIO_GPU_CMD_RESOURCE_MAP, + VIRTIO_GPU_CMD_RESOURCE_UNMAP, /* 3d commands */ VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, @@ -79,6 +108,13 @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_RESP_OK_CAPSET_INFO, VIRTIO_GPU_RESP_OK_CAPSET, VIRTIO_GPU_RESP_OK_EDID, + VIRTIO_GPU_RESP_OK_RESOURCE_UUID, + VIRTIO_GPU_RESP_OK_MAP_INFO, + + /* CHROMIUM: legacy responses */ + VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO_LEGACY = 0x1104, + /* CHROMIUM: success responses */ + VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO = 0x11FF, /* error responses */ VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, @@ -87,6 +123,7 @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, + VIRTIO_GPU_RESP_ERR_INVALID_MEMORY_ID, }; #define VIRTIO_GPU_FLAG_FENCE (1 << 0) @@ -138,6 +175,7 @@ struct virtio_gpu_resource_unref { struct virtio_gpu_resource_create_2d { struct virtio_gpu_ctrl_hdr hdr; __le32 resource_id; + /* memory_type is VIRTIO_GPU_MEMORY_TRANSFER */ __le32 format; __le32 width; __le32 height; @@ -179,6 +217,7 @@ struct virtio_gpu_resource_attach_backing { struct virtio_gpu_ctrl_hdr hdr; __le32 resource_id; __le32 nr_entries; + /* struct virtio_gpu_mem_entry entries follow here */ }; /* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */ @@ -263,6 +302,7 @@ struct virtio_gpu_cmd_submit { }; #define VIRTIO_GPU_CAPSET_VIRGL 1 +#define VIRTIO_GPU_CAPSET_VIRGL2 2 /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ struct virtio_gpu_get_capset_info { @@ -308,6 +348,15 @@ struct virtio_gpu_resp_edid { __u8 edid[1024]; }; +/* VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO */ +struct virtio_gpu_resp_resource_plane_info { + struct virtio_gpu_ctrl_hdr hdr; + __le32 num_planes; + __le64 format_modifier; + __le32 strides[4]; + __le32 offsets[4]; +}; + #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) struct virtio_gpu_config { @@ -331,4 +380,68 @@ enum virtio_gpu_formats { VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, }; +/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */ +struct virtio_gpu_resource_assign_uuid { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; +}; + +/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */ +struct virtio_gpu_resp_resource_uuid { + struct virtio_gpu_ctrl_hdr hdr; + __u8 uuid[16]; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */ +struct virtio_gpu_resource_create_blob { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; +#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001 +#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002 +#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003 +#define VIRTIO_GPU_BLOB_MEM_HOSTSYS 0x0004 +#define VIRTIO_GPU_BLOB_MEM_HOSTSYS_GUEST 0x0005 + +#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001 +#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002 +#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 + /* zero is invalid blob mem */ + __le32 blob_mem; + __le32 blob_flags; + __le64 blob_id; + __le64 size; + __le32 nr_entries; + /* + * sizeof(nr_entries * virtio_gpu_mem_entry) bytes follow + */ +}; + +/* VIRTIO_GPU_CMD_RESOURCE_MAP */ +struct virtio_gpu_resource_map { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; + __le64 offset; +}; + +/* VIRTIO_GPU_RESP_OK_MAP_INFO */ +#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f +#define VIRTIO_GPU_MAP_CACHE_NONE 0x00 +#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01 +#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02 +#define VIRTIO_GPU_MAP_CACHE_WC 0x03 +struct virtio_gpu_resp_map_info { + struct virtio_gpu_ctrl_hdr hdr; + __u32 map_flags; + __u32 padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_UNMAP */ +struct virtio_gpu_resource_unmap { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; +}; + #endif diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 55105fd903b051a32b5f941a4faec8c5bcf1fe8a..50b81276d0e1d91b0f49f785ce37bc5fae10b43e 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -269,6 +269,7 @@ struct cam_req_mgr_link_control { #define CAM_MEM_FLAG_CACHE (1<<10) #define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11) #define CAM_MEM_FLAG_CDSP_OUTPUT (1<<12) +#define CAM_MEM_FLAG_CP_PIXEL (1<<13) #define CAM_MEM_MMU_MAX_HANDLE 16 diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 5f0fd5ebb94af1e3ce945af28f134fb1ccd11eba..3a50f6ca1619f1aa8f92ec8ea92e276bc26dc857 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -137,6 +137,7 @@ struct snd_compr_audio_info { #define SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER 0 #define SNDRV_COMPRESS_RENDER_MODE_STC_MASTER 1 #define SNDRV_COMPRESS_RENDER_MODE_TTP 2 +#define SNDRV_COMPRESS_RENDER_MODE_TTP_PASS_THROUGH 3 #define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0 #define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1 diff --git a/init/Makefile b/init/Makefile index 0320e1a0705d20778f016cee1c425b5da278868b..e5dd3192ed356ef2e8579c0a4c65035cc6fb90c1 100644 --- a/init/Makefile +++ b/init/Makefile @@ -33,5 +33,6 @@ $(obj)/version.o: include/generated/compile.h silent_chk_compile.h = : include/generated/compile.h: FORCE @$($(quiet)chk_compile.h) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \ - "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)" + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \ + "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" \ + "$(CC) $(KBUILD_CFLAGS)" "$(LD)" diff --git a/init/main.c b/init/main.c index 22f1c5b9e8e589fb6df27ff90388f76c49db917b..e2294e865a6b9abefb593af6c831648f8a0426aa 100644 --- a/init/main.c +++ b/init/main.c @@ -1022,7 +1022,7 @@ static int __ref kernel_init(void *unused) { int ret; #ifdef CONFIG_EARLY_SERVICES - int status = get_early_services_status(); + int status = 0; #endif kernel_init_freeable(); /* need to finish all async __init code before freeing the memory */ @@ -1037,6 +1037,7 @@ static int __ref kernel_init(void *unused) place_marker("M - DRIVER Kernel Boot Done"); #ifdef CONFIG_EARLY_SERVICES + status = get_early_services_status(); if (status) { struct kstat stat; /* Wait for early services SE policy load completion signal */ diff --git a/ipc/sem.c b/ipc/sem.c index d6dd2dc9ddad3c579ddab5d5b8e2730465fc9238..6adc245f3e02cd17fb9c0502e15e0a2a33e2557e 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -2248,11 +2248,9 @@ void exit_sem(struct task_struct *tsk) ipc_assert_locked_object(&sma->sem_perm); list_del(&un->list_id); - /* we are the last process using this ulp, acquiring ulp->lock - * isn't required. Besides that, we are also protected against - * IPC_RMID as we hold sma->sem_perm lock now - */ + spin_lock(&ulp->lock); list_del_rcu(&un->list_proc); + spin_unlock(&ulp->lock); /* perform adjustments registered in un */ for (i = 0; i < sma->sem_nsems; i++) { diff --git a/ipc/util.c b/ipc/util.c index 79b30eee32cd857c5dae1a71d1cdf37b34b07d0a..7989f5e532198b19d65d895b5d0326d4bfe0bd36 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -750,13 +750,13 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, total++; } + *new_pos = pos + 1; if (total >= ids->in_use) return NULL; for (; pos < IPCMNI; pos++) { ipc = idr_find(&ids->ipcs_idr, pos); if (ipc != NULL) { - *new_pos = pos + 1; rcu_read_lock(); ipc_lock_object(ipc); return ipc; diff --git a/kernel/audit.c b/kernel/audit.c index d301276bca584170e2d01de37f5372cbf5f4de38..aa6d5e39526b1840bf71869db6b9bcf5708f0db9 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1067,13 +1067,11 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature audit_log_end(ab); } -static int audit_set_feature(struct sk_buff *skb) +static int audit_set_feature(struct audit_features *uaf) { - struct audit_features *uaf; int i; BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names)); - uaf = nlmsg_data(nlmsg_hdr(skb)); /* if there is ever a version 2 we should handle that here */ @@ -1141,6 +1139,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { u32 seq; void *data; + int data_len; int err; struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; @@ -1154,6 +1153,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) seq = nlh->nlmsg_seq; data = nlmsg_data(nlh); + data_len = nlmsg_len(nlh); switch (msg_type) { case AUDIT_GET: { @@ -1177,7 +1177,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct audit_status s; memset(&s, 0, sizeof(s)); /* guard against past and future API changes */ - memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); + memcpy(&s, data, min_t(size_t, sizeof(s), data_len)); if (s.mask & AUDIT_STATUS_ENABLED) { err = audit_set_enabled(s.enabled); if (err < 0) @@ -1281,7 +1281,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return err; break; case AUDIT_SET_FEATURE: - err = audit_set_feature(skb); + if (data_len < sizeof(struct audit_features)) + return -EINVAL; + err = audit_set_feature(data); if (err) return err; break; @@ -1290,9 +1292,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: if (!audit_enabled && msg_type != AUDIT_USER_AVC) return 0; + /* exit early if there isn't at least one character to print */ + if (data_len < 2) + return -EINVAL; err = audit_filter(msg_type, AUDIT_FILTER_USER); if (err == 1) { /* match or error */ + char *str = data; + err = 0; if (msg_type == AUDIT_USER_TTY) { err = tty_audit_push(); @@ -1300,26 +1307,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; } audit_log_common_recv_msg(&ab, msg_type); - if (msg_type != AUDIT_USER_TTY) + if (msg_type != AUDIT_USER_TTY) { + /* ensure NULL termination */ + str[data_len - 1] = '\0'; audit_log_format(ab, " msg='%.*s'", AUDIT_MESSAGE_TEXT_MAX, - (char *)data); - else { - int size; - + str); + } else { audit_log_format(ab, " data="); - size = nlmsg_len(nlh); - if (size > 0 && - ((unsigned char *)data)[size - 1] == '\0') - size--; - audit_log_n_untrustedstring(ab, data, size); + if (data_len > 0 && str[data_len - 1] == '\0') + data_len--; + audit_log_n_untrustedstring(ab, str, data_len); } audit_log_end(ab); } break; case AUDIT_ADD_RULE: case AUDIT_DEL_RULE: - if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) + if (data_len < sizeof(struct audit_rule_data)) return -EINVAL; if (audit_enabled == AUDIT_LOCKED) { audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); @@ -1327,7 +1332,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) audit_log_end(ab); return -EPERM; } - err = audit_rule_change(msg_type, seq, data, nlmsg_len(nlh)); + err = audit_rule_change(msg_type, seq, data, data_len); break; case AUDIT_LIST_RULES: err = audit_list_rules_send(skb, seq); @@ -1341,7 +1346,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case AUDIT_MAKE_EQUIV: { void *bufp = data; u32 sizes[2]; - size_t msglen = nlmsg_len(nlh); + size_t msglen = data_len; char *old, *new; err = -EINVAL; @@ -1417,7 +1422,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) memset(&s, 0, sizeof(s)); /* guard against past and future API changes */ - memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); + memcpy(&s, data, min_t(size_t, sizeof(s), data_len)); /* check if new data is valid */ if ((s.enabled != 0 && s.enabled != 1) || (s.log_passwd != 0 && s.log_passwd != 1)) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 215c6e1ee026fa2006ceb090b243f393867a2b25..16cf396ea738a2c29769b18997f30fdb0d59a9a9 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -435,6 +435,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, bufp = data->buf; for (i = 0; i < data->field_count; i++) { struct audit_field *f = &entry->rule.fields[i]; + u32 f_val; err = -EINVAL; @@ -443,12 +444,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, goto exit_free; f->type = data->fields[i]; - f->val = data->values[i]; + f_val = data->values[i]; /* Support legacy tests for a valid loginuid */ - if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) { + if ((f->type == AUDIT_LOGINUID) && (f_val == AUDIT_UID_UNSET)) { f->type = AUDIT_LOGINUID_SET; - f->val = 0; + f_val = 0; entry->rule.pflags |= AUDIT_LOGINUID_LEGACY; } @@ -464,7 +465,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, case AUDIT_SUID: case AUDIT_FSUID: case AUDIT_OBJ_UID: - f->uid = make_kuid(current_user_ns(), f->val); + f->uid = make_kuid(current_user_ns(), f_val); if (!uid_valid(f->uid)) goto exit_free; break; @@ -473,12 +474,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, case AUDIT_SGID: case AUDIT_FSGID: case AUDIT_OBJ_GID: - f->gid = make_kgid(current_user_ns(), f->val); + f->gid = make_kgid(current_user_ns(), f_val); if (!gid_valid(f->gid)) goto exit_free; break; case AUDIT_SESSIONID: case AUDIT_ARCH: + f->val = f_val; entry->rule.arch_f = f; break; case AUDIT_SUBJ_USER: @@ -491,11 +493,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: - str = audit_unpack_string(&bufp, &remain, f->val); - if (IS_ERR(str)) + str = audit_unpack_string(&bufp, &remain, f_val); + if (IS_ERR(str)) { + err = PTR_ERR(str); goto exit_free; - entry->rule.buflen += f->val; - + } + entry->rule.buflen += f_val; + f->lsm_str = str; err = security_audit_rule_init(f->type, f->op, str, (void **)&f->lsm_rule); /* Keep currently invalid fields around in case they @@ -504,68 +508,71 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, pr_warn("audit rule for LSM \'%s\' is invalid\n", str); err = 0; - } - if (err) { - kfree(str); + } else if (err) goto exit_free; - } else - f->lsm_str = str; break; case AUDIT_WATCH: - str = audit_unpack_string(&bufp, &remain, f->val); - if (IS_ERR(str)) + str = audit_unpack_string(&bufp, &remain, f_val); + if (IS_ERR(str)) { + err = PTR_ERR(str); goto exit_free; - entry->rule.buflen += f->val; - - err = audit_to_watch(&entry->rule, str, f->val, f->op); + } + err = audit_to_watch(&entry->rule, str, f_val, f->op); if (err) { kfree(str); goto exit_free; } + entry->rule.buflen += f_val; break; case AUDIT_DIR: - str = audit_unpack_string(&bufp, &remain, f->val); - if (IS_ERR(str)) + str = audit_unpack_string(&bufp, &remain, f_val); + if (IS_ERR(str)) { + err = PTR_ERR(str); goto exit_free; - entry->rule.buflen += f->val; - + } err = audit_make_tree(&entry->rule, str, f->op); kfree(str); if (err) goto exit_free; + entry->rule.buflen += f_val; break; case AUDIT_INODE: + f->val = f_val; err = audit_to_inode(&entry->rule, f); if (err) goto exit_free; break; case AUDIT_FILTERKEY: - if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN) + if (entry->rule.filterkey || f_val > AUDIT_MAX_KEY_LEN) goto exit_free; - str = audit_unpack_string(&bufp, &remain, f->val); - if (IS_ERR(str)) + str = audit_unpack_string(&bufp, &remain, f_val); + if (IS_ERR(str)) { + err = PTR_ERR(str); goto exit_free; - entry->rule.buflen += f->val; + } + entry->rule.buflen += f_val; entry->rule.filterkey = str; break; case AUDIT_EXE: - if (entry->rule.exe || f->val > PATH_MAX) + if (entry->rule.exe || f_val > PATH_MAX) goto exit_free; - str = audit_unpack_string(&bufp, &remain, f->val); + str = audit_unpack_string(&bufp, &remain, f_val); if (IS_ERR(str)) { err = PTR_ERR(str); goto exit_free; } - entry->rule.buflen += f->val; - - audit_mark = audit_alloc_mark(&entry->rule, str, f->val); + audit_mark = audit_alloc_mark(&entry->rule, str, f_val); if (IS_ERR(audit_mark)) { kfree(str); err = PTR_ERR(audit_mark); goto exit_free; } + entry->rule.buflen += f_val; entry->rule.exe = audit_mark; break; + default: + f->val = f_val; + break; } } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 89d58554eb9910b1a6c251875efcf8a645ac44ae..d346cc46c9d52ed66ff3ddc62e3aca81f618ce30 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1473,7 +1473,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, union bpf_attr __user *uattr) { struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); - struct bpf_prog_info info = {}; + struct bpf_prog_info info; u32 info_len = attr->info.info_len; char __user *uinsns; u32 ulen; @@ -1484,6 +1484,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, return err; info_len = min_t(u32, sizeof(info), info_len); + memset(&info, 0, sizeof(info)); if (copy_from_user(&info, uinfo, info_len)) return -EFAULT; @@ -1529,7 +1530,7 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map, union bpf_attr __user *uattr) { struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); - struct bpf_map_info info = {}; + struct bpf_map_info info; u32 info_len = attr->info.info_len; int err; @@ -1538,6 +1539,7 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map, return err; info_len = min_t(u32, sizeof(info), info_len); + memset(&info, 0, sizeof(info)); info.type = map->map_type; info.id = map->id; info.key_size = map->key_size; @@ -1583,7 +1585,7 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) { - union bpf_attr attr = {}; + union bpf_attr attr; int err; if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN)) @@ -1595,6 +1597,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz size = min_t(u32, size, sizeof(attr)); /* copy attributes from user space, may be less than sizeof(bpf_attr) */ + memset(&attr, 0, sizeof(attr)); if (copy_from_user(&attr, uattr, size) != 0) return -EFAULT; diff --git a/kernel/cfi.c b/kernel/cfi.c index 967b0755c00e2155764f9997ecee5bfdfd391962..b23f6ede42ca6e2bb9488cd1b3adeec2eb420586 100644 --- a/kernel/cfi.c +++ b/kernel/cfi.c @@ -12,7 +12,6 @@ #include #include #include -#include #include /* Compiler-defined handler names */ diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 292b60183e57e00e23d85493a09d316a4c8dd283..1d166be184f7b3fd4754925c46f89f9fe3a15558 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -501,6 +501,7 @@ static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos) */ p++; if (p >= end) { + (*pos)++; return NULL; } else { *pos = *p; @@ -824,7 +825,7 @@ void cgroup1_release_agent(struct work_struct *work) pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL); - if (!pathbuf || !agentbuf) + if (!pathbuf || !agentbuf || !strlen(agentbuf)) goto out; spin_lock_irq(&css_set_lock); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index ea287f53c3a3da70843df836b95ff22083faffb0..a86b94e29d6bddd5afed002f8a3f9f7899bc6663 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4141,12 +4141,16 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it) } } while (!css_set_populated(cset) && list_empty(&cset->dying_tasks)); - if (!list_empty(&cset->tasks)) + if (!list_empty(&cset->tasks)) { it->task_pos = cset->tasks.next; - else if (!list_empty(&cset->mg_tasks)) + it->cur_tasks_head = &cset->tasks; + } else if (!list_empty(&cset->mg_tasks)) { it->task_pos = cset->mg_tasks.next; - else + it->cur_tasks_head = &cset->mg_tasks; + } else { it->task_pos = cset->dying_tasks.next; + it->cur_tasks_head = &cset->dying_tasks; + } it->tasks_head = &cset->tasks; it->mg_tasks_head = &cset->mg_tasks; @@ -4204,10 +4208,14 @@ static void css_task_iter_advance(struct css_task_iter *it) else it->task_pos = it->task_pos->next; - if (it->task_pos == it->tasks_head) + if (it->task_pos == it->tasks_head) { it->task_pos = it->mg_tasks_head->next; - if (it->task_pos == it->mg_tasks_head) + it->cur_tasks_head = it->mg_tasks_head; + } + if (it->task_pos == it->mg_tasks_head) { it->task_pos = it->dying_tasks_head->next; + it->cur_tasks_head = it->dying_tasks_head; + } if (it->task_pos == it->dying_tasks_head) css_task_iter_advance_css_set(it); } else { @@ -4226,11 +4234,12 @@ static void css_task_iter_advance(struct css_task_iter *it) goto repeat; /* and dying leaders w/o live member threads */ - if (!atomic_read(&task->signal->live)) + if (it->cur_tasks_head == it->dying_tasks_head && + !atomic_read(&task->signal->live)) goto repeat; } else { /* skip all dying ones */ - if (task->flags & PF_EXITING) + if (it->cur_tasks_head == it->dying_tasks_head) goto repeat; } } @@ -4339,6 +4348,9 @@ static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos) struct kernfs_open_file *of = s->private; struct css_task_iter *it = of->priv; + if (pos) + (*pos)++; + return css_task_iter_next(it); } @@ -4354,7 +4366,7 @@ static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos, * from position 0, so we can simply keep iterating on !0 *pos. */ if (!it) { - if (WARN_ON_ONCE((*pos)++)) + if (WARN_ON_ONCE((*pos))) return ERR_PTR(-EINVAL); it = kzalloc(sizeof(*it), GFP_KERNEL); @@ -4362,10 +4374,11 @@ static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos, return ERR_PTR(-ENOMEM); of->priv = it; css_task_iter_start(&cgrp->self, iter_flags, it); - } else if (!(*pos)++) { + } else if (!(*pos)) { css_task_iter_end(it); css_task_iter_start(&cgrp->self, iter_flags, it); - } + } else + return it->cur_task; return cgroup_procs_next(s, NULL, NULL); } @@ -5925,6 +5938,10 @@ void cgroup_sk_alloc(struct sock_cgroup_data *skcd) return; } + /* Don't associate the sock with unrelated interrupted task's cgroup. */ + if (in_interrupt()) + return; + rcu_read_lock(); while (true) { diff --git a/kernel/cpu.c b/kernel/cpu.c index aaebab62f2f2488e882cf6e2d3a36d57697cb591..c185e19820d608939e1151d7c531722b1d38dabe 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -498,8 +498,7 @@ static int bringup_wait_for_ap(unsigned int cpu) if (WARN_ON_ONCE((!cpu_online(cpu)))) return -ECANCELED; - /* Unpark the stopper thread and the hotplug thread of the target cpu */ - stop_machine_unpark(cpu); + /* Unpark the hotplug thread of the target cpu */ kthread_unpark(st->thread); /* @@ -1089,8 +1088,8 @@ void notify_cpu_starting(unsigned int cpu) /* * Called from the idle task. Wake up the controlling task which brings the - * stopper and the hotplug thread of the upcoming CPU up and then delegates - * the rest of the online bringup to the hotplug thread. + * hotplug thread of the upcoming CPU up and then delegates the rest of the + * online bringup to the hotplug thread. */ void cpuhp_online_idle(enum cpuhp_state state) { @@ -1100,6 +1099,12 @@ void cpuhp_online_idle(enum cpuhp_state state) if (state != CPUHP_AP_ONLINE_IDLE) return; + /* + * Unpart the stopper thread before we start the idle loop (and start + * scheduling); this ensures the stopper task is always available. + */ + stop_machine_unpark(smp_processor_id()); + st->state = CPUHP_AP_ONLINE_IDLE; complete_ap_thread(st, true); } @@ -2174,10 +2179,8 @@ int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) */ cpuhp_offline_cpu_device(cpu); } - if (!ret) { + if (!ret) cpu_smt_control = ctrlval; - arch_smt_update(); - } cpu_maps_update_done(); return ret; } @@ -2188,7 +2191,6 @@ int cpuhp_smt_enable(void) cpu_maps_update_begin(); cpu_smt_control = CPU_SMT_ENABLED; - arch_smt_update(); for_each_present_cpu(cpu) { /* Skip online CPUs and CPUs on offline nodes */ if (cpu_online(cpu) || !node_online(cpu_to_node(cpu))) diff --git a/kernel/events/core.c b/kernel/events/core.c index 52cd55918417775082776d474febf12988a7895f..0033bc900c4bcf0e3e41ab1b2fcf770b4c0579e2 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5653,7 +5653,15 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) */ user_lock_limit *= num_online_cpus(); - user_locked = atomic_long_read(&user->locked_vm) + user_extra; + user_locked = atomic_long_read(&user->locked_vm); + + /* + * sysctl_perf_event_mlock may have changed, so that + * user->locked_vm > user_lock_limit + */ + if (user_locked > user_lock_limit) + user_locked = user_lock_limit; + user_locked += user_extra; if (user_locked > user_lock_limit) extra = user_locked - user_lock_limit; @@ -6323,9 +6331,12 @@ static u64 perf_virt_to_phys(u64 virt) * Try IRQ-safe __get_user_pages_fast first. * If failed, leave phys_addr as 0. */ - if ((current->mm != NULL) && - (__get_user_pages_fast(virt, 1, 0, &p) == 1)) - phys_addr = page_to_phys(p) + virt % PAGE_SIZE; + if (current->mm != NULL) { + pagefault_disable(); + if (__get_user_pages_fast(virt, 1, 0, &p) == 1) + phys_addr = page_to_phys(p) + virt % PAGE_SIZE; + pagefault_enable(); + } if (p) put_page(p); @@ -6812,10 +6823,17 @@ static void perf_event_task_output(struct perf_event *event, goto out; task_event->event_id.pid = perf_event_pid(event, task); - task_event->event_id.ppid = perf_event_pid(event, current); - task_event->event_id.tid = perf_event_tid(event, task); - task_event->event_id.ptid = perf_event_tid(event, current); + + if (task_event->event_id.header.type == PERF_RECORD_EXIT) { + task_event->event_id.ppid = perf_event_pid(event, + task->real_parent); + task_event->event_id.ptid = perf_event_pid(event, + task->real_parent); + } else { /* PERF_RECORD_FORK */ + task_event->event_id.ppid = perf_event_pid(event, current); + task_event->event_id.ptid = perf_event_tid(event, current); + } task_event->event_id.time = perf_event_clock(event); diff --git a/kernel/futex.c b/kernel/futex.c index f5aae14c247b65b394ff6964dc8f3b350ad5e054..2921ebaa14676f3021e662897631146403600508 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -401,9 +401,9 @@ static inline int hb_waiters_pending(struct futex_hash_bucket *hb) */ static struct futex_hash_bucket *hash_futex(union futex_key *key) { - u32 hash = jhash2((u32*)&key->both.word, - (sizeof(key->both.word)+sizeof(key->both.ptr))/4, + u32 hash = jhash2((u32 *)key, offsetof(typeof(*key), both.offset) / 4, key->both.offset); + return &futex_queues[hash & (futex_hashsize - 1)]; } @@ -445,7 +445,7 @@ static void get_futex_key_refs(union futex_key *key) switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) { case FUT_OFF_INODE: - ihold(key->shared.inode); /* implies smp_mb(); (B) */ + smp_mb(); /* explicit smp_mb(); (B) */ break; case FUT_OFF_MMSHARED: futex_get_mm(key); /* implies smp_mb(); (B) */ @@ -479,7 +479,6 @@ static void drop_futex_key_refs(union futex_key *key) switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) { case FUT_OFF_INODE: - iput(key->shared.inode); break; case FUT_OFF_MMSHARED: mmdrop(key->private.mm); @@ -487,6 +486,46 @@ static void drop_futex_key_refs(union futex_key *key) } } +/* + * Generate a machine wide unique identifier for this inode. + * + * This relies on u64 not wrapping in the life-time of the machine; which with + * 1ns resolution means almost 585 years. + * + * This further relies on the fact that a well formed program will not unmap + * the file while it has a (shared) futex waiting on it. This mapping will have + * a file reference which pins the mount and inode. + * + * If for some reason an inode gets evicted and read back in again, it will get + * a new sequence number and will _NOT_ match, even though it is the exact same + * file. + * + * It is important that match_futex() will never have a false-positive, esp. + * for PI futexes that can mess up the state. The above argues that false-negatives + * are only possible for malformed programs. + */ +static u64 get_inode_sequence_number(struct inode *inode) +{ + static atomic64_t i_seq; + u64 old; + + /* Does the inode already have a sequence number? */ + old = atomic64_read(&inode->i_sequence); + if (likely(old)) + return old; + + for (;;) { + u64 new = atomic64_add_return(1, &i_seq); + if (WARN_ON_ONCE(!new)) + continue; + + old = atomic64_cmpxchg_relaxed(&inode->i_sequence, 0, new); + if (old) + return old; + return new; + } +} + /** * get_futex_key() - Get parameters which are the keys for a futex * @uaddr: virtual address of the futex @@ -499,9 +538,15 @@ static void drop_futex_key_refs(union futex_key *key) * * The key words are stored in @key on success. * - * For shared mappings, it's (page->index, file_inode(vma->vm_file), - * offset_within_page). For private mappings, it's (uaddr, current->mm). - * We can usually work out the index without swapping in the page. + * For shared mappings (when @fshared), the key is: + * ( inode->i_sequence, page->index, offset_within_page ) + * [ also see get_inode_sequence_number() ] + * + * For private mappings (or when !@fshared), the key is: + * ( current->mm, address, 0 ) + * + * This allows (cross process, where applicable) identification of the futex + * without keeping the page pinned for the duration of the FUTEX_WAIT. * * lock_page() might sleep, the caller should not hold a spinlock. */ @@ -641,8 +686,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) key->private.mm = mm; key->private.address = address; - get_futex_key_refs(key); /* implies smp_mb(); (B) */ - } else { struct inode *inode; @@ -674,40 +717,14 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) goto again; } - /* - * Take a reference unless it is about to be freed. Previously - * this reference was taken by ihold under the page lock - * pinning the inode in place so i_lock was unnecessary. The - * only way for this check to fail is if the inode was - * truncated in parallel which is almost certainly an - * application bug. In such a case, just retry. - * - * We are not calling into get_futex_key_refs() in file-backed - * cases, therefore a successful atomic_inc return below will - * guarantee that get_futex_key() will still imply smp_mb(); (B). - */ - if (!atomic_inc_not_zero(&inode->i_count)) { - rcu_read_unlock(); - put_page(page); - - goto again; - } - - /* Should be impossible but lets be paranoid for now */ - if (WARN_ON_ONCE(inode->i_mapping != mapping)) { - err = -EFAULT; - rcu_read_unlock(); - iput(inode); - - goto out; - } - key->both.offset |= FUT_OFF_INODE; /* inode-based key */ - key->shared.inode = inode; + key->shared.i_seq = get_inode_sequence_number(inode); key->shared.pgoff = basepage_index(tail); rcu_read_unlock(); } + get_futex_key_refs(key); /* implies smp_mb(); (B) */ + out: put_page(page); return err; diff --git a/kernel/gcov/fs.c b/kernel/gcov/fs.c index 6e40ff6be083dab77ad46edc01dbd95e4c0a854f..291e0797125b694334db84869b5db3676531d335 100644 --- a/kernel/gcov/fs.c +++ b/kernel/gcov/fs.c @@ -109,9 +109,9 @@ static void *gcov_seq_next(struct seq_file *seq, void *data, loff_t *pos) { struct gcov_iterator *iter = data; + (*pos)++; if (gcov_iter_next(iter)) return NULL; - (*pos)++; return iter; } diff --git a/kernel/gen_kheaders.sh b/kernel/gen_kheaders.sh index 9a34e1d9bd7f97eb82e6ceb0042c7f5502742041..9ff449888d9cda491a39b0ffeba27c31d47a72b3 100755 --- a/kernel/gen_kheaders.sh +++ b/kernel/gen_kheaders.sh @@ -4,24 +4,12 @@ # This script generates an archive consisting of kernel headers # for CONFIG_IKHEADERS. set -e -spath="$(dirname "$(readlink -f "$0")")" -kroot="$spath/.." +sfile="$(readlink -f "$0")" outdir="$(pwd)" tarfile=$1 cpio_dir=$outdir/$tarfile.tmp -# Script filename relative to the kernel source root -# We add it to the archive because it is small and any changes -# to this script will also cause a rebuild of the archive. -sfile="$(realpath --relative-to $kroot "$(readlink -f "$0")")" - -src_file_list=" -include/ -arch/$SRCARCH/include/ -$sfile -" - -obj_file_list=" +dir_list=" include/ arch/$SRCARCH/include/ " @@ -33,33 +21,29 @@ arch/$SRCARCH/include/ # Uncomment it for debugging. # if [ ! -f /tmp/iter ]; then iter=1; echo 1 > /tmp/iter; # else iter=$(($(cat /tmp/iter) + 1)); echo $iter > /tmp/iter; fi -# find $src_file_list -type f | xargs ls -lR > /tmp/src-ls-$iter -# find $obj_file_list -type f | xargs ls -lR > /tmp/obj-ls-$iter +# find $src_file_list -name "*.h" | xargs ls -l > /tmp/src-ls-$iter +# find $obj_file_list -name "*.h" | xargs ls -l > /tmp/obj-ls-$iter # include/generated/compile.h is ignored because it is touched even when none # of the source files changed. This causes pointless regeneration, so let us # ignore them for md5 calculation. -pushd $kroot > /dev/null -src_files_md5="$(find $src_file_list -type f | +pushd $srctree > /dev/null +src_files_md5="$(find $dir_list -name "*.h" | grep -v "include/generated/compile.h" | grep -v "include/generated/autoconf.h" | - grep -v "include/config/auto.conf" | - grep -v "include/config/auto.conf.cmd" | - grep -v "include/config/tristate.conf" | - xargs ls -lR | md5sum | cut -d ' ' -f1)" + xargs ls -l | md5sum | cut -d ' ' -f1)" popd > /dev/null -obj_files_md5="$(find $obj_file_list -type f | +obj_files_md5="$(find $dir_list -name "*.h" | grep -v "include/generated/compile.h" | grep -v "include/generated/autoconf.h" | - grep -v "include/config/auto.conf" | - grep -v "include/config/auto.conf.cmd" | - grep -v "include/config/tristate.conf" | - xargs ls -lR | md5sum | cut -d ' ' -f1)" - + xargs ls -l | md5sum | cut -d ' ' -f1)" +# Any changes to this script will also cause a rebuild of the archive. +this_file_md5="$(ls -l $sfile | md5sum | cut -d ' ' -f1)" if [ -f $tarfile ]; then tarfile_md5="$(md5sum $tarfile | cut -d ' ' -f1)"; fi if [ -f kernel/kheaders.md5 ] && [ "$(cat kernel/kheaders.md5|head -1)" == "$src_files_md5" ] && [ "$(cat kernel/kheaders.md5|head -2|tail -1)" == "$obj_files_md5" ] && + [ "$(cat kernel/kheaders.md5|head -3|tail -1)" == "$this_file_md5" ] && [ "$(cat kernel/kheaders.md5|tail -1)" == "$tarfile_md5" ]; then exit fi @@ -71,16 +55,16 @@ fi rm -rf $cpio_dir mkdir $cpio_dir -pushd $kroot > /dev/null -for f in $src_file_list; - do find "$f" ! -name "*.cmd" ! -name ".*"; +pushd $srctree > /dev/null +for f in $dir_list; + do find "$f" -name "*.h"; done | cpio --quiet -pd $cpio_dir popd > /dev/null # The second CPIO can complain if files already exist which can # happen with out of tree builds. Just silence CPIO for now. -for f in $obj_file_list; - do find "$f" ! -name "*.cmd" ! -name ".*"; +for f in $dir_list; + do find "$f" -name "*.h"; done | cpio --quiet -pd $cpio_dir >/dev/null 2>&1 # Remove comments except SDPX lines @@ -91,6 +75,7 @@ tar -Jcf $tarfile -C $cpio_dir/ . > /dev/null echo "$src_files_md5" > kernel/kheaders.md5 echo "$obj_files_md5" >> kernel/kheaders.md5 +echo "$this_file_md5" >> kernel/kheaders.md5 echo "$(md5sum $tarfile | cut -d ' ' -f1)" >> kernel/kheaders.md5 rm -rf $cpio_dir diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 317fc759de76160061cda5699a63998d2b3e8dc0..9da08b53d06a20d8f452757c9721af7d40bee2ad 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -480,8 +481,22 @@ static bool irq_may_run(struct irq_desc *desc) * If the interrupt is not in progress and is not an armed * wakeup interrupt, proceed. */ - if (!irqd_has_set(&desc->irq_data, mask)) + if (!irqd_has_set(&desc->irq_data, mask)) { +#ifdef CONFIG_PM_SLEEP + if (unlikely(desc->no_suspend_depth && + irqd_is_wakeup_set(&desc->irq_data))) { + unsigned int irq = irq_desc_get_irq(desc); + const char *name = "(unnamed)"; + + if (desc->action && desc->action->name) + name = desc->action->name; + + log_abnormal_wakeup_reason("misconfigured IRQ %u %s", + irq, name); + } +#endif return true; + } /* * If the interrupt is an armed wakeup source, mark it pending diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 4ef7f3b820ce6aab4629fcf421bf53c6f0972de7..5230c47fc43e1e3f124b1ed62fb7b43173c07ef4 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -119,8 +119,6 @@ static inline void unregister_handler_proc(unsigned int irq, extern bool irq_can_set_affinity_usr(unsigned int irq); -extern int irq_select_affinity_usr(unsigned int irq); - extern void irq_set_thread_affinity(struct irq_desc *desc); extern int irq_do_set_affinity(struct irq_data *data, diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 0f0e7975a3093486e3e9c2e45e9ece05f052c33d..0d54f8256b9f401145e87ccd03820e676a2c8669 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1372,6 +1372,11 @@ int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs, void *arg) { + if (!domain->ops->alloc) { + pr_debug("domain->ops->alloc() is NULL\n"); + return -ENOSYS; + } + return domain->ops->alloc(domain, irq_base, nr_irqs, arg); } @@ -1409,11 +1414,6 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, return -EINVAL; } - if (!domain->ops->alloc) { - pr_debug("domain->ops->alloc() is NULL\n"); - return -ENOSYS; - } - if (realloc && irq_base >= 0) { virq = irq_base; } else { @@ -1538,6 +1538,7 @@ int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg) if (rv) { /* Restore the original irq_data. */ *root_irq_data = *child_irq_data; + kfree(child_irq_data); goto error; } diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 9c86a3e451101feb0661982081ef21fcf489006c..5277949e82e09e1ecdc7a92f4d8471e1c4171248 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -224,7 +224,11 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask, if (desc->affinity_notify) { kref_get(&desc->affinity_notify->kref); - schedule_work(&desc->affinity_notify->work); + if (!schedule_work(&desc->affinity_notify->work)) { + /* Work was already scheduled, drop our extra ref */ + kref_put(&desc->affinity_notify->kref, + desc->affinity_notify->release); + } } irqd_set(data, IRQD_AFFINITY_SET); @@ -324,7 +328,10 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) raw_spin_unlock_irqrestore(&desc->lock, flags); if (old_notify) { - cancel_work_sync(&old_notify->work); + if (cancel_work_sync(&old_notify->work)) { + /* Pending work had a ref, put that one too */ + kref_put(&old_notify->kref, old_notify->release); + } kref_put(&old_notify->kref, old_notify->release); } @@ -382,23 +389,9 @@ int irq_setup_affinity(struct irq_desc *desc) { return irq_select_affinity(irq_desc_get_irq(desc)); } -#endif +#endif /* CONFIG_AUTO_IRQ_AFFINITY */ +#endif /* CONFIG_SMP */ -/* - * Called when a bogus affinity is set via /proc/irq - */ -int irq_select_affinity_usr(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - unsigned long flags; - int ret; - - raw_spin_lock_irqsave(&desc->lock, flags); - ret = irq_setup_affinity(desc); - raw_spin_unlock_irqrestore(&desc->lock, flags); - return ret; -} -#endif /** * irq_set_vcpu_affinity - Set vcpu affinity for the interrupt diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index d4e8d20dd64e39af8ca0e99043ad5f59379f98e0..374108c5bbdeffd0c8415a8718dea50fe88986c1 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -117,6 +117,28 @@ static int irq_affinity_list_proc_show(struct seq_file *m, void *v) return show_irq_affinity(AFFINITY_LIST, m); } +#ifndef CONFIG_AUTO_IRQ_AFFINITY +static inline int irq_select_affinity_usr(unsigned int irq) +{ + /* + * If the interrupt is started up already then this fails. The + * interrupt is assigned to an online CPU already. There is no + * point to move it around randomly. Tell user space that the + * selected mask is bogus. + * + * If not then any change to the affinity is pointless because the + * startup code invokes irq_setup_affinity() which will select + * a online CPU anyway. + */ + return -EINVAL; +} +#else +/* ALPHA magic affinity auto selector. Keep it for historical reasons. */ +static inline int irq_select_affinity_usr(unsigned int irq) +{ + return irq_select_affinity(irq); +} +#endif static ssize_t write_irq_affinity(int type, struct file *file, const char __user *buffer, size_t count, loff_t *pos) diff --git a/kernel/kmod.c b/kernel/kmod.c index bc6addd9152b4db58c57757f1fe0a2911a16e459..a2de58de6ab6259c266e0901e3e9dd212074cf83 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -120,7 +120,7 @@ static int call_modprobe(char *module_name, int wait) * invoke it. * * If module auto-loading support is disabled then this function - * becomes a no-operation. + * simply returns -ENOENT. */ int __request_module(bool wait, const char *fmt, ...) { @@ -137,7 +137,7 @@ int __request_module(bool wait, const char *fmt, ...) WARN_ON_ONCE(wait && current_is_async()); if (!modprobe_path[0]) - return 0; + return -ENOENT; va_start(args, fmt); ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); diff --git a/kernel/kprobes.c b/kernel/kprobes.c index d0fe20a5475f722b0e7fa303b4d8ff08b8b3f647..66f1818d47620be11c91a742f975399be18c5db7 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -523,6 +523,8 @@ static void do_unoptimize_kprobes(void) arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list); /* Loop free_list for disarming */ list_for_each_entry_safe(op, tmp, &freeing_list, list) { + /* Switching from detour code to origin */ + op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; /* Disarm probes if marked disabled */ if (kprobe_disabled(&op->kp)) arch_disarm_kprobe(&op->kp); @@ -623,6 +625,18 @@ void wait_for_kprobe_optimizer(void) mutex_unlock(&kprobe_mutex); } +static bool optprobe_queued_unopt(struct optimized_kprobe *op) +{ + struct optimized_kprobe *_op; + + list_for_each_entry(_op, &unoptimizing_list, list) { + if (op == _op) + return true; + } + + return false; +} + /* Optimize kprobe if p is ready to be optimized */ static void optimize_kprobe(struct kprobe *p) { @@ -644,17 +658,21 @@ static void optimize_kprobe(struct kprobe *p) return; /* Check if it is already optimized. */ - if (op->kp.flags & KPROBE_FLAG_OPTIMIZED) + if (op->kp.flags & KPROBE_FLAG_OPTIMIZED) { + if (optprobe_queued_unopt(op)) { + /* This is under unoptimizing. Just dequeue the probe */ + list_del_init(&op->list); + } return; + } op->kp.flags |= KPROBE_FLAG_OPTIMIZED; - if (!list_empty(&op->list)) - /* This is under unoptimizing. Just dequeue the probe */ - list_del_init(&op->list); - else { - list_add(&op->list, &optimizing_list); - kick_kprobe_optimizer(); - } + /* On unoptimizing/optimizing_list, op must have OPTIMIZED flag */ + if (WARN_ON_ONCE(!list_empty(&op->list))) + return; + + list_add(&op->list, &optimizing_list); + kick_kprobe_optimizer(); } /* Short cut to direct unoptimizing */ @@ -662,6 +680,7 @@ static void force_unoptimize_kprobe(struct optimized_kprobe *op) { lockdep_assert_cpus_held(); arch_unoptimize_kprobe(op); + op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; if (kprobe_disabled(&op->kp)) arch_disarm_kprobe(&op->kp); } @@ -675,31 +694,33 @@ static void unoptimize_kprobe(struct kprobe *p, bool force) return; /* This is not an optprobe nor optimized */ op = container_of(p, struct optimized_kprobe, kp); - if (!kprobe_optimized(p)) { - /* Unoptimized or unoptimizing case */ - if (force && !list_empty(&op->list)) { - /* - * Only if this is unoptimizing kprobe and forced, - * forcibly unoptimize it. (No need to unoptimize - * unoptimized kprobe again :) - */ - list_del_init(&op->list); - force_unoptimize_kprobe(op); - } + if (!kprobe_optimized(p)) return; - } - op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; if (!list_empty(&op->list)) { - /* Dequeue from the optimization queue */ - list_del_init(&op->list); + if (optprobe_queued_unopt(op)) { + /* Queued in unoptimizing queue */ + if (force) { + /* + * Forcibly unoptimize the kprobe here, and queue it + * in the freeing list for release afterwards. + */ + force_unoptimize_kprobe(op); + list_move(&op->list, &freeing_list); + } + } else { + /* Dequeue from the optimizing queue */ + list_del_init(&op->list); + op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; + } return; } + /* Optimized kprobe case */ - if (force) + if (force) { /* Forcibly update the code: this is a special case */ force_unoptimize_kprobe(op); - else { + } else { list_add(&op->list, &unoptimizing_list); kick_kprobe_optimizer(); } diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 90a3469a7a888780f5bdce835234d5849aa22d7a..03e3ab61a2edd6ff7645be5dcdd1c99694085983 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -1297,9 +1297,11 @@ unsigned long lockdep_count_forward_deps(struct lock_class *class) this.class = class; raw_local_irq_save(flags); + current->lockdep_recursion = 1; arch_spin_lock(&lockdep_lock); ret = __lockdep_count_forward_deps(&this); arch_spin_unlock(&lockdep_lock); + current->lockdep_recursion = 0; raw_local_irq_restore(flags); return ret; @@ -1324,9 +1326,11 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class) this.class = class; raw_local_irq_save(flags); + current->lockdep_recursion = 1; arch_spin_lock(&lockdep_lock); ret = __lockdep_count_backward_deps(&this); arch_spin_unlock(&lockdep_lock); + current->lockdep_recursion = 0; raw_local_irq_restore(flags); return ret; diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index 6dca260eeccf29bca8ccd92ba543e6e262c6c32b..032868be325940e30554ad00c8fdb8f7aa921303 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -723,10 +723,10 @@ static void __torture_print_stats(char *page, if (statp[i].n_lock_fail) fail = true; sum += statp[i].n_lock_acquired; - if (max < statp[i].n_lock_fail) - max = statp[i].n_lock_fail; - if (min > statp[i].n_lock_fail) - min = statp[i].n_lock_fail; + if (max < statp[i].n_lock_acquired) + max = statp[i].n_lock_acquired; + if (min > statp[i].n_lock_acquired) + min = statp[i].n_lock_acquired; } page += sprintf(page, "%s: Total: %lld Max/Min: %ld/%ld %s Fail: %d %s\n", diff --git a/kernel/module.c b/kernel/module.c index 125b1cedc65dd89a0c9f99790bf995dcd2e6bff5..31c5623457e8e0c2596a7b8ee1cb4cde026dd09a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1730,6 +1730,8 @@ static int module_add_modinfo_attrs(struct module *mod) error_out: if (i > 0) module_remove_modinfo_attrs(mod, --i); + else + kfree(mod->modinfo_attrs); return error; } diff --git a/kernel/notifier.c b/kernel/notifier.c index 6196af8a82230024ba98647c7fe946bf842bd102..59a1e9b48a6af80d834c8fc764d07da0572cc4fe 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c @@ -552,7 +552,7 @@ NOKPROBE_SYMBOL(notify_die); int register_die_notifier(struct notifier_block *nb) { - vmalloc_sync_all(); + vmalloc_sync_mappings(); return atomic_notifier_chain_register(&die_chain, nb); } EXPORT_SYMBOL_GPL(register_die_notifier); diff --git a/kernel/padata.c b/kernel/padata.c index 87540ce72aea6bcef0126e8d172b2b8cd8d6f80f..a71620d2b8bab46d81d4f590a6212a7f010d1eba 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -34,6 +34,8 @@ #define MAX_OBJ_NUM 1000 +static void padata_free_pd(struct parallel_data *pd); + static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) { int cpu, target_cpu; @@ -292,6 +294,7 @@ static void padata_serial_worker(struct work_struct *serial_work) struct padata_serial_queue *squeue; struct parallel_data *pd; LIST_HEAD(local_list); + int cnt; local_bh_disable(); squeue = container_of(serial_work, struct padata_serial_queue, work); @@ -301,6 +304,8 @@ static void padata_serial_worker(struct work_struct *serial_work) list_replace_init(&squeue->serial.list, &local_list); spin_unlock(&squeue->serial.lock); + cnt = 0; + while (!list_empty(&local_list)) { struct padata_priv *padata; @@ -310,9 +315,12 @@ static void padata_serial_worker(struct work_struct *serial_work) list_del_init(&padata->list); padata->serial(padata); - atomic_dec(&pd->refcnt); + cnt++; } local_bh_enable(); + + if (atomic_sub_and_test(cnt, &pd->refcnt)) + padata_free_pd(pd); } /** @@ -435,7 +443,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst, setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd); atomic_set(&pd->seq_nr, -1); atomic_set(&pd->reorder_objects, 0); - atomic_set(&pd->refcnt, 0); + atomic_set(&pd->refcnt, 1); pd->pinst = pinst; spin_lock_init(&pd->lock); @@ -460,31 +468,6 @@ static void padata_free_pd(struct parallel_data *pd) kfree(pd); } -/* Flush all objects out of the padata queues. */ -static void padata_flush_queues(struct parallel_data *pd) -{ - int cpu; - struct padata_parallel_queue *pqueue; - struct padata_serial_queue *squeue; - - for_each_cpu(cpu, pd->cpumask.pcpu) { - pqueue = per_cpu_ptr(pd->pqueue, cpu); - flush_work(&pqueue->work); - } - - del_timer_sync(&pd->timer); - - if (atomic_read(&pd->reorder_objects)) - padata_reorder(pd); - - for_each_cpu(cpu, pd->cpumask.cbcpu) { - squeue = per_cpu_ptr(pd->squeue, cpu); - flush_work(&squeue->work); - } - - BUG_ON(atomic_read(&pd->refcnt) != 0); -} - static void __padata_start(struct padata_instance *pinst) { pinst->flags |= PADATA_INIT; @@ -498,10 +481,6 @@ static void __padata_stop(struct padata_instance *pinst) pinst->flags &= ~PADATA_INIT; synchronize_rcu(); - - get_online_cpus(); - padata_flush_queues(pinst->pd); - put_online_cpus(); } /* Replace the internal control structure with a new one. */ @@ -522,8 +501,8 @@ static void padata_replace(struct padata_instance *pinst, if (!cpumask_equal(pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu)) notification_mask |= PADATA_CPU_SERIAL; - padata_flush_queues(pd_old); - padata_free_pd(pd_old); + if (atomic_dec_and_test(&pd_old->refcnt)) + padata_free_pd(pd_old); if (notification_mask) blocking_notifier_call_chain(&pinst->cpumask_change_notifier, @@ -626,8 +605,8 @@ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type, struct cpumask *serial_mask, *parallel_mask; int err = -EINVAL; - mutex_lock(&pinst->lock); get_online_cpus(); + mutex_lock(&pinst->lock); switch (cpumask_type) { case PADATA_CPU_PARALLEL: @@ -645,8 +624,8 @@ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type, err = __padata_set_cpumasks(pinst, parallel_mask, serial_mask); out: - put_online_cpus(); mutex_unlock(&pinst->lock); + put_online_cpus(); return err; } diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 376716bfd057e6a0b360a56315bda7e0928e9a03..4b007fd99af29a744ff6b6e625d4d08a7ac3a268 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -897,6 +897,13 @@ static int software_resume(void) error = freeze_processes(); if (error) goto Close_Finish; + + error = freeze_kernel_threads(); + if (error) { + thaw_processes(); + goto Close_Finish; + } + error = load_image_and_restore(); thaw_processes(); place_marker("M - PM: Thaw processes completed!"); diff --git a/kernel/power/process.c b/kernel/power/process.c index 659cd91f1c6529904584878cf5db7c2d15bbe5d5..1ae7f93efde952ecaaa285abf37ae538c91089a8 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -23,7 +23,6 @@ #include #include #include -#include /* * Timeout for stopping processes @@ -40,9 +39,6 @@ static int try_to_freeze_tasks(bool user_only) unsigned int elapsed_msecs; bool wakeup = false; int sleep_usecs = USEC_PER_MSEC; -#ifdef CONFIG_PM_SLEEP - char suspend_abort[MAX_SUSPEND_ABORT_LEN]; -#endif start = ktime_get_boottime(); @@ -72,11 +68,6 @@ static int try_to_freeze_tasks(bool user_only) break; if (pm_wakeup_pending()) { -#ifdef CONFIG_PM_SLEEP - pm_get_active_wakeup_sources(suspend_abort, - MAX_SUSPEND_ABORT_LEN); - log_suspend_abort_reason(suspend_abort); -#endif wakeup = true; break; } diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index ad7e726085be448d61a3e43c8441c620d68d0e2f..2ac0ed3b08167cd2ef134ad2dc73b9ce6230bf7a 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -149,6 +149,7 @@ static void s2idle_loop(void) break; pm_wakeup_clear(false); + clear_wakeup_reasons(); } pm_pr_dbg("resume from suspend-to-idle\n"); @@ -362,6 +363,7 @@ static int suspend_prepare(suspend_state_t state) if (!error) return 0; + log_suspend_abort_reason("One or more tasks refusing to freeze"); suspend_stats.failed_freeze++; dpm_save_failed_step(SUSPEND_FREEZE); Finish: @@ -391,7 +393,6 @@ void __weak arch_suspend_enable_irqs(void) */ static int suspend_enter(suspend_state_t state, bool *wakeup) { - char suspend_abort[MAX_SUSPEND_ABORT_LEN]; int error, last_dev; error = platform_suspend_prepare(state); @@ -403,8 +404,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; last_dev %= REC_FAILED_NUM; pr_err("late suspend of devices failed\n"); - log_suspend_abort_reason("%s device failed to power down", - suspend_stats.failed_devs[last_dev]); + log_suspend_abort_reason("late suspend of %s device failed", + suspend_stats.failed_devs[last_dev]); goto Platform_finish; } error = platform_suspend_prepare_late(state); @@ -422,7 +423,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) last_dev %= REC_FAILED_NUM; pr_err("noirq suspend of devices failed\n"); log_suspend_abort_reason("noirq suspend of %s device failed", - suspend_stats.failed_devs[last_dev]); + suspend_stats.failed_devs[last_dev]); goto Platform_early_resume; } error = platform_suspend_prepare_noirq(state); @@ -451,9 +452,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) trace_suspend_resume(TPS("machine_suspend"), state, false); } else if (*wakeup) { - pm_get_active_wakeup_sources(suspend_abort, - MAX_SUSPEND_ABORT_LEN); - log_suspend_abort_reason(suspend_abort); error = -EBUSY; } syscore_resume(); @@ -486,7 +484,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) */ int suspend_devices_and_enter(suspend_state_t state) { - int error, last_dev; + int error; bool wakeup = false; if (!sleep_state_supported(state)) @@ -502,11 +500,9 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_test_start(); error = dpm_suspend_start(PMSG_SUSPEND); if (error) { - last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; - last_dev %= REC_FAILED_NUM; pr_err("Some devices failed to suspend, or early wake event detected\n"); - log_suspend_abort_reason("%s device failed to suspend, or early wake event detected", - suspend_stats.failed_devs[last_dev]); + log_suspend_abort_reason( + "Some devices failed to suspend, or early wake event detected"); goto Recover_platform; } suspend_test_finish("suspend devices"); diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 252611fad2fee221c0cee0f3dc563bdd88a4fc3a..3c118c0446330f4b43a93811da79828edf6e2288 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -4,7 +4,7 @@ * Logs the reasons which caused the kernel to resume from * the suspend mode. * - * Copyright (C) 2014 Google, Inc. + * Copyright (C) 2020 Google, Inc. * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. @@ -26,70 +26,315 @@ #include #include #include +#include +/* + * struct wakeup_irq_node - stores data and relationships for IRQs logged as + * either base or nested wakeup reasons during suspend/resume flow. + * @siblings - for membership on leaf or parent IRQ lists + * @irq - the IRQ number + * @irq_name - the name associated with the IRQ, or a default if none + */ +struct wakeup_irq_node { + struct list_head siblings; + int irq; + const char *irq_name; +}; + +static DEFINE_SPINLOCK(wakeup_reason_lock); + +static LIST_HEAD(leaf_irqs); /* kept in ascending IRQ sorted order */ +static LIST_HEAD(parent_irqs); /* unordered */ -#define MAX_WAKEUP_REASON_IRQS 32 -static int irq_list[MAX_WAKEUP_REASON_IRQS]; -static int irqcount; +static struct kmem_cache *wakeup_irq_nodes_cache; + +static const char *default_irq_name = "(unnamed)"; + +static struct kobject *kobj; + +static bool capture_reasons; static bool suspend_abort; -static char abort_reason[MAX_SUSPEND_ABORT_LEN]; -static struct kobject *wakeup_reason; -static DEFINE_SPINLOCK(resume_reason_lock); +static bool abnormal_wake; +static char non_irq_wake_reason[MAX_SUSPEND_ABORT_LEN]; static ktime_t last_monotime; /* monotonic time before last suspend */ static ktime_t curr_monotime; /* monotonic time after last suspend */ static ktime_t last_stime; /* monotonic boottime offset before last suspend */ static ktime_t curr_stime; /* monotonic boottime offset after last suspend */ -static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, - char *buf) +static void init_node(struct wakeup_irq_node *p, int irq) { - int irq_no, buf_offset = 0; struct irq_desc *desc; - spin_lock(&resume_reason_lock); - if (suspend_abort) { - buf_offset = sprintf(buf, "Abort: %s", abort_reason); - } else { - for (irq_no = 0; irq_no < irqcount; irq_no++) { - desc = irq_to_desc(irq_list[irq_no]); - if (desc && desc->action && desc->action->name) - buf_offset += sprintf(buf + buf_offset, "%d %s\n", - irq_list[irq_no], desc->action->name); + + INIT_LIST_HEAD(&p->siblings); + + p->irq = irq; + desc = irq_to_desc(irq); + if (desc && desc->action && desc->action->name) + p->irq_name = desc->action->name; + else + p->irq_name = default_irq_name; +} + +static struct wakeup_irq_node *create_node(int irq) +{ + struct wakeup_irq_node *result; + + result = kmem_cache_alloc(wakeup_irq_nodes_cache, GFP_ATOMIC); + if (unlikely(!result)) + pr_warn("Failed to log wakeup IRQ %d\n", irq); + else + init_node(result, irq); + + return result; +} + +static void delete_list(struct list_head *head) +{ + struct wakeup_irq_node *n; + + while (!list_empty(head)) { + n = list_first_entry(head, struct wakeup_irq_node, siblings); + list_del(&n->siblings); + kmem_cache_free(wakeup_irq_nodes_cache, n); + } +} + +static bool add_sibling_node_sorted(struct list_head *head, int irq) +{ + struct wakeup_irq_node *n = NULL; + struct list_head *predecessor = head; + + if (unlikely(WARN_ON(!head))) + return NULL; + + if (!list_empty(head)) + list_for_each_entry(n, head, siblings) { + if (n->irq < irq) + predecessor = &n->siblings; + else if (n->irq == irq) + return true; else - buf_offset += sprintf(buf + buf_offset, "%d\n", - irq_list[irq_no]); + break; + } + + n = create_node(irq); + if (n) { + list_add(&n->siblings, predecessor); + return true; + } + + return false; +} + +static struct wakeup_irq_node *find_node_in_list(struct list_head *head, + int irq) +{ + struct wakeup_irq_node *n; + + if (unlikely(WARN_ON(!head))) + return NULL; + + list_for_each_entry(n, head, siblings) + if (n->irq == irq) + return n; + + return NULL; +} + +void log_irq_wakeup_reason(int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&wakeup_reason_lock, flags); + + if (!capture_reasons) { + spin_unlock_irqrestore(&wakeup_reason_lock, flags); + return; + } + + if (find_node_in_list(&parent_irqs, irq) == NULL) + add_sibling_node_sorted(&leaf_irqs, irq); + + spin_unlock_irqrestore(&wakeup_reason_lock, flags); +} + +void log_threaded_irq_wakeup_reason(int irq, int parent_irq) +{ + struct wakeup_irq_node *parent; + unsigned long flags; + + /* + * Intentionally unsynchronized. Calls that come in after we have + * resumed should have a fast exit path since there's no work to be + * done, any any coherence issue that could cause a wrong value here is + * both highly improbable - given the set/clear timing - and very low + * impact (parent IRQ gets logged instead of the specific child). + */ + if (!capture_reasons) + return; + + spin_lock_irqsave(&wakeup_reason_lock, flags); + + if (!capture_reasons || (find_node_in_list(&leaf_irqs, irq) != NULL)) { + spin_unlock_irqrestore(&wakeup_reason_lock, flags); + return; + } + + parent = find_node_in_list(&parent_irqs, parent_irq); + if (parent != NULL) + add_sibling_node_sorted(&leaf_irqs, irq); + else { + parent = find_node_in_list(&leaf_irqs, parent_irq); + if (parent != NULL) { + list_del_init(&parent->siblings); + list_add_tail(&parent->siblings, &parent_irqs); + add_sibling_node_sorted(&leaf_irqs, irq); } } - spin_unlock(&resume_reason_lock); + + spin_unlock_irqrestore(&wakeup_reason_lock, flags); +} + +static void __log_abort_or_abnormal_wake(bool abort, const char *fmt, + va_list args) +{ + unsigned long flags; + + spin_lock_irqsave(&wakeup_reason_lock, flags); + + /* Suspend abort or abnormal wake reason has already been logged. */ + if (suspend_abort || abnormal_wake) { + spin_unlock_irqrestore(&wakeup_reason_lock, flags); + return; + } + + suspend_abort = abort; + abnormal_wake = !abort; + vsnprintf(non_irq_wake_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); + + spin_unlock_irqrestore(&wakeup_reason_lock, flags); +} + +void log_suspend_abort_reason(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + __log_abort_or_abnormal_wake(true, fmt, args); + va_end(args); +} + +void log_abnormal_wakeup_reason(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + __log_abort_or_abnormal_wake(false, fmt, args); + va_end(args); +} + +void clear_wakeup_reasons(void) +{ + unsigned long flags; + + spin_lock_irqsave(&wakeup_reason_lock, flags); + + delete_list(&leaf_irqs); + delete_list(&parent_irqs); + suspend_abort = false; + abnormal_wake = false; + capture_reasons = true; + + spin_unlock_irqrestore(&wakeup_reason_lock, flags); +} + +static void print_wakeup_sources(void) +{ + struct wakeup_irq_node *n; + unsigned long flags; + + spin_lock_irqsave(&wakeup_reason_lock, flags); + + capture_reasons = false; + + if (suspend_abort) { + pr_info("Abort: %s\n", non_irq_wake_reason); + spin_unlock_irqrestore(&wakeup_reason_lock, flags); + return; + } + + if (!list_empty(&leaf_irqs)) + list_for_each_entry(n, &leaf_irqs, siblings) + pr_info("Resume caused by IRQ %d, %s\n", n->irq, + n->irq_name); + else if (abnormal_wake) + pr_info("Resume caused by %s\n", non_irq_wake_reason); + else + pr_info("Resume cause unknown\n"); + + spin_unlock_irqrestore(&wakeup_reason_lock, flags); +} + +static ssize_t last_resume_reason_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t buf_offset = 0; + struct wakeup_irq_node *n; + unsigned long flags; + + spin_lock_irqsave(&wakeup_reason_lock, flags); + + if (suspend_abort) { + buf_offset = scnprintf(buf, PAGE_SIZE, "Abort: %s", + non_irq_wake_reason); + spin_unlock_irqrestore(&wakeup_reason_lock, flags); + return buf_offset; + } + + if (!list_empty(&leaf_irqs)) + list_for_each_entry(n, &leaf_irqs, siblings) + buf_offset += scnprintf(buf + buf_offset, + PAGE_SIZE - buf_offset, + "%d %s\n", n->irq, n->irq_name); + else if (abnormal_wake) + buf_offset = scnprintf(buf, PAGE_SIZE, "-1 %s", + non_irq_wake_reason); + + spin_unlock_irqrestore(&wakeup_reason_lock, flags); + return buf_offset; } static ssize_t last_suspend_time_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - struct timespec sleep_time; - struct timespec total_time; - struct timespec suspend_resume_time; + struct timespec64 sleep_time; + struct timespec64 total_time; + struct timespec64 suspend_resume_time; /* * total_time is calculated from monotonic bootoffsets because * unlike CLOCK_MONOTONIC it include the time spent in suspend state. */ - total_time = ktime_to_timespec(ktime_sub(curr_stime, last_stime)); + total_time = ktime_to_timespec64(ktime_sub(curr_stime, last_stime)); /* * suspend_resume_time is calculated as monotonic (CLOCK_MONOTONIC) * time interval before entering suspend and post suspend. */ - suspend_resume_time = ktime_to_timespec(ktime_sub(curr_monotime, last_monotime)); + suspend_resume_time = + ktime_to_timespec64(ktime_sub(curr_monotime, last_monotime)); /* sleep_time = total_time - suspend_resume_time */ - sleep_time = timespec_sub(total_time, suspend_resume_time); + sleep_time = timespec64_sub(total_time, suspend_resume_time); /* Export suspend_resume_time and sleep_time in pair here. */ - return sprintf(buf, "%lu.%09lu %lu.%09lu\n", - suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec, - sleep_time.tv_sec, sleep_time.tv_nsec); + return sprintf(buf, "%llu.%09lu %llu.%09lu\n", + (unsigned long long)suspend_resume_time.tv_sec, + suspend_resume_time.tv_nsec, + (unsigned long long)sleep_time.tv_sec, + sleep_time.tv_nsec); } static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason); @@ -104,86 +349,24 @@ static struct attribute_group attr_group = { .attrs = attrs, }; -/* - * logs all the wake up reasons to the kernel - * stores the irqs to expose them to the userspace via sysfs - */ -void log_wakeup_reason(int irq) -{ - struct irq_desc *desc; - desc = irq_to_desc(irq); - if (desc && desc->action && desc->action->name) - printk(KERN_INFO "Resume caused by IRQ %d, %s\n", irq, - desc->action->name); - else - printk(KERN_INFO "Resume caused by IRQ %d\n", irq); - - spin_lock(&resume_reason_lock); - if (irqcount == MAX_WAKEUP_REASON_IRQS) { - spin_unlock(&resume_reason_lock); - printk(KERN_WARNING "Resume caused by more than %d IRQs\n", - MAX_WAKEUP_REASON_IRQS); - return; - } - - irq_list[irqcount++] = irq; - spin_unlock(&resume_reason_lock); -} - -int check_wakeup_reason(int irq) -{ - int irq_no; - int ret = false; - - spin_lock(&resume_reason_lock); - for (irq_no = 0; irq_no < irqcount; irq_no++) - if (irq_list[irq_no] == irq) { - ret = true; - break; - } - spin_unlock(&resume_reason_lock); - return ret; -} - -void log_suspend_abort_reason(const char *fmt, ...) -{ - va_list args; - - spin_lock(&resume_reason_lock); - - //Suspend abort reason has already been logged. - if (suspend_abort) { - spin_unlock(&resume_reason_lock); - return; - } - - suspend_abort = true; - va_start(args, fmt); - vsnprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); - va_end(args); - spin_unlock(&resume_reason_lock); -} - /* Detects a suspend and clears all the previous wake up reasons*/ static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) { switch (pm_event) { case PM_SUSPEND_PREPARE: - spin_lock(&resume_reason_lock); - irqcount = 0; - suspend_abort = false; - spin_unlock(&resume_reason_lock); /* monotonic time since boot */ last_monotime = ktime_get(); /* monotonic time since boot including the time spent in suspend */ last_stime = ktime_get_boottime(); + clear_wakeup_reasons(); break; case PM_POST_SUSPEND: /* monotonic time since boot */ curr_monotime = ktime_get(); /* monotonic time since boot including the time spent in suspend */ curr_stime = ktime_get_boottime(); + print_wakeup_sources(); break; default: break; @@ -195,31 +378,40 @@ static struct notifier_block wakeup_reason_pm_notifier_block = { .notifier_call = wakeup_reason_pm_event, }; -/* Initializes the sysfs parameter - * registers the pm_event notifier - */ -int __init wakeup_reason_init(void) +static int __init wakeup_reason_init(void) { - int retval; - - retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); - if (retval) - printk(KERN_WARNING "[%s] failed to register PM notifier %d\n", - __func__, retval); + if (register_pm_notifier(&wakeup_reason_pm_notifier_block)) { + pr_warn("[%s] failed to register PM notifier\n", __func__); + goto fail; + } - wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj); - if (!wakeup_reason) { - printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n", - __func__); - return 1; + kobj = kobject_create_and_add("wakeup_reasons", kernel_kobj); + if (!kobj) { + pr_warn("[%s] failed to create a sysfs kobject\n", __func__); + goto fail_unregister_pm_notifier; } - retval = sysfs_create_group(wakeup_reason, &attr_group); - if (retval) { - kobject_put(wakeup_reason); - printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n", - __func__, retval); + + if (sysfs_create_group(kobj, &attr_group)) { + pr_warn("[%s] failed to create a sysfs group\n", __func__); + goto fail_kobject_put; } + + wakeup_irq_nodes_cache = + kmem_cache_create("wakeup_irq_node_cache", + sizeof(struct wakeup_irq_node), 0, 0, NULL); + if (!wakeup_irq_nodes_cache) + goto fail_remove_group; + return 0; + +fail_remove_group: + sysfs_remove_group(kobj, &attr_group); +fail_kobject_put: + kobject_put(kobj); +fail_unregister_pm_notifier: + unregister_pm_notifier(&wakeup_reason_pm_notifier_block); +fail: + return 1; } late_initcall(wakeup_reason_init); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 358d9af7d84b0ca3021b42f34a68173e30b99d5a..4a727c8b84dc2c044bab399b4029dbb0fd9fe2f4 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include @@ -2186,7 +2185,6 @@ void resume_console(void) { if (!console_suspend_enabled) return; - place_marker("M - System Resume Started"); down_console_sem(); console_suspended = 0; console_unlock(); diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 3f85da02be4ea53230a2235b33832a07f7527267..bc4b72527b027b8f6c5af3f7c255ac726de9e806 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -186,7 +186,8 @@ static void group_init(struct psi_group *group) for_each_possible_cpu(cpu) seqcount_init(&per_cpu_ptr(group->pcpu, cpu)->seq); - group->avg_next_update = sched_clock() + psi_period; + group->avg_last_update = sched_clock(); + group->avg_next_update = group->avg_last_update + psi_period; INIT_DELAYED_WORK(&group->avgs_work, psi_avgs_work); mutex_init(&group->avgs_lock); /* Init trigger-related members */ @@ -482,7 +483,7 @@ static u64 window_update(struct psi_window *win, u64 now, u64 value) u32 remaining; remaining = win->size - elapsed; - growth += div_u64(win->prev_growth * remaining, win->size); + growth += div64_u64(win->prev_growth * remaining, win->size); } return growth; @@ -1199,7 +1200,10 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf, if (static_branch_likely(&psi_disabled)) return -EOPNOTSUPP; - buf_size = min(nbytes, (sizeof(buf) - 1)); + if (!nbytes) + return -EINVAL; + + buf_size = min(nbytes, sizeof(buf)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 38aae2631f1d3263f0ed8e99fabc44609a16b924..dc63c7ae9e737a6e80fb7010f1e9b8c65c2b220d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -159,7 +159,13 @@ static inline void cpu_load_update_active(struct rq *this_rq) { } #ifdef CONFIG_64BIT # define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT + SCHED_FIXEDPOINT_SHIFT) # define scale_load(w) ((w) << SCHED_FIXEDPOINT_SHIFT) -# define scale_load_down(w) ((w) >> SCHED_FIXEDPOINT_SHIFT) +# define scale_load_down(w) \ +({ \ + unsigned long __w = (w); \ + if (__w) \ + __w = max(2UL, __w >> SCHED_FIXEDPOINT_SHIFT); \ + __w; \ +}) #else # define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT) # define scale_load(w) (w) @@ -2867,15 +2873,14 @@ extern void clear_top_tasks_bitmap(unsigned long *bitmap); #if defined(CONFIG_SCHED_TUNE) extern bool task_sched_boost(struct task_struct *p); extern int sync_cgroup_colocation(struct task_struct *p, bool insert); -extern bool same_schedtune(struct task_struct *tsk1, struct task_struct *tsk2); +extern bool schedtune_task_colocated(struct task_struct *p); extern void update_cgroup_boost_settings(void); extern void restore_cgroup_boost_settings(void); #else -static inline bool -same_schedtune(struct task_struct *tsk1, struct task_struct *tsk2) +static inline bool schedtune_task_colocated(struct task_struct *p) { - return true; + return false; } static inline bool task_sched_boost(struct task_struct *p) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 51862ccdb71983bab0d1bbbeafb75b3ee73b4699..5670542c774e23ab174ad6ad6b83a1ab42ef3cef 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -150,11 +150,6 @@ static inline void init_sched_boost(struct schedtune *st) st->colocate_update_disabled = false; } -bool same_schedtune(struct task_struct *tsk1, struct task_struct *tsk2) -{ - return task_schedtune(tsk1) == task_schedtune(tsk2); -} - void update_cgroup_boost_settings(void) { int i; @@ -482,6 +477,23 @@ static int sched_colocate_write(struct cgroup_subsys_state *css, return 0; } +bool schedtune_task_colocated(struct task_struct *p) +{ + struct schedtune *st; + bool colocated; + + if (unlikely(!schedtune_initialized)) + return false; + + /* Get task boost value */ + rcu_read_lock(); + st = task_schedtune(p); + colocated = st->colocate; + rcu_read_unlock(); + + return colocated; +} + #else /* CONFIG_SCHED_WALT */ static inline void init_sched_boost(struct schedtune *st) { } diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index fbf12f07b4dce06f833ecd9b215bd916bc1b12a5..be19e3b0c25d134de2fb29f5b115780d0a24b234 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -2514,7 +2514,6 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp, * Enable colocation and frequency aggregation for all threads in a process. * The children inherits the group id from the parent. */ -unsigned int __read_mostly sysctl_sched_enable_thread_grouping; struct related_thread_group *related_thread_groups[MAX_NUM_CGROUP_COLOC_ID]; static LIST_HEAD(active_related_thread_groups); @@ -2780,34 +2779,25 @@ void add_new_task_to_grp(struct task_struct *new) { unsigned long flags; struct related_thread_group *grp; - struct task_struct *leader = new->group_leader; - unsigned int leader_grp_id = sched_get_group_id(leader); - if (!sysctl_sched_enable_thread_grouping && - leader_grp_id != DEFAULT_CGROUP_COLOC_ID) - return; - - if (thread_group_leader(new)) + /* + * If the task does not belong to colocated schedtune + * cgroup, nothing to do. We are checking this without + * lock. Even if there is a race, it will be added + * to the co-located cgroup via cgroup attach. + */ + if (!schedtune_task_colocated(new)) return; - if (leader_grp_id == DEFAULT_CGROUP_COLOC_ID) { - if (!same_schedtune(new, leader)) - return; - } - + grp = lookup_related_thread_group(DEFAULT_CGROUP_COLOC_ID); write_lock_irqsave(&related_thread_group_lock, flags); - rcu_read_lock(); - grp = task_related_thread_group(leader); - rcu_read_unlock(); - /* * It's possible that someone already added the new task to the - * group. A leader's thread group is updated prior to calling - * this function. It's also possible that the leader has exited - * the group. In either case, there is nothing else to do. + * group. or it might have taken out from the colocated schedtune + * cgroup. check these conditions under lock. */ - if (!grp || new->grp) { + if (!schedtune_task_colocated(new) || new->grp) { write_unlock_irqrestore(&related_thread_group_lock, flags); return; } diff --git a/kernel/signal.c b/kernel/signal.c index 84b028ece696c03a9c977eac152a7b506461a0e2..a067e2c8942beb177b7d82d2daaf8334b192b0e2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -383,27 +383,32 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi { struct sigqueue *q = NULL; struct user_struct *user; + int sigpending; /* * Protect access to @t credentials. This can go away when all * callers hold rcu read lock. + * + * NOTE! A pending signal will hold on to the user refcount, + * and we get/put the refcount only when the sigpending count + * changes from/to zero. */ rcu_read_lock(); - user = get_uid(__task_cred(t)->user); - atomic_inc(&user->sigpending); + user = __task_cred(t)->user; + sigpending = atomic_inc_return(&user->sigpending); + if (sigpending == 1) + get_uid(user); rcu_read_unlock(); - if (override_rlimit || - atomic_read(&user->sigpending) <= - task_rlimit(t, RLIMIT_SIGPENDING)) { + if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) { q = kmem_cache_alloc(sigqueue_cachep, flags); } else { print_dropped_signal(sig); } if (unlikely(q == NULL)) { - atomic_dec(&user->sigpending); - free_uid(user); + if (atomic_dec_and_test(&user->sigpending)) + free_uid(user); } else { INIT_LIST_HEAD(&q->list); q->flags = 0; @@ -417,8 +422,8 @@ static void __sigqueue_free(struct sigqueue *q) { if (q->flags & SIGQUEUE_PREALLOC) return; - atomic_dec(&q->user->sigpending); - free_uid(q->user); + if (atomic_dec_and_test(&q->user->sigpending)) + free_uid(q->user); kmem_cache_free(sigqueue_cachep, q); } @@ -1688,7 +1693,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig) * This is only possible if parent == real_parent. * Check if it has changed security domain. */ - if (tsk->parent_exec_id != tsk->parent->self_exec_id) + if (tsk->parent_exec_id != READ_ONCE(tsk->parent->self_exec_id)) sig = SIGCHLD; } diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 0300147bea8d52e603a6d341ec90c13c3848c04c..9f15dc0493ad7df9d0123f892a3dab7896c0ea99 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -102,9 +102,9 @@ static int alarmtimer_rtc_add_device(struct device *dev, struct class_interface *class_intf) { unsigned long flags; - int err = 0; struct rtc_device *rtc = to_rtc_device(dev); struct wakeup_source *__ws; + int ret = 0; if (rtcdev) return -EBUSY; @@ -117,13 +117,13 @@ static int alarmtimer_rtc_add_device(struct device *dev, spin_lock_irqsave(&rtcdev_lock, flags); if (!rtcdev) { if (!try_module_get(rtc->owner)) { - spin_unlock_irqrestore(&rtcdev_lock, flags); - return -1; + ret = -1; + goto unlock; } - err = rtc_irq_register(rtc, &alarmtimer_rtc_task); - if (err) - goto rtc_irq_reg_err; + ret = rtc_irq_register(rtc, &alarmtimer_rtc_task); + if (ret) + goto unlock; rtcdev = rtc; /* hold a reference so it doesn't go away */ @@ -132,11 +132,11 @@ static int alarmtimer_rtc_add_device(struct device *dev, __ws = NULL; } -rtc_irq_reg_err: +unlock: spin_unlock_irqrestore(&rtcdev_lock, flags); wakeup_source_unregister(__ws); - return err; + return ret; } static void alarmtimer_rtc_remove_device(struct device *dev, diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index e13d32706b74be029b8eb048cc767e0848ec2559..1505777e090cc91d880e0655e2e3c6e811084695 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -280,8 +280,15 @@ static void clocksource_watchdog(unsigned long data) next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask); if (next_cpu >= nr_cpu_ids) next_cpu = cpumask_first(cpu_online_mask); - watchdog_timer.expires += WATCHDOG_INTERVAL; - add_timer_on(&watchdog_timer, next_cpu); + + /* + * Arm timer if not already pending: could race with concurrent + * pair clocksource_stop_watchdog() clocksource_start_watchdog(). + */ + if (!timer_pending(&watchdog_timer)) { + watchdog_timer.expires += WATCHDOG_INTERVAL; + add_timer_on(&watchdog_timer, next_cpu); + } out: spin_unlock(&watchdog_lock); } diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 551fdd4d0ea878acba87358950bbe15623b02124..5cc253f8fbf73688b5ffbcbc55fc3d0dd5376c2b 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -5147,8 +5147,8 @@ static const struct file_operations ftrace_notrace_fops = { static DEFINE_MUTEX(graph_lock); -struct ftrace_hash *ftrace_graph_hash = EMPTY_HASH; -struct ftrace_hash *ftrace_graph_notrace_hash = EMPTY_HASH; +struct ftrace_hash __rcu *ftrace_graph_hash = EMPTY_HASH; +struct ftrace_hash __rcu *ftrace_graph_notrace_hash = EMPTY_HASH; enum graph_filter_type { GRAPH_FILTER_NOTRACE = 0, @@ -5420,8 +5420,15 @@ ftrace_graph_release(struct inode *inode, struct file *file) mutex_unlock(&graph_lock); - /* Wait till all users are no longer using the old hash */ - synchronize_sched(); + /* + * We need to do a hard force of sched synchronization. + * This is because we use preempt_disable() to do RCU, but + * the function tracers can be called where RCU is not watching + * (like before user_exit()). We can not rely on the RCU + * infrastructure to do the synchronization, thus we must do it + * ourselves. + */ + schedule_on_each_cpu(ftrace_sync); free_ftrace_hash(old_hash); } @@ -6312,9 +6319,10 @@ static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) struct trace_array *tr = m->private; struct trace_pid_list *pid_list = rcu_dereference_sched(tr->function_pids); - if (v == FTRACE_NO_PIDS) + if (v == FTRACE_NO_PIDS) { + (*pos)++; return NULL; - + } return trace_pid_next(pid_list, v, pos); } diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index aea0f442516e0113aa79a7f7606f184810d9efd4..04b5e4cef44de25cc940e9909b38c025c9bae138 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1544,6 +1544,7 @@ static __init int init_trace_selftests(void) pr_info("Running postponed tracer tests:\n"); + tracing_selftest_running = true; list_for_each_entry_safe(p, n, &postponed_selftests, list) { ret = run_tracer_selftest(p->type); /* If the test fails, then warn and remove from available_tracers */ @@ -1562,6 +1563,7 @@ static __init int init_trace_selftests(void) list_del(&p->list); kfree(p); } + tracing_selftest_running = false; out: mutex_unlock(&trace_types_lock); @@ -7729,6 +7731,7 @@ static int instance_mkdir(const char *name) struct trace_array *tr; int ret; + mutex_lock(&event_mutex); mutex_lock(&trace_types_lock); ret = -EEXIST; @@ -7784,6 +7787,7 @@ static int instance_mkdir(const char *name) list_add(&tr->list, &ftrace_trace_arrays); mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); return 0; @@ -7795,6 +7799,7 @@ static int instance_mkdir(const char *name) out_unlock: mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); return ret; @@ -7807,6 +7812,7 @@ static int instance_rmdir(const char *name) int ret; int i; + mutex_lock(&event_mutex); mutex_lock(&trace_types_lock); ret = -ENODEV; @@ -7852,6 +7858,7 @@ static int instance_rmdir(const char *name) out_unlock: mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); return ret; } diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index afa0cb712093c7b996c2cb0e853f959e5954de6a..ca74e1bc554e00620ef3c33149ab5d2f49485961 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -868,22 +868,31 @@ extern void __trace_graph_return(struct trace_array *tr, unsigned long flags, int pc); #ifdef CONFIG_DYNAMIC_FTRACE -extern struct ftrace_hash *ftrace_graph_hash; -extern struct ftrace_hash *ftrace_graph_notrace_hash; +extern struct ftrace_hash __rcu *ftrace_graph_hash; +extern struct ftrace_hash __rcu *ftrace_graph_notrace_hash; static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace) { unsigned long addr = trace->func; int ret = 0; + struct ftrace_hash *hash; preempt_disable_notrace(); - if (ftrace_hash_empty(ftrace_graph_hash)) { + /* + * Have to open code "rcu_dereference_sched()" because the + * function graph tracer can be called when RCU is not + * "watching". + * Protected with schedule_on_each_cpu(ftrace_sync) + */ + hash = rcu_dereference_protected(ftrace_graph_hash, !preemptible()); + + if (ftrace_hash_empty(hash)) { ret = 1; goto out; } - if (ftrace_lookup_ip(ftrace_graph_hash, addr)) { + if (ftrace_lookup_ip(hash, addr)) { /* * This needs to be cleared on the return functions @@ -919,10 +928,20 @@ static inline void ftrace_graph_addr_finish(struct ftrace_graph_ret *trace) static inline int ftrace_graph_notrace_addr(unsigned long addr) { int ret = 0; + struct ftrace_hash *notrace_hash; preempt_disable_notrace(); - if (ftrace_lookup_ip(ftrace_graph_notrace_hash, addr)) + /* + * Have to open code "rcu_dereference_sched()" because the + * function graph tracer can be called when RCU is not + * "watching". + * Protected with schedule_on_each_cpu(ftrace_sync) + */ + notrace_hash = rcu_dereference_protected(ftrace_graph_notrace_hash, + !preemptible()); + + if (ftrace_lookup_ip(notrace_hash, addr)) ret = 1; preempt_enable_notrace(); diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 2b0a01b2be2d1d05445cb954630ff6d59fe95dad..421166a39253aa7c23c53bb1fee60977db44fd6f 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1403,8 +1403,8 @@ static int subsystem_open(struct inode *inode, struct file *filp) return -ENODEV; /* Make sure the system still exists */ - mutex_lock(&trace_types_lock); mutex_lock(&event_mutex); + mutex_lock(&trace_types_lock); list_for_each_entry(tr, &ftrace_trace_arrays, list) { list_for_each_entry(dir, &tr->systems, list) { if (dir == inode->i_private) { @@ -1418,8 +1418,8 @@ static int subsystem_open(struct inode *inode, struct file *filp) } } exit_loop: - mutex_unlock(&event_mutex); mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); if (!system) return -ENODEV; @@ -2305,15 +2305,15 @@ static void __add_event_to_tracers(struct trace_event_call *call); int trace_add_event_call(struct trace_event_call *call) { int ret; - mutex_lock(&trace_types_lock); mutex_lock(&event_mutex); + mutex_lock(&trace_types_lock); ret = __register_event(call, NULL); if (ret >= 0) __add_event_to_tracers(call); - mutex_unlock(&event_mutex); mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); return ret; } @@ -2367,13 +2367,13 @@ int trace_remove_event_call(struct trace_event_call *call) { int ret; - mutex_lock(&trace_types_lock); mutex_lock(&event_mutex); + mutex_lock(&trace_types_lock); down_write(&trace_event_sem); ret = probe_remove_event_call(call); up_write(&trace_event_sem); - mutex_unlock(&event_mutex); mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); return ret; } @@ -2435,8 +2435,8 @@ static int trace_module_notify(struct notifier_block *self, { struct module *mod = data; - mutex_lock(&trace_types_lock); mutex_lock(&event_mutex); + mutex_lock(&trace_types_lock); switch (val) { case MODULE_STATE_COMING: trace_module_add_events(mod); @@ -2445,8 +2445,8 @@ static int trace_module_notify(struct notifier_block *self, trace_module_remove_events(mod); break; } - mutex_unlock(&event_mutex); mutex_unlock(&trace_types_lock); + mutex_unlock(&event_mutex); return 0; } @@ -2961,24 +2961,24 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr) * creates the event hierachry in the @parent/events directory. * * Returns 0 on success. + * + * Must be called with event_mutex held. */ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr) { int ret; - mutex_lock(&event_mutex); + lockdep_assert_held(&event_mutex); ret = create_event_toplevel_files(parent, tr); if (ret) - goto out_unlock; + goto out; down_write(&trace_event_sem); __trace_add_event_dirs(tr); up_write(&trace_event_sem); - out_unlock: - mutex_unlock(&event_mutex); - + out: return ret; } @@ -3007,9 +3007,10 @@ early_event_add_tracer(struct dentry *parent, struct trace_array *tr) return ret; } +/* Must be called with event_mutex held */ int event_trace_del_tracer(struct trace_array *tr) { - mutex_lock(&event_mutex); + lockdep_assert_held(&event_mutex); /* Disable any event triggers and associated soft-disabled events */ clear_event_triggers(tr); @@ -3030,8 +3031,6 @@ int event_trace_del_tracer(struct trace_array *tr) tr->event_dir = NULL; - mutex_unlock(&event_mutex); - return 0; } diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index e2da180ca172a6418b448253e244a1dd5ef61ca3..6fb5eb7b57dc03eb5b7de6c4253e7ea8b2d89a0c 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -127,9 +127,10 @@ static void *trigger_next(struct seq_file *m, void *t, loff_t *pos) { struct trace_event_file *event_file = event_file_data(m->private); - if (t == SHOW_AVAILABLE_TRIGGERS) + if (t == SHOW_AVAILABLE_TRIGGERS) { + (*pos)++; return NULL; - + } return seq_list_next(t, &event_file->triggers, pos); } @@ -1074,14 +1075,10 @@ register_snapshot_trigger(char *glob, struct event_trigger_ops *ops, struct event_trigger_data *data, struct trace_event_file *file) { - int ret = register_trigger(glob, ops, data, file); - - if (ret > 0 && tracing_alloc_snapshot_instance(file->tr) != 0) { - unregister_trigger(glob, ops, data, file); - ret = 0; - } + if (tracing_alloc_snapshot_instance(file->tr) != 0) + return 0; - return ret; + return register_trigger(glob, ops, data, file); } static int diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 0c23b5615977fa34a6c09f67354bf24646fe5b0b..b0db2e4cefa3570dddd4b49912c9853e3b49a09c 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -877,6 +877,8 @@ static int probes_seq_show(struct seq_file *m, void *v) int i; seq_putc(m, trace_kprobe_is_return(tk) ? 'r' : 'p'); + if (trace_kprobe_is_return(tk) && tk->rp.maxactive) + seq_printf(m, "%d", tk->rp.maxactive); seq_printf(m, ":%s/%s", tk->tp.call.class->system, trace_event_name(&tk->tp.call)); diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c index e288168661e118c07ca5638bb2ddb3dd33fb1acc..e304196d7c2853ae0056c06c78d74819468265ca 100644 --- a/kernel/trace/trace_sched_switch.c +++ b/kernel/trace/trace_sched_switch.c @@ -89,8 +89,10 @@ static void tracing_sched_unregister(void) static void tracing_start_sched_switch(int ops) { - bool sched_register = (!sched_cmdline_ref && !sched_tgid_ref); + bool sched_register; + mutex_lock(&sched_register_mutex); + sched_register = (!sched_cmdline_ref && !sched_tgid_ref); switch (ops) { case RECORD_CMDLINE: diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c index 75bf1bcb4a8a56164641549f51bbec41584afe24..92b76f9e25eddd71ef4760ca2cce00504236b18d 100644 --- a/kernel/trace/trace_stat.c +++ b/kernel/trace/trace_stat.c @@ -278,18 +278,22 @@ static int tracing_stat_init(void) d_tracing = tracing_init_dentry(); if (IS_ERR(d_tracing)) - return 0; + return -ENODEV; stat_dir = tracefs_create_dir("trace_stat", d_tracing); - if (!stat_dir) + if (!stat_dir) { pr_warn("Could not create tracefs 'trace_stat' entry\n"); + return -ENOMEM; + } return 0; } static int init_stat_file(struct stat_session *session) { - if (!stat_dir && tracing_stat_init()) - return -ENODEV; + int ret; + + if (!stat_dir && (ret = tracing_stat_init())) + return ret; session->file = tracefs_create_file(session->ts->name, 0644, stat_dir, @@ -302,7 +306,7 @@ static int init_stat_file(struct stat_session *session) int register_stat_tracer(struct tracer_stat *trace) { struct stat_session *session, *node; - int ret; + int ret = -EINVAL; if (!trace) return -EINVAL; @@ -313,17 +317,15 @@ int register_stat_tracer(struct tracer_stat *trace) /* Already registered? */ mutex_lock(&all_stat_sessions_mutex); list_for_each_entry(node, &all_stat_sessions, session_list) { - if (node->ts == trace) { - mutex_unlock(&all_stat_sessions_mutex); - return -EINVAL; - } + if (node->ts == trace) + goto out; } - mutex_unlock(&all_stat_sessions_mutex); + ret = -ENOMEM; /* Init the session */ session = kzalloc(sizeof(*session), GFP_KERNEL); if (!session) - return -ENOMEM; + goto out; session->ts = trace; INIT_LIST_HEAD(&session->session_list); @@ -332,15 +334,16 @@ int register_stat_tracer(struct tracer_stat *trace) ret = init_stat_file(session); if (ret) { destroy_session(session); - return ret; + goto out; } + ret = 0; /* Register */ - mutex_lock(&all_stat_sessions_mutex); list_add_tail(&session->session_list, &all_stat_sessions); + out: mutex_unlock(&all_stat_sessions_mutex); - return 0; + return ret; } void unregister_stat_tracer(struct tracer_stat *trace) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 45ea3a8853cc798f770648c7bebebd63fec6c7a4..1f81cb57eafc3c5ad1249a1a9ef5a345acb48c4d 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -165,6 +165,8 @@ static void lockup_detector_update_enable(void) #ifdef CONFIG_SOFTLOCKUP_DETECTOR +#define SOFTLOCKUP_RESET ULONG_MAX + /* Global variables, exported for sysctl */ unsigned int __read_mostly softlockup_panic = CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE; @@ -273,7 +275,7 @@ notrace void touch_softlockup_watchdog_sched(void) * Preemption can be enabled. It doesn't matter which CPU's timestamp * gets zeroed here, so use the raw_ operation. */ - raw_cpu_write(watchdog_touch_ts, 0); + raw_cpu_write(watchdog_touch_ts, SOFTLOCKUP_RESET); } notrace void touch_softlockup_watchdog(void) @@ -297,14 +299,14 @@ void touch_all_softlockup_watchdogs(void) * the softlockup check. */ for_each_cpu(cpu, &watchdog_allowed_mask) - per_cpu(watchdog_touch_ts, cpu) = 0; + per_cpu(watchdog_touch_ts, cpu) = SOFTLOCKUP_RESET; wq_watchdog_touch(-1); } void touch_softlockup_watchdog_sync(void) { __this_cpu_write(softlockup_touch_sync, true); - __this_cpu_write(watchdog_touch_ts, 0); + __this_cpu_write(watchdog_touch_ts, SOFTLOCKUP_RESET); } static int is_softlockup(unsigned long touch_ts) @@ -356,7 +358,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) /* .. and repeat */ hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period)); - if (touch_ts == 0) { + if (touch_ts == SOFTLOCKUP_RESET) { if (unlikely(__this_cpu_read(softlockup_touch_sync))) { /* * If the time stamp was touched atomically diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 25053738531c538da6d20b21d0846787ae71ffaf..f93f40dd7aaf2c75a42bd952f21c29bea37ce409 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1414,14 +1414,16 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, WARN_ON_ONCE(!is_chained_work(wq))) return; retry: - if (req_cpu == WORK_CPU_UNBOUND) - cpu = wq_select_unbound_cpu(raw_smp_processor_id()); - /* pwq which will be used unless @work is executing elsewhere */ - if (!(wq->flags & WQ_UNBOUND)) - pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); - else + if (wq->flags & WQ_UNBOUND) { + if (req_cpu == WORK_CPU_UNBOUND) + cpu = wq_select_unbound_cpu(raw_smp_processor_id()); pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); + } else { + if (req_cpu == WORK_CPU_UNBOUND) + cpu = raw_smp_processor_id(); + pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); + } /* * If @work was previously on a different pool, it might still be @@ -1538,8 +1540,10 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, struct work_struct *work = &dwork->work; WARN_ON_ONCE(!wq); - WARN_ON_ONCE(timer->function != delayed_work_timer_fn || - timer->data != (unsigned long)dwork); +#ifndef CONFIG_CFI_CLANG + WARN_ON_ONCE(timer->function != delayed_work_timer_fn); +#endif + WARN_ON_ONCE(timer->data != (unsigned long)dwork); WARN_ON_ONCE(timer_pending(timer)); WARN_ON_ONCE(!list_empty(&work->entry)); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5edeeae34343adde501c4b9bd07910d0ef0a16bc..a460785f42ef9c96587921d1056b13acd29c6b92 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -67,7 +67,7 @@ config DYNAMIC_DEBUG bool "Enable dynamic printk() support" default n depends on PRINTK - depends on DEBUG_FS + depends on (DEBUG_FS || PROC_FS) help Compiles debug level messages into the kernel, which would not @@ -85,8 +85,9 @@ config DYNAMIC_DEBUG Usage: Dynamic debugging is controlled via the 'dynamic_debug/control' file, - which is contained in the 'debugfs' filesystem. Thus, the debugfs - filesystem must first be mounted before making use of this feature. + which is contained in the 'debugfs' filesystem or procfs. + Thus, the debugfs or procfs filesystem must first be mounted before + making use of this feature. We refer the control file as: /dynamic_debug/control. This file contains a list of the debug statements that can be enabled. The format for each line of the file is: @@ -2069,6 +2070,16 @@ config TEST_MEMINIT If unsure, say N. +config TEST_STACKINIT + tristate "Test level of stack variable initialization" + help + Test if the kernel is zero-initializing stack variables and + padding. Coverage is controlled by compiler flags, + CONFIG_GCC_PLUGIN_STRUCTLEAK, CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF, + or CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL. + + If unsure, say N. + endmenu # runtime tests config MEMTEST diff --git a/lib/Makefile b/lib/Makefile index 8b11699929fdad86ed305cf106657f149c60048c..ec649b0b711e1837a2a6ffaf2953c04a3a4205f5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -77,6 +77,10 @@ obj-$(CONFIG_TEST_UUID) += test_uuid.o obj-$(CONFIG_TEST_PARMAN) += test_parman.o obj-$(CONFIG_TEST_KMOD) += test_kmod.o obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o +obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o +obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o +CFLAGS_test_stackinit.o += $(call cc-disable-warning, switch-unreachable) +obj-$(CONFIG_TEST_STACKINIT) += test_stackinit.o obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o ifeq ($(CONFIG_DEBUG_KOBJECT),y) diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index 347fa7ac2e8a858827415d44725d256d2a9e96a3..9555b68bb774cc3277dca434d19880286d71df0e 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -33,3 +33,19 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) } EXPORT_SYMBOL(_atomic_dec_and_lock); + +int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock, + unsigned long *flags) +{ + /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ + if (atomic_add_unless(atomic, -1, 1)) + return 0; + + /* Otherwise do it the slow way */ + spin_lock_irqsave(lock, *flags); + if (atomic_dec_and_test(atomic)) + return 1; + spin_unlock_irqrestore(lock, *flags); + return 0; +} +EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave); diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index c7c96bc7654af7c4d5f3c8bbf595989f9b3d0ebf..3f4a49c3c03bbf2c13c0110341a68aeb39bb8bb2 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -954,22 +954,26 @@ static void ddebug_remove_all_tables(void) static __initdata int ddebug_init_success; -static int __init dynamic_debug_init_debugfs(void) +static int __init dynamic_debug_init_control(void) { - struct dentry *dir, *file; + struct proc_dir_entry *procfs_dir; + struct dentry *debugfs_dir; if (!ddebug_init_success) return -ENODEV; - dir = debugfs_create_dir("dynamic_debug", NULL); - if (!dir) - return -ENOMEM; - file = debugfs_create_file("control", 0644, dir, NULL, - &ddebug_proc_fops); - if (!file) { - debugfs_remove(dir); - return -ENOMEM; + /* Create the control file in debugfs if it is enabled */ + if (debugfs_initialized()) { + debugfs_dir = debugfs_create_dir("dynamic_debug", NULL); + debugfs_create_file("control", 0644, debugfs_dir, NULL, + &ddebug_proc_fops); } + + /* Also create the control file in procfs */ + procfs_dir = proc_mkdir("dynamic_debug", NULL); + if (procfs_dir) + proc_create("control", 0644, procfs_dir, &ddebug_proc_fops); + return 0; } @@ -1046,4 +1050,4 @@ static int __init dynamic_debug_init(void) early_initcall(dynamic_debug_init); /* Debugfs setup must be done later */ -fs_initcall(dynamic_debug_init_debugfs); +fs_initcall(dynamic_debug_init_control); diff --git a/lib/find_bit.c b/lib/find_bit.c index 6ed74f78380ce1f6e69568fad0c28d685a5f2048..883ef3755a1cb390ae06efab84a483f4978bd574 100644 --- a/lib/find_bit.c +++ b/lib/find_bit.c @@ -133,18 +133,6 @@ EXPORT_SYMBOL(find_last_bit); #ifdef __BIG_ENDIAN -/* include/linux/byteorder does not support "unsigned long" type */ -static inline unsigned long ext2_swab(const unsigned long y) -{ -#if BITS_PER_LONG == 64 - return (unsigned long) __swab64((u64) y); -#elif BITS_PER_LONG == 32 - return (unsigned long) __swab32((u32) y); -#else -#error BITS_PER_LONG not defined -#endif -} - #if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) static unsigned long _find_next_bit_le(const unsigned long *addr, unsigned long nbits, unsigned long start, unsigned long invert) @@ -157,7 +145,7 @@ static unsigned long _find_next_bit_le(const unsigned long *addr, tmp = addr[start / BITS_PER_LONG] ^ invert; /* Handle 1st word. */ - tmp &= ext2_swab(BITMAP_FIRST_WORD_MASK(start)); + tmp &= swab(BITMAP_FIRST_WORD_MASK(start)); start = round_down(start, BITS_PER_LONG); while (!tmp) { @@ -168,7 +156,7 @@ static unsigned long _find_next_bit_le(const unsigned long *addr, tmp = addr[start / BITS_PER_LONG] ^ invert; } - return min(start + __ffs(ext2_swab(tmp)), nbits); + return min(start + __ffs(swab(tmp)), nbits); } #endif diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 08c60d10747fddc204788e75f24107805702caf4..e01b705556aa68fb156d4e481c07c9677dde83d8 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -756,22 +756,22 @@ do { \ do { \ if (__builtin_constant_p(bh) && (bh) == 0) \ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "%r" ((USItype)(ah)), \ "%r" ((USItype)(al)), \ "rI" ((USItype)(bl))); \ else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "%r" ((USItype)(ah)), \ "%r" ((USItype)(al)), \ "rI" ((USItype)(bl))); \ else \ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "%r" ((USItype)(ah)), \ "r" ((USItype)(bh)), \ "%r" ((USItype)(al)), \ @@ -781,36 +781,36 @@ do { \ do { \ if (__builtin_constant_p(ah) && (ah) == 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((USItype)(bh)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else if (__builtin_constant_p(ah) && (ah) == ~(USItype) 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((USItype)(bh)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else if (__builtin_constant_p(bh) && (bh) == 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((USItype)(ah)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((USItype)(ah)), \ "rI" ((USItype)(al)), \ "r" ((USItype)(bl))); \ else \ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((USItype)(ah)), \ "r" ((USItype)(bh)), \ "rI" ((USItype)(al)), \ @@ -821,7 +821,7 @@ do { \ do { \ USItype __m0 = (m0), __m1 = (m1); \ __asm__ ("mulhwu %0,%1,%2" \ - : "=r" ((USItype) ph) \ + : "=r" (ph) \ : "%r" (__m0), \ "r" (__m1)); \ (pl) = __m0 * __m1; \ diff --git a/lib/raid6/neon.uc b/lib/raid6/neon.uc index d5242f5445511784bc821f3cd64a4487f2673c97..b7c68030da4fd94d5e6bf3efca157127288e9f9a 100644 --- a/lib/raid6/neon.uc +++ b/lib/raid6/neon.uc @@ -28,7 +28,6 @@ typedef uint8x16_t unative_t; -#define NBYTES(x) ((unative_t){x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}) #define NSIZE sizeof(unative_t) /* @@ -61,7 +60,7 @@ void raid6_neon$#_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) int d, z, z0; register unative_t wd$$, wq$$, wp$$, w1$$, w2$$; - const unative_t x1d = NBYTES(0x1d); + const unative_t x1d = vdupq_n_u8(0x1d); z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ @@ -92,7 +91,7 @@ void raid6_neon$#_xor_syndrome_real(int disks, int start, int stop, int d, z, z0; register unative_t wd$$, wq$$, wp$$, w1$$, w2$$; - const unative_t x1d = NBYTES(0x1d); + const unative_t x1d = vdupq_n_u8(0x1d); z0 = stop; /* P/Q right side optimization */ p = dptr[disks-2]; /* XOR parity */ diff --git a/lib/raid6/recov_neon_inner.c b/lib/raid6/recov_neon_inner.c index 8cd20c9f834a1e8cc90e9a4f783f74a4244a5f7a..7d00c31a654706763eb29da6952bb7033e635eee 100644 --- a/lib/raid6/recov_neon_inner.c +++ b/lib/raid6/recov_neon_inner.c @@ -10,11 +10,6 @@ #include -static const uint8x16_t x0f = { - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, -}; - #ifdef CONFIG_ARM /* * AArch32 does not provide this intrinsic natively because it does not @@ -41,6 +36,7 @@ void __raid6_2data_recov_neon(int bytes, uint8_t *p, uint8_t *q, uint8_t *dp, uint8x16_t pm1 = vld1q_u8(pbmul + 16); uint8x16_t qm0 = vld1q_u8(qmul); uint8x16_t qm1 = vld1q_u8(qmul + 16); + uint8x16_t x0f = vdupq_n_u8(0x0f); /* * while ( bytes-- ) { @@ -87,6 +83,7 @@ void __raid6_datap_recov_neon(int bytes, uint8_t *p, uint8_t *q, uint8_t *dq, { uint8x16_t qm0 = vld1q_u8(qmul); uint8x16_t qm1 = vld1q_u8(qmul + 16); + uint8x16_t x0f = vdupq_n_u8(0x0f); /* * while (bytes--) { diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 11fce289d116675c341478893a5ad263c87c4793..834c846c5af84f1552a81f2f9dc5b0b79ad4840b 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -317,7 +317,7 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, if (prv) table->nents = ++table->orig_nents; - return -ENOMEM; + return -ENOMEM; } sg_init_table(sg, alloc_size); diff --git a/lib/stackdepot.c b/lib/stackdepot.c index da258c507675673706a993d1062c75c6e8e4c089..be32f766ab940b55285706e70de8a4f1bb8f0491 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -92,15 +92,19 @@ static bool init_stack_slab(void **prealloc) return true; if (stack_slabs[depot_index] == NULL) { stack_slabs[depot_index] = *prealloc; + *prealloc = NULL; } else { - stack_slabs[depot_index + 1] = *prealloc; + /* If this is the last depot slab, do not touch the next one. */ + if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) { + stack_slabs[depot_index + 1] = *prealloc; + *prealloc = NULL; + } /* * This smp_store_release pairs with smp_load_acquire() from * |next_slab_inited| above and in depot_save_stack(). */ smp_store_release(&next_slab_inited, 1); } - *prealloc = NULL; return true; } diff --git a/lib/test_kasan.c b/lib/test_kasan.c index c55538663d51b5125ef3c27135b4e6cf386ef09d..4593a3a9d3af8bfecef868e972afbe71575d7113 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -157,6 +157,7 @@ static noinline void __init kmalloc_oob_krealloc_more(void) if (!ptr1 || !ptr2) { pr_err("Allocation failed\n"); kfree(ptr1); + kfree(ptr2); return; } diff --git a/lib/test_meminit.c b/lib/test_meminit.c index e4f706a404b3a1f45b3443b4f8de0fbdd15107f8..61d55b74d83534abd4f21f00de77a1b9a7b15b2e 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -397,11 +397,16 @@ static int __init test_meminit_init(void) num_tests += test_kmemcache(&failures); num_tests += test_rcu_persistent(&failures); - if (failures == 0) + if (failures == 0) { pr_info("all %d tests passed!\n", num_tests); - else + } else { pr_info("failures: %d out of %d\n", failures, num_tests); - + /* + * Android 4.14 only: if this test is built as part of the + * kernel, make the failure visible. + */ + panic("Test failed!\n"); + } return failures ? -EINVAL : 0; } module_init(test_meminit_init); diff --git a/lib/test_stackinit.c b/lib/test_stackinit.c new file mode 100644 index 0000000000000000000000000000000000000000..c589bfa120f371cb612e5f0fe80775423bfed60a --- /dev/null +++ b/lib/test_stackinit.c @@ -0,0 +1,402 @@ +// SPDX-Licenses: GPLv2 +/* + * Test cases for compiler-based stack variable zeroing via future + * compiler flags or CONFIG_GCC_PLUGIN_STRUCTLEAK*. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +/* Exfiltration buffer. */ +#define MAX_VAR_SIZE 128 +static u8 check_buf[MAX_VAR_SIZE]; + +/* Character array to trigger stack protector in all functions. */ +#define VAR_BUFFER 32 + +/* Volatile mask to convince compiler to copy memory with 0xff. */ +static volatile u8 forced_mask = 0xff; + +/* Location and size tracking to validate fill and test are colocated. */ +static void *fill_start, *target_start; +static size_t fill_size, target_size; + +static bool range_contains(char *haystack_start, size_t haystack_size, + char *needle_start, size_t needle_size) +{ + if (needle_start >= haystack_start && + needle_start + needle_size <= haystack_start + haystack_size) + return true; + return false; +} + +#define DO_NOTHING_TYPE_SCALAR(var_type) var_type +#define DO_NOTHING_TYPE_STRING(var_type) void +#define DO_NOTHING_TYPE_STRUCT(var_type) void + +#define DO_NOTHING_RETURN_SCALAR(ptr) *(ptr) +#define DO_NOTHING_RETURN_STRING(ptr) /**/ +#define DO_NOTHING_RETURN_STRUCT(ptr) /**/ + +#define DO_NOTHING_CALL_SCALAR(var, name) \ + (var) = do_nothing_ ## name(&(var)) +#define DO_NOTHING_CALL_STRING(var, name) \ + do_nothing_ ## name(var) +#define DO_NOTHING_CALL_STRUCT(var, name) \ + do_nothing_ ## name(&(var)) + +#define FETCH_ARG_SCALAR(var) &var +#define FETCH_ARG_STRING(var) var +#define FETCH_ARG_STRUCT(var) &var + +#define FILL_SIZE_STRING 16 + +#define INIT_CLONE_SCALAR /**/ +#define INIT_CLONE_STRING [FILL_SIZE_STRING] +#define INIT_CLONE_STRUCT /**/ + +#define INIT_SCALAR_none /**/ +#define INIT_SCALAR_zero = 0 + +#define INIT_STRING_none [FILL_SIZE_STRING] /**/ +#define INIT_STRING_zero [FILL_SIZE_STRING] = { } + +#define INIT_STRUCT_none /**/ +#define INIT_STRUCT_zero = { } +#define INIT_STRUCT_static_partial = { .two = 0, } +#define INIT_STRUCT_static_all = { .one = arg->one, \ + .two = arg->two, \ + .three = arg->three, \ + .four = arg->four, \ + } +#define INIT_STRUCT_dynamic_partial = { .two = arg->two, } +#define INIT_STRUCT_dynamic_all = { .one = arg->one, \ + .two = arg->two, \ + .three = arg->three, \ + .four = arg->four, \ + } +#define INIT_STRUCT_runtime_partial ; \ + var.two = 0 +#define INIT_STRUCT_runtime_all ; \ + var.one = 0; \ + var.two = 0; \ + var.three = 0; \ + memset(&var.four, 0, \ + sizeof(var.four)) + +/* + * @name: unique string name for the test + * @var_type: type to be tested for zeroing initialization + * @which: is this a SCALAR, STRING, or STRUCT type? + * @init_level: what kind of initialization is performed + * @xfail: is this test expected to fail? + */ +#define DEFINE_TEST_DRIVER(name, var_type, which, xfail) \ +/* Returns 0 on success, 1 on failure. */ \ +static noinline __init int test_ ## name (void) \ +{ \ + var_type zero INIT_CLONE_ ## which; \ + int ignored; \ + u8 sum = 0, i; \ + \ + /* Notice when a new test is larger than expected. */ \ + BUILD_BUG_ON(sizeof(zero) > MAX_VAR_SIZE); \ + \ + /* Fill clone type with zero for per-field init. */ \ + memset(&zero, 0x00, sizeof(zero)); \ + /* Clear entire check buffer for 0xFF overlap test. */ \ + memset(check_buf, 0x00, sizeof(check_buf)); \ + /* Fill stack with 0xFF. */ \ + ignored = leaf_ ##name((unsigned long)&ignored, 1, \ + FETCH_ARG_ ## which(zero)); \ + /* Verify all bytes overwritten with 0xFF. */ \ + for (sum = 0, i = 0; i < target_size; i++) \ + sum += (check_buf[i] != 0xFF); \ + if (sum) { \ + pr_err(#name ": leaf fill was not 0xFF!?\n"); \ + return 1; \ + } \ + /* Clear entire check buffer for later bit tests. */ \ + memset(check_buf, 0x00, sizeof(check_buf)); \ + /* Extract stack-defined variable contents. */ \ + ignored = leaf_ ##name((unsigned long)&ignored, 0, \ + FETCH_ARG_ ## which(zero)); \ + \ + /* Validate that compiler lined up fill and target. */ \ + if (!range_contains(fill_start, fill_size, \ + target_start, target_size)) { \ + pr_err(#name ": stack fill missed target!?\n"); \ + pr_err(#name ": fill %zu wide\n", fill_size); \ + pr_err(#name ": target offset by %d\n", \ + (int)((ssize_t)(uintptr_t)fill_start - \ + (ssize_t)(uintptr_t)target_start)); \ + return 1; \ + } \ + \ + /* Look for any bytes still 0xFF in check region. */ \ + for (sum = 0, i = 0; i < target_size; i++) \ + sum += (check_buf[i] == 0xFF); \ + \ + if (sum == 0) { \ + pr_info(#name " ok\n"); \ + return 0; \ + } else { \ + pr_warn(#name " %sFAIL (uninit bytes: %d)\n", \ + (xfail) ? "X" : "", sum); \ + return (xfail) ? 0 : 1; \ + } \ +} +#define DEFINE_TEST(name, var_type, which, init_level) \ +/* no-op to force compiler into ignoring "uninitialized" vars */\ +static noinline __init DO_NOTHING_TYPE_ ## which(var_type) \ +do_nothing_ ## name(var_type *ptr) \ +{ \ + /* Will always be true, but compiler doesn't know. */ \ + if ((unsigned long)ptr > 0x2) \ + return DO_NOTHING_RETURN_ ## which(ptr); \ + else \ + return DO_NOTHING_RETURN_ ## which(ptr + 1); \ +} \ +static noinline __init int leaf_ ## name(unsigned long sp, \ + bool fill, \ + var_type *arg) \ +{ \ + char buf[VAR_BUFFER]; \ + var_type var INIT_ ## which ## _ ## init_level; \ + \ + target_start = &var; \ + target_size = sizeof(var); \ + /* \ + * Keep this buffer around to make sure we've got a \ + * stack frame of SOME kind... \ + */ \ + memset(buf, (char)(sp & 0xff), sizeof(buf)); \ + /* Fill variable with 0xFF. */ \ + if (fill) { \ + fill_start = &var; \ + fill_size = sizeof(var); \ + memset(fill_start, \ + (char)((sp & 0xff) | forced_mask), \ + fill_size); \ + } \ + \ + /* Silence "never initialized" warnings. */ \ + DO_NOTHING_CALL_ ## which(var, name); \ + \ + /* Exfiltrate "var". */ \ + memcpy(check_buf, target_start, target_size); \ + \ + return (int)buf[0] | (int)buf[sizeof(buf) - 1]; \ +} \ +DEFINE_TEST_DRIVER(name, var_type, which, 0) + +/* Structure with no padding. */ +struct test_packed { + unsigned long one; + unsigned long two; + unsigned long three; + unsigned long four; +}; + +/* Simple structure with padding likely to be covered by compiler. */ +struct test_small_hole { + size_t one; + char two; + /* 3 byte padding hole here. */ + int three; + unsigned long four; +}; + +/* Try to trigger unhandled padding in a structure. */ +struct test_aligned { + u32 internal1; + u64 internal2; +} __aligned(64); + +struct test_big_hole { + u8 one; + u8 two; + u8 three; + /* 61 byte padding hole here. */ + struct test_aligned four; +} __aligned(64); + +struct test_trailing_hole { + char *one; + char *two; + char *three; + char four; + /* "sizeof(unsigned long) - 1" byte padding hole here. */ +}; + +/* Test if STRUCTLEAK is clearing structs with __user fields. */ +struct test_user { + u8 one; + unsigned long two; + char __user *three; + unsigned long four; +}; + +#define DEFINE_SCALAR_TEST(name, init) \ + DEFINE_TEST(name ## _ ## init, name, SCALAR, init) + +#define DEFINE_SCALAR_TESTS(init) \ + DEFINE_SCALAR_TEST(u8, init); \ + DEFINE_SCALAR_TEST(u16, init); \ + DEFINE_SCALAR_TEST(u32, init); \ + DEFINE_SCALAR_TEST(u64, init); \ + DEFINE_TEST(char_array_ ## init, unsigned char, STRING, init) + +#define DEFINE_STRUCT_TEST(name, init) \ + DEFINE_TEST(name ## _ ## init, \ + struct test_ ## name, STRUCT, init) + +#define DEFINE_STRUCT_TESTS(init) \ + DEFINE_STRUCT_TEST(small_hole, init); \ + DEFINE_STRUCT_TEST(big_hole, init); \ + DEFINE_STRUCT_TEST(trailing_hole, init); \ + DEFINE_STRUCT_TEST(packed, init) + +/* These should be fully initialized all the time! */ +DEFINE_SCALAR_TESTS(zero); +DEFINE_STRUCT_TESTS(zero); +/* Static initialization: padding may be left uninitialized. */ +DEFINE_STRUCT_TESTS(static_partial); +DEFINE_STRUCT_TESTS(static_all); +/* Dynamic initialization: padding may be left uninitialized. */ +DEFINE_STRUCT_TESTS(dynamic_partial); +DEFINE_STRUCT_TESTS(dynamic_all); +/* Runtime initialization: padding may be left uninitialized. */ +DEFINE_STRUCT_TESTS(runtime_partial); +DEFINE_STRUCT_TESTS(runtime_all); +/* No initialization without compiler instrumentation. */ +DEFINE_SCALAR_TESTS(none); +DEFINE_STRUCT_TESTS(none); +DEFINE_TEST(user, struct test_user, STRUCT, none); + +/* + * Check two uses through a variable declaration outside either path, + * which was noticed as a special case in porting earlier stack init + * compiler logic. + */ +static int noinline __leaf_switch_none(int path, bool fill) +{ + uint64_t var; + + switch (path) { + + case 1: + target_start = &var; + target_size = sizeof(var); + if (fill) { + fill_start = &var; + fill_size = sizeof(var); + + memset(fill_start, forced_mask | 0x55, fill_size); + } + memcpy(check_buf, target_start, target_size); + break; + case 2: + target_start = &var; + target_size = sizeof(var); + if (fill) { + fill_start = &var; + fill_size = sizeof(var); + + memset(fill_start, forced_mask | 0xaa, fill_size); + } + memcpy(check_buf, target_start, target_size); + break; + default: + var = 5; + return var & forced_mask; + } + return 0; +} + +static noinline __init int leaf_switch_1_none(unsigned long sp, bool fill, + uint64_t *arg) +{ + return __leaf_switch_none(1, fill); +} + +static noinline __init int leaf_switch_2_none(unsigned long sp, bool fill, + uint64_t *arg) +{ + return __leaf_switch_none(2, fill); +} + +/* + * These are expected to fail for most configurations because neither + * GCC nor Clang have a way to perform initialization of variables in + * non-code areas (i.e. in a switch statement before the first "case"). + * https://bugs.llvm.org/show_bug.cgi?id=44916 + */ +DEFINE_TEST_DRIVER(switch_1_none, uint64_t, SCALAR, 1); +DEFINE_TEST_DRIVER(switch_2_none, uint64_t, SCALAR, 1); + +static int __init test_stackinit_init(void) +{ + unsigned int failures = 0; + +#define test_scalars(init) do { \ + failures += test_u8_ ## init (); \ + failures += test_u16_ ## init (); \ + failures += test_u32_ ## init (); \ + failures += test_u64_ ## init (); \ + failures += test_char_array_ ## init (); \ + } while (0) + +#define test_structs(init) do { \ + failures += test_small_hole_ ## init (); \ + failures += test_big_hole_ ## init (); \ + failures += test_trailing_hole_ ## init (); \ + failures += test_packed_ ## init (); \ + } while (0) + + /* These are explicitly initialized and should always pass. */ + test_scalars(zero); + test_structs(zero); + /* Padding here appears to be accidentally always initialized? */ + test_structs(dynamic_partial); + /* Padding initialization depends on compiler behaviors. */ + test_structs(static_partial); + test_structs(static_all); + test_structs(dynamic_all); + test_structs(runtime_partial); + test_structs(runtime_all); + + /* STRUCTLEAK_BYREF_ALL should cover everything from here down. */ + test_scalars(none); + failures += test_switch_1_none(); + failures += test_switch_2_none(); + + /* STRUCTLEAK_BYREF should cover from here down. */ + test_structs(none); + + /* STRUCTLEAK will only cover this. */ + failures += test_user(); + + if (failures == 0) { + pr_info("all tests passed!\n"); + } else { + pr_err("failures: %u\n", failures); + /* + * Android 4.14 only: if this test is built as part of the + * kernel, make the failure visible. + */ + panic("Test failed!\n"); + } + + return failures ? -EINVAL : 0; +} +module_init(test_stackinit_init); + +static void __exit test_stackinit_exit(void) +{ } +module_exit(test_stackinit_exit); + +MODULE_LICENSE("GPL"); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 5c089f2d2d4c74f4226ebb81e6d01b66e6bc30d8..8847f84da129b3330f25287c330c822a91edeff6 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -163,16 +163,13 @@ static ssize_t enabled_store(struct kobject *kobj, { ssize_t ret = count; - if (!memcmp("always", buf, - min(sizeof("always")-1, count))) { + if (sysfs_streq(buf, "always")) { clear_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, &transparent_hugepage_flags); set_bit(TRANSPARENT_HUGEPAGE_FLAG, &transparent_hugepage_flags); - } else if (!memcmp("madvise", buf, - min(sizeof("madvise")-1, count))) { + } else if (sysfs_streq(buf, "madvise")) { clear_bit(TRANSPARENT_HUGEPAGE_FLAG, &transparent_hugepage_flags); set_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, &transparent_hugepage_flags); - } else if (!memcmp("never", buf, - min(sizeof("never")-1, count))) { + } else if (sysfs_streq(buf, "never")) { clear_bit(TRANSPARENT_HUGEPAGE_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, &transparent_hugepage_flags); } else @@ -236,32 +233,27 @@ static ssize_t defrag_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { - if (!memcmp("always", buf, - min(sizeof("always")-1, count))) { + if (sysfs_streq(buf, "always")) { clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); - } else if (!memcmp("defer+madvise", buf, - min(sizeof("defer+madvise")-1, count))) { + } else if (sysfs_streq(buf, "defer+madvise")) { clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); - } else if (!memcmp("defer", buf, - min(sizeof("defer")-1, count))) { + } else if (sysfs_streq(buf, "defer")) { clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); - } else if (!memcmp("madvise", buf, - min(sizeof("madvise")-1, count))) { + } else if (sysfs_streq(buf, "madvise")) { clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); - } else if (!memcmp("never", buf, - min(sizeof("never")-1, count))) { + } else if (sysfs_streq(buf, "never")) { clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); @@ -2562,7 +2554,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) unsigned long flags; pgoff_t end; - VM_BUG_ON_PAGE(is_huge_zero_page(page), page); + VM_BUG_ON_PAGE(is_huge_zero_page(head), head); VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(!PageCompound(page), page); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 9e8c023b11688295f9ae5e8a69b7870662d536ce..9ac4f76310cfd2b95739a9c98bcd452541f593be 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4747,8 +4747,8 @@ pte_t *huge_pte_offset(struct mm_struct *mm, { pgd_t *pgd; p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; + pud_t *pud, pud_entry; + pmd_t *pmd, pmd_entry; pgd = pgd_offset(mm, addr); if (!pgd_present(*pgd)) @@ -4758,17 +4758,19 @@ pte_t *huge_pte_offset(struct mm_struct *mm, return NULL; pud = pud_offset(p4d, addr); - if (sz != PUD_SIZE && pud_none(*pud)) + pud_entry = READ_ONCE(*pud); + if (sz != PUD_SIZE && pud_none(pud_entry)) return NULL; /* hugepage or swap? */ - if (pud_huge(*pud) || !pud_present(*pud)) + if (pud_huge(pud_entry) || !pud_present(pud_entry)) return (pte_t *)pud; pmd = pmd_offset(pud, addr); - if (sz != PMD_SIZE && pmd_none(*pmd)) + pmd_entry = READ_ONCE(*pmd); + if (sz != PMD_SIZE && pmd_none(pmd_entry)) return NULL; /* hugepage or swap? */ - if (pmd_huge(*pmd) || !pmd_present(*pmd)) + if (pmd_huge(pmd_entry) || !pmd_present(pmd_entry)) return (pte_t *)pmd; return NULL; diff --git a/mm/ksm.c b/mm/ksm.c index f288fc70c4462a3a2c40f4425e0d6d5925dcc92b..1ba1593726798e8fba52810f29f7b70ddc69b5c1 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2074,8 +2074,16 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) down_read(&mm->mmap_sem); vma = find_mergeable_vma(mm, rmap_item->address); - err = try_to_merge_one_page(vma, page, - ZERO_PAGE(rmap_item->address)); + if (vma) { + err = try_to_merge_one_page(vma, page, + ZERO_PAGE(rmap_item->address)); + } else { + /* + * If the vma is out of date, we do not need to + * continue. + */ + err = 0; + } up_read(&mm->mmap_sem); /* * In case of failure, the page was not really empty, so we diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 1b709c775229b09ed0da043f4c652dd6b110bbae..082ac42cca234d259e9f932d23e7e4910f61af3a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3563,7 +3563,7 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg, struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; unsigned long usage; - int i, j, size; + int i, j, size, entries; mutex_lock(&memcg->thresholds_lock); @@ -3583,14 +3583,20 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg, __mem_cgroup_threshold(memcg, type == _MEMSWAP); /* Calculate new number of threshold */ - size = 0; + size = entries = 0; for (i = 0; i < thresholds->primary->size; i++) { if (thresholds->primary->entries[i].eventfd != eventfd) size++; + else + entries++; } new = thresholds->spare; + /* If no items related to eventfd have been cleared, nothing to do */ + if (!entries) + goto unlock; + /* Set thresholds array to NULL if we don't have thresholds */ if (!size) { kfree(new); @@ -5912,19 +5918,9 @@ void mem_cgroup_sk_alloc(struct sock *sk) if (!mem_cgroup_sockets_enabled) return; - /* - * Socket cloning can throw us here with sk_memcg already - * filled. It won't however, necessarily happen from - * process context. So the test for root memcg given - * the current task's memcg won't help us in this case. - * - * Respecting the original socket's memcg is a better - * decision in this case. - */ - if (sk->sk_memcg) { - css_get(&sk->sk_memcg->css); + /* Do not associate the sock with unrelated interrupted task's memcg. */ + if (in_interrupt()) return; - } rcu_read_lock(); memcg = mem_cgroup_from_task(current); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 6bc6c2f833a4a30819bc65796f6478380051c27c..b29d66b66dbe0c12c2b333dc5e80c84448b455e4 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2769,7 +2769,9 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) switch (mode) { case MPOL_PREFERRED: /* - * Insist on a nodelist of one node only + * Insist on a nodelist of one node only, although later + * we use first_node(nodes) to grab a single node, so here + * nodelist (or nodes) cannot be empty. */ if (nodelist) { char *rest = nodelist; @@ -2777,6 +2779,8 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) rest++; if (*rest) goto out; + if (nodes_empty(nodes)) + goto out; } break; case MPOL_INTERLEAVE: diff --git a/mm/mmap.c b/mm/mmap.c index 4c7f5ae61837ff2b186dc01972b54d80815708a4..573e0ac6f1f5b779e84bff02f0bab6d851b97a04 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -202,8 +202,6 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) bool populate; LIST_HEAD(uf); - brk = untagged_addr(brk); - if (down_write_killable(&mm->mmap_sem)) return -EINTR; @@ -1598,8 +1596,6 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, struct file *file = NULL; unsigned long retval; - addr = untagged_addr(addr); - if (!(flags & MAP_ANONYMOUS)) { audit_mmap_fd(fd, flags); file = fget(fd); diff --git a/mm/mprotect.c b/mm/mprotect.c index 2fb38d9c7e123858770bb35249d20b20f90f4740..3979aa727f896316338e55ef93a30b38f2727fd8 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -148,6 +148,31 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, return pages; } +/* + * Used when setting automatic NUMA hinting protection where it is + * critical that a numa hinting PMD is not confused with a bad PMD. + */ +static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd) +{ + pmd_t pmdval = pmd_read_atomic(pmd); + + /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + barrier(); +#endif + + if (pmd_none(pmdval)) + return 1; + if (pmd_trans_huge(pmdval)) + return 0; + if (unlikely(pmd_bad(pmdval))) { + pmd_clear_bad(pmd); + return 1; + } + + return 0; +} + static inline unsigned long change_pmd_range(struct vm_area_struct *vma, pud_t *pud, unsigned long addr, unsigned long end, pgprot_t newprot, int dirty_accountable, int prot_numa) @@ -164,8 +189,17 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, unsigned long this_pages; next = pmd_addr_end(addr, end); - if (!is_swap_pmd(*pmd) && !pmd_trans_huge(*pmd) && !pmd_devmap(*pmd) - && pmd_none_or_clear_bad(pmd)) + + /* + * Automatic NUMA balancing walks the tables with mmap_sem + * held for read. It's possible a parallel update to occur + * between pmd_trans_huge() and a pmd_none_or_clear_bad() + * check leading to a false positive and clearing. + * Hence, it's necessary to atomically read the PMD value + * for all the checks. + */ + if (!is_swap_pmd(*pmd) && !pmd_devmap(*pmd) && + pmd_none_or_clear_bad_unless_trans_huge(pmd)) goto next; /* invoke the mmu notifier if the pmd is populated */ diff --git a/mm/mremap.c b/mm/mremap.c index 9737d473089d3df70b60ff4fc60793ad04532efc..d18f8429596f6a81e99b2bc1b83012e15f1db77f 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -543,7 +543,6 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, LIST_HEAD(uf_unmap); addr = untagged_addr(addr); - new_addr = untagged_addr(new_addr); if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) return ret; diff --git a/mm/nommu.c b/mm/nommu.c index 040bde3ef3f782ddde0fd184df13d6e9aa21a1dd..f430e87f4ea439d12c52a927090519d83f42dfbd 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -450,10 +450,14 @@ void vm_unmap_aliases(void) EXPORT_SYMBOL_GPL(vm_unmap_aliases); /* - * Implement a stub for vmalloc_sync_all() if the architecture chose not to - * have one. + * Implement a stub for vmalloc_sync_[un]mapping() if the architecture + * chose not to have one. */ -void __weak vmalloc_sync_all(void) +void __weak vmalloc_sync_mappings(void) +{ +} + +void __weak vmalloc_sync_unmappings(void) { } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bfcbb43fd7d98061bebbb0df9200b7afec0a16f7..496ad8492c92c29660b8e0cc9071990be2c94772 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4534,11 +4534,11 @@ void *page_frag_alloc(struct page_frag_cache *nc, /* Even if we own the page, we do not use atomic_set(). * This would break get_page_unless_zero() users. */ - page_ref_add(page, size); + page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE); /* reset page count bias and offset to start of new frag */ nc->pfmemalloc = page_is_pfmemalloc(page); - nc->pagecnt_bias = size + 1; + nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; nc->offset = size; } @@ -4554,10 +4554,10 @@ void *page_frag_alloc(struct page_frag_cache *nc, size = nc->size; #endif /* OK, page count is 0, we can safely set it */ - set_page_count(page, size + 1); + set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1); /* reset page count bias and offset to start of new frag */ - nc->pagecnt_bias = size + 1; + nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1; offset = size - fragsz; } diff --git a/mm/shmem.c b/mm/shmem.c index 393a674b92bf8965dab63e6848fe84a61c76a577..05399bbc865e9b4db126646005f4e75bd0aa2c47 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2352,11 +2352,11 @@ static int shmem_mfill_atomic_pte(struct mm_struct *dst_mm, lru_cache_add_anon(page); - spin_lock(&info->lock); + spin_lock_irq(&info->lock); info->alloced++; inode->i_blocks += BLOCKS_PER_PAGE; shmem_recalc_inode(inode); - spin_unlock(&info->lock); + spin_unlock_irq(&info->lock); inc_mm_counter(dst_mm, mm_counter_file(page)); page_add_file_rmap(page, false); diff --git a/mm/slub.c b/mm/slub.c index 5dcbbea0d57ab85056dd4ff2b19622fba8bd30f1..fd5f9337bc7a8accbfae91170915302fded168de 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -259,7 +259,7 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr, * freepointer to be restored incorrectly. */ return (void *)((unsigned long)ptr ^ s->random ^ - (unsigned long)kasan_reset_tag((void *)ptr_addr)); + swab((unsigned long)kasan_reset_tag((void *)ptr_addr))); #else return ptr; #endif @@ -280,8 +280,7 @@ static inline void *get_freepointer(struct kmem_cache *s, void *object) static void prefetch_freepointer(const struct kmem_cache *s, void *object) { - if (object) - prefetch(freelist_dereference(s, object + s->offset)); + prefetch(object + s->offset); } static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) @@ -2001,8 +2000,6 @@ static void *get_partial(struct kmem_cache *s, gfp_t flags, int node, if (node == NUMA_NO_NODE) searchnode = numa_mem_id(); - else if (!node_present_pages(node)) - searchnode = node_to_mem_node(node); object = get_partial_node(s, get_node(s, searchnode), c, flags); if (object || node != NUMA_NO_NODE) @@ -2599,17 +2596,27 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, struct page *page; page = c->page; - if (!page) + if (!page) { + /* + * if the node is not online or has no normal memory, just + * ignore the node constraint + */ + if (unlikely(node != NUMA_NO_NODE && + !node_state(node, N_NORMAL_MEMORY))) + node = NUMA_NO_NODE; goto new_slab; + } redo: if (unlikely(!node_match(page, node))) { - int searchnode = node; - - if (node != NUMA_NO_NODE && !node_present_pages(node)) - searchnode = node_to_mem_node(node); - - if (unlikely(!node_match(page, searchnode))) { + /* + * same as above but node_match() being false already + * implies node != NUMA_NO_NODE + */ + if (!node_state(node, N_NORMAL_MEMORY)) { + node = NUMA_NO_NODE; + goto redo; + } else { stat(s, ALLOC_NODE_MISMATCH); deactivate_slab(s, page, c->freelist, c); goto new_slab; @@ -3034,11 +3041,13 @@ static __always_inline void do_slab_free(struct kmem_cache *s, barrier(); if (likely(page == c->page)) { - set_freepointer(s, tail_obj, c->freelist); + void **freelist = READ_ONCE(c->freelist); + + set_freepointer(s, tail_obj, freelist); if (unlikely(!this_cpu_cmpxchg_double( s->cpu_slab->freelist, s->cpu_slab->tid, - c->freelist, tid, + freelist, tid, head, next_tid(tid)))) { note_cmpxchg_failure("slab_free", s, tid); @@ -3211,6 +3220,15 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, void *object = c->freelist; if (unlikely(!object)) { + /* + * We may have removed an object from c->freelist using + * the fastpath in the previous iteration; in that case, + * c->tid has not been bumped yet. + * Since ___slab_alloc() may reenable interrupts while + * allocating memory, we should bump c->tid now. + */ + c->tid = next_tid(c->tid); + /* * Invoking slow path likely have side-effect * of re-populating per CPU c->freelist diff --git a/mm/swapfile.c b/mm/swapfile.c index 2ba909118887fe016f9671c89a9fad29e3aa151f..72c0a28a0e103c111457bcb5e3fa2ef1e77ec31d 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2403,6 +2403,7 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, list_add_tail(&new_se->list, &sis->first_swap_extent.list); return 1; } +EXPORT_SYMBOL_GPL(add_swap_extent); /* * A `swap extent' is a simple thing which maps a contiguous range of pages diff --git a/mm/util.c b/mm/util.c index 990acbf5c2f80a34ef2f505ab63dc1b4aaab1fd1..b8e849125eccdc49eb135f3949f94c4f5c0d766a 100644 --- a/mm/util.c +++ b/mm/util.c @@ -367,7 +367,8 @@ EXPORT_SYMBOL(vm_mmap); * __GFP_RETRY_MAYFAIL is supported, and it should be used only if kmalloc is * preferable to the vmalloc fallback, due to visible performance drawbacks. * - * Any use of gfp flags outside of GFP_KERNEL should be consulted with mm people. + * Please note that any use of gfp flags outside of GFP_KERNEL is careful to not + * fall back to vmalloc. */ void *kvmalloc_node(size_t size, gfp_t flags, int node) { @@ -378,7 +379,8 @@ void *kvmalloc_node(size_t size, gfp_t flags, int node) * vmalloc uses GFP_KERNEL for some internal allocations (e.g page tables) * so the given set of flags has to be compatible. */ - WARN_ON_ONCE((flags & GFP_KERNEL) != GFP_KERNEL); + if ((flags & GFP_KERNEL) != GFP_KERNEL) + return kmalloc_node(size, flags, node); /* * We want to attempt a large physically contiguous block first because diff --git a/mm/vmalloc.c b/mm/vmalloc.c index e2d2ceb47075bf8b56676fee601af35b4b27ea17..7e3bcd86c95761439c6271b9bab023b0b39f2632 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1779,7 +1780,6 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, nr_pages = get_vm_area_size(area) >> PAGE_SHIFT; array_size = (nr_pages * sizeof(struct page *)); - area->nr_pages = nr_pages; /* Please note that the recursion is strictly bounded. */ if (array_size > PAGE_SIZE) { pages = __vmalloc_node(array_size, 1, nested_gfp|highmem_mask, @@ -1787,13 +1787,16 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, } else { pages = kmalloc_node(array_size, nested_gfp, node); } - area->pages = pages; - if (!area->pages) { + + if (!pages) { remove_vm_area(area->addr); kfree(area); return NULL; } + area->pages = pages; + area->nr_pages = nr_pages; + for (i = 0; i < area->nr_pages; i++) { struct page *page; @@ -1868,7 +1871,7 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align, * First make sure the mappings are removed from all page-tables * before they are freed. */ - vmalloc_sync_all(); + vmalloc_sync_unmappings(); /* * In this function, newly allocated vm_struct has VM_UNINITIALIZED @@ -2343,6 +2346,7 @@ long vwrite(char *buf, char *addr, unsigned long count) * @vma: vma to cover * @uaddr: target user address to start at * @kaddr: virtual address of vmalloc kernel memory + * @pgoff: offset from @kaddr to start at * @size: size of map area * * Returns: 0 for success, -Exxx on failure @@ -2355,9 +2359,15 @@ long vwrite(char *buf, char *addr, unsigned long count) * Similar to remap_pfn_range() (see mm/memory.c) */ int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr, - void *kaddr, unsigned long size) + void *kaddr, unsigned long pgoff, + unsigned long size) { struct vm_struct *area; + unsigned long off; + unsigned long end_index; + + if (check_shl_overflow(pgoff, PAGE_SHIFT, &off)) + return -EINVAL; size = PAGE_ALIGN(size); @@ -2371,8 +2381,10 @@ int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr, if (!(area->flags & VM_USERMAP)) return -EINVAL; - if (kaddr + size > area->addr + get_vm_area_size(area)) + if (check_add_overflow(size, off, &end_index) || + end_index > get_vm_area_size(area)) return -EINVAL; + kaddr += off; do { struct page *page = vmalloc_to_page(kaddr); @@ -2411,22 +2423,25 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, unsigned long pgoff) { return remap_vmalloc_range_partial(vma, vma->vm_start, - addr + (pgoff << PAGE_SHIFT), + addr, pgoff, vma->vm_end - vma->vm_start); } EXPORT_SYMBOL(remap_vmalloc_range); /* - * Implement a stub for vmalloc_sync_all() if the architecture chose not to - * have one. + * Implement stubs for vmalloc_sync_[un]mappings () if the architecture chose + * not to have one. * * The purpose of this function is to make sure the vmalloc area * mappings are identical in all page-tables in the system. */ -void __weak vmalloc_sync_all(void) +void __weak vmalloc_sync_mappings(void) { } +void __weak vmalloc_sync_unmappings(void) +{ +} static int f(pte_t *pte, pgtable_t table, unsigned long addr, void *data) { diff --git a/mm/vmscan.c b/mm/vmscan.c index d0709374d9fadbcda93ad9428e5dc4123173dca8..f60ba74a2da12a62c3680fcbe1059bbfe436724b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2444,10 +2444,13 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, /* * Scan types proportional to swappiness and * their relative recent reclaim efficiency. - * Make sure we don't miss the last page - * because of a round-off error. + * Make sure we don't miss the last page on + * the offlined memory cgroups because of a + * round-off error. */ - scan = DIV64_U64_ROUND_UP(scan * fraction[file], + scan = mem_cgroup_online(memcg) ? + div64_u64(scan * fraction[file], denominator) : + DIV64_U64_ROUND_UP(scan * fraction[file], denominator); break; case SCAN_FILE: diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 8b3f9441b3a01cd5732131226f9e911172b4086c..7a723e124dbb55eef70f3b433de6a5d1aa63558e 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -149,7 +150,7 @@ static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node) * Return: 0 on success, a negative error code otherwise. */ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, - int max_if_num) + unsigned int max_if_num) { void *data_ptr; size_t old_size; @@ -193,7 +194,8 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, */ static void batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, - int max_if_num, int del_if_num) + unsigned int max_if_num, + unsigned int del_if_num) { size_t chunk_size; size_t if_offset; @@ -231,7 +233,8 @@ batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, */ static void batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, - int max_if_num, int del_if_num) + unsigned int max_if_num, + unsigned int del_if_num) { size_t if_offset; void *data_ptr; @@ -268,7 +271,8 @@ batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, * Return: 0 on success, a negative error code otherwise. */ static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node, - int max_if_num, int del_if_num) + unsigned int max_if_num, + unsigned int del_if_num) { spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); @@ -302,7 +306,8 @@ static struct batadv_orig_node * batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) { struct batadv_orig_node *orig_node; - int size, hash_added; + int hash_added; + size_t size; orig_node = batadv_orig_hash_find(bat_priv, addr); if (orig_node) @@ -366,14 +371,18 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) unsigned char *ogm_buff; u32 random_seqno; + mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); + /* randomize initial seqno to avoid collision */ get_random_bytes(&random_seqno, sizeof(random_seqno)); atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno); hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN; ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC); - if (!ogm_buff) + if (!ogm_buff) { + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); return -ENOMEM; + } hard_iface->bat_iv.ogm_buff = ogm_buff; @@ -385,35 +394,59 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) batadv_ogm_packet->reserved = 0; batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE; + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); + return 0; } static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface) { + mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); + kfree(hard_iface->bat_iv.ogm_buff); hard_iface->bat_iv.ogm_buff = NULL; + + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); } static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) { struct batadv_ogm_packet *batadv_ogm_packet; - unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff; + void *ogm_buff; - batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff; + mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); + + ogm_buff = hard_iface->bat_iv.ogm_buff; + if (!ogm_buff) + goto unlock; + + batadv_ogm_packet = ogm_buff; ether_addr_copy(batadv_ogm_packet->orig, hard_iface->net_dev->dev_addr); ether_addr_copy(batadv_ogm_packet->prev_sender, hard_iface->net_dev->dev_addr); + +unlock: + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); } static void batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface) { struct batadv_ogm_packet *batadv_ogm_packet; - unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff; + void *ogm_buff; - batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff; + mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); + + ogm_buff = hard_iface->bat_iv.ogm_buff; + if (!ogm_buff) + goto unlock; + + batadv_ogm_packet = ogm_buff; batadv_ogm_packet->ttl = BATADV_TTL; + +unlock: + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); } /* when do we schedule our own ogm to be sent */ @@ -890,7 +923,7 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) u32 i; size_t word_index; u8 *w; - int if_num; + unsigned int if_num; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -911,7 +944,11 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) } } -static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) +/** + * batadv_iv_ogm_schedule_buff() - schedule submission of hardif ogm buffer + * @hard_iface: interface whose ogm buffer should be transmitted + */ +static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; @@ -922,8 +959,10 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) u16 tvlv_len = 0; unsigned long send_time; - if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) || - (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)) + lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); + + /* interface already disabled by batadv_iv_ogm_iface_disable */ + if (!*ogm_buff) return; /* the interface gets activated here to avoid race conditions between @@ -992,6 +1031,17 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) batadv_hardif_put(primary_if); } +static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) +{ + if (hard_iface->if_status == BATADV_IF_NOT_IN_USE || + hard_iface->if_status == BATADV_IF_TO_BE_REMOVED) + return; + + mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); + batadv_iv_ogm_schedule_buff(hard_iface); + mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); +} + /** * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an * originator @@ -1020,7 +1070,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_neigh_node *tmp_neigh_node = NULL; struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_node_tmp; - int if_num; + unsigned int if_num; u8 sum_orig, sum_neigh; u8 *neigh_addr; u8 tq_avg; @@ -1179,7 +1229,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, u8 total_count; u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; - int if_num; + unsigned int if_num; unsigned int tq_asym_penalty, inv_asym_penalty; unsigned int combined_tq; unsigned int tq_iface_penalty; @@ -1220,7 +1270,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, orig_node->last_seen = jiffies; /* find packet count of corresponding one hop neighbor */ - spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); + spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); if_num = if_incoming->if_num; orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num]; neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); @@ -1230,7 +1280,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, } else { neigh_rq_count = 0; } - spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); + spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); /* pay attention to not get a value bigger than 100 % */ if (orig_eq_count > neigh_rq_count) @@ -1698,9 +1748,9 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, if (is_my_orig) { unsigned long *word; - int offset; + size_t offset; s32 bit_pos; - s16 if_num; + unsigned int if_num; u8 *weight; orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, @@ -2477,7 +2527,7 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1, return ret; } -static void batadv_iv_iface_activate(struct batadv_hard_iface *hard_iface) +static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface) { /* begin scheduling originator messages on that interface */ batadv_iv_ogm_schedule(hard_iface); @@ -2817,8 +2867,8 @@ static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb, static struct batadv_algo_ops batadv_batman_iv __read_mostly = { .name = "BATMAN_IV", .iface = { - .activate = batadv_iv_iface_activate, .enable = batadv_iv_ogm_iface_enable, + .enabled = batadv_iv_iface_enabled, .disable = batadv_iv_ogm_iface_disable, .update_mac = batadv_iv_ogm_iface_update_mac, .primary_set = batadv_iv_ogm_primary_iface_set, diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 371a1f1651b48d58beef141f002eec7bf3cfe556..eb8cec14b854b4ca1ca23c91c3637c99cb356724 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -19,7 +19,6 @@ #include "main.h" #include -#include #include #include #include @@ -623,11 +622,11 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, int ret = 0; ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); - if (WARN_ON(!ifinfo1)) + if (!ifinfo1) goto err_ifinfo1; ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); - if (WARN_ON(!ifinfo2)) + if (!ifinfo2) goto err_ifinfo2; ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput; @@ -649,11 +648,11 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, bool ret = false; ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); - if (WARN_ON(!ifinfo1)) + if (!ifinfo1) goto err_ifinfo1; ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); - if (WARN_ON(!ifinfo2)) + if (!ifinfo2) goto err_ifinfo2; threshold = ifinfo1->bat_v.throughput / 4; @@ -815,7 +814,7 @@ static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv, } orig_gw = batadv_gw_node_get(bat_priv, orig_node); - if (!orig_node) + if (!orig_gw) goto out; if (batadv_v_gw_throughput_get(orig_gw, &orig_throughput) < 0) diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index e07f636160b67533c63d3c779797347888143605..cec31769bb3fc8e1d2814e71b0540f78e92ef902 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -127,14 +129,12 @@ static void batadv_v_ogm_send_to_if(struct sk_buff *skb, } /** - * batadv_v_ogm_send - periodic worker broadcasting the own OGM - * @work: work queue item + * batadv_v_ogm_send_softif() - periodic worker broadcasting the own OGM + * @bat_priv: the bat priv with all the soft interface information */ -static void batadv_v_ogm_send(struct work_struct *work) +static void batadv_v_ogm_send_softif(struct batadv_priv *bat_priv) { struct batadv_hard_iface *hard_iface; - struct batadv_priv_bat_v *bat_v; - struct batadv_priv *bat_priv; struct batadv_ogm2_packet *ogm_packet; struct sk_buff *skb, *skb_tmp; unsigned char *ogm_buff; @@ -142,8 +142,7 @@ static void batadv_v_ogm_send(struct work_struct *work) u16 tvlv_len = 0; int ret; - bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work); - bat_priv = container_of(bat_v, struct batadv_priv, bat_v); + lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex); if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) goto out; @@ -234,6 +233,23 @@ static void batadv_v_ogm_send(struct work_struct *work) return; } +/** + * batadv_v_ogm_send() - periodic worker broadcasting the own OGM + * @work: work queue item + */ +static void batadv_v_ogm_send(struct work_struct *work) +{ + struct batadv_priv_bat_v *bat_v; + struct batadv_priv *bat_priv; + + bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work); + bat_priv = container_of(bat_v, struct batadv_priv, bat_v); + + mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); + batadv_v_ogm_send_softif(bat_priv); + mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex); +} + /** * batadv_v_ogm_iface_enable - prepare an interface for B.A.T.M.A.N. V * @hard_iface: the interface to prepare @@ -260,11 +276,15 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface) struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface); struct batadv_ogm2_packet *ogm_packet; + mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); if (!bat_priv->bat_v.ogm_buff) - return; + goto unlock; ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff; ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr); + +unlock: + mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex); } /** @@ -886,6 +906,8 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv) atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno); INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send); + mutex_init(&bat_priv->bat_v.ogm_buff_mutex); + return 0; } @@ -897,7 +919,11 @@ void batadv_v_ogm_free(struct batadv_priv *bat_priv) { cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq); + mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); + kfree(bat_priv->bat_v.ogm_buff); bat_priv->bat_v.ogm_buff = NULL; bat_priv->bat_v.ogm_buff_len = 0; + + mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex); } diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index e32ad47c6efdf17914aad1e89029020d15801150..4957d4824437ae0240a732f943d39caf2868923f 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c @@ -18,6 +18,7 @@ #include "debugfs.h" #include "main.h" +#include #include #include #include @@ -338,7 +339,26 @@ int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) } /** - * batadv_debugfs_del_hardif - delete the base directory for a hard interface + * batadv_debugfs_rename_hardif() - Fix debugfs path for renamed hardif + * @hard_iface: hard interface which was renamed + */ +void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface) +{ + const char *name = hard_iface->net_dev->name; + struct dentry *dir; + struct dentry *d; + + dir = hard_iface->debug_dir; + if (!dir) + return; + + d = debugfs_rename(dir->d_parent, dir, dir->d_parent, name); + if (!d) + pr_err("Can't rename debugfs dir to %s\n", name); +} + +/** + * batadv_debugfs_del_hardif() - delete the base directory for a hard interface * in debugfs. * @hard_iface: hard interface which is deleted. */ @@ -401,6 +421,30 @@ int batadv_debugfs_add_meshif(struct net_device *dev) return -ENOMEM; } +/** + * batadv_debugfs_rename_meshif() - Fix debugfs path for renamed softif + * @dev: net_device which was renamed + */ +void batadv_debugfs_rename_meshif(struct net_device *dev) +{ + struct batadv_priv *bat_priv = netdev_priv(dev); + const char *name = dev->name; + struct dentry *dir; + struct dentry *d; + + dir = bat_priv->debug_dir; + if (!dir) + return; + + d = debugfs_rename(dir->d_parent, dir, dir->d_parent, name); + if (!d) + pr_err("Can't rename debugfs dir to %s\n", name); +} + +/** + * batadv_debugfs_del_meshif() - Remove interface dependent debugfs entries + * @dev: netdev struct of the soft interface + */ void batadv_debugfs_del_meshif(struct net_device *dev) { struct batadv_priv *bat_priv = netdev_priv(dev); diff --git a/net/batman-adv/debugfs.h b/net/batman-adv/debugfs.h index 9c5d4a65b98c35239709d9258bb889a61ffef8c2..901bbc357bf42e5c471e50ee5cd4cf42df7e26dc 100644 --- a/net/batman-adv/debugfs.h +++ b/net/batman-adv/debugfs.h @@ -29,8 +29,10 @@ struct net_device; void batadv_debugfs_init(void); void batadv_debugfs_destroy(void); int batadv_debugfs_add_meshif(struct net_device *dev); +void batadv_debugfs_rename_meshif(struct net_device *dev); void batadv_debugfs_del_meshif(struct net_device *dev); int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface); +void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface); void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface); #else @@ -48,6 +50,10 @@ static inline int batadv_debugfs_add_meshif(struct net_device *dev) return 0; } +static inline void batadv_debugfs_rename_meshif(struct net_device *dev) +{ +} + static inline void batadv_debugfs_del_meshif(struct net_device *dev) { } @@ -58,6 +64,11 @@ int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) return 0; } +static inline +void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface) +{ +} + static inline void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface) { diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index c6d37d22bd125f779deeab58ea5035b63ae3f977..788d62073964b2f50979d894427855b21533465f 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -500,6 +500,8 @@ int batadv_frag_send_packet(struct sk_buff *skb, */ if (skb->priority >= 256 && skb->priority <= 263) frag_header.priority = skb->priority - 256; + else + frag_header.priority = 0; ether_addr_copy(frag_header.orig, primary_if->net_dev->dev_addr); ether_addr_copy(frag_header.dest, orig_node->orig); diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 2e1a084b0bd2a10fb567c1adada8ca6ebd978bc7..9fdfa9984f024b33231b934db8ff611a6874fd09 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -738,6 +739,11 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, hard_iface->soft_iface = soft_iface; bat_priv = netdev_priv(hard_iface->soft_iface); + if (bat_priv->num_ifaces >= UINT_MAX) { + ret = -ENOSPC; + goto err_dev; + } + ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface, NULL, NULL); if (ret) @@ -790,6 +796,9 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, batadv_hardif_recalc_extra_skbroom(soft_iface); + if (bat_priv->algo_ops->iface.enabled) + bat_priv->algo_ops->iface.enabled(hard_iface); + out: return 0; @@ -845,7 +854,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); /* nobody uses this interface anymore */ - if (!bat_priv->num_ifaces) { + if (bat_priv->num_ifaces == 0) { batadv_gw_check_client_stop(bat_priv); if (autodel == BATADV_IF_CLEANUP_AUTO) @@ -881,7 +890,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) if (ret) goto free_if; - hard_iface->if_num = -1; + hard_iface->if_num = 0; hard_iface->net_dev = net_dev; hard_iface->soft_iface = NULL; hard_iface->if_status = BATADV_IF_NOT_IN_USE; @@ -893,6 +902,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) INIT_LIST_HEAD(&hard_iface->list); INIT_HLIST_HEAD(&hard_iface->neigh_list); + mutex_init(&hard_iface->bat_iv.ogm_buff_mutex); spin_lock_init(&hard_iface->neigh_list_lock); kref_init(&hard_iface->refcount); @@ -950,6 +960,32 @@ void batadv_hardif_remove_interfaces(void) rtnl_unlock(); } +/** + * batadv_hard_if_event_softif() - Handle events for soft interfaces + * @event: NETDEV_* event to handle + * @net_dev: net_device which generated an event + * + * Return: NOTIFY_* result + */ +static int batadv_hard_if_event_softif(unsigned long event, + struct net_device *net_dev) +{ + struct batadv_priv *bat_priv; + + switch (event) { + case NETDEV_REGISTER: + batadv_sysfs_add_meshif(net_dev); + bat_priv = netdev_priv(net_dev); + batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS); + break; + case NETDEV_CHANGENAME: + batadv_debugfs_rename_meshif(net_dev); + break; + } + + return NOTIFY_DONE; +} + static int batadv_hard_if_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -958,12 +994,8 @@ static int batadv_hard_if_event(struct notifier_block *this, struct batadv_hard_iface *primary_if = NULL; struct batadv_priv *bat_priv; - if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) { - batadv_sysfs_add_meshif(net_dev); - bat_priv = netdev_priv(net_dev); - batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS); - return NOTIFY_DONE; - } + if (batadv_softif_is_valid(net_dev)) + return batadv_hard_if_event_softif(event, net_dev); hard_iface = batadv_hardif_get_by_netdev(net_dev); if (!hard_iface && (event == NETDEV_REGISTER || @@ -1012,6 +1044,9 @@ static int batadv_hard_if_event(struct notifier_block *this, if (batadv_is_wifi_hardif(hard_iface)) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; break; + case NETDEV_CHANGENAME: + batadv_debugfs_rename_hardif(hard_iface); + break; default: break; } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 8e2a4b205257929e9b64f157e8570972cf1383f9..653eaadcfefb4db23c73034c157e7c86fc1bcc06 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -1500,7 +1500,7 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) } int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, - int max_if_num) + unsigned int max_if_num) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_algo_ops *bao = bat_priv->algo_ops; @@ -1535,7 +1535,7 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, } int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, - int max_if_num) + unsigned int max_if_num) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_hashtable *hash = bat_priv->orig_hash; diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index d94220a6d21acf58d55fcf7a179151c67392b055..d6ca52220ec066d8e82096b7487d6f5e9dfd57dc 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -78,9 +78,9 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, - int max_if_num); + unsigned int max_if_num); int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, - int max_if_num); + unsigned int max_if_num); struct batadv_orig_node_vlan * batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, unsigned short vid); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index cd82cff716c78eb9df9f85be139e21693bab7464..f59aac06733e1a7c45f9bb08b48fbf9c42eb740a 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -950,14 +950,10 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, struct batadv_orig_node *orig_node = NULL, *orig_node_gw = NULL; int check, hdr_size = sizeof(*unicast_packet); enum batadv_subtype subtype; - struct ethhdr *ethhdr; int ret = NET_RX_DROP; bool is4addr, is_gw; unicast_packet = (struct batadv_unicast_packet *)skb->data; - unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; - ethhdr = eth_hdr(skb); - is4addr = unicast_packet->packet_type == BATADV_UNICAST_4ADDR; /* the caller function should have already pulled 2 bytes */ if (is4addr) @@ -977,12 +973,14 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) goto free_skb; + unicast_packet = (struct batadv_unicast_packet *)skb->data; + /* packet for me */ if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) { /* If this is a unicast packet from another backgone gw, * drop it. */ - orig_addr_gw = ethhdr->h_source; + orig_addr_gw = eth_hdr(skb)->h_source; orig_node_gw = batadv_orig_hash_find(bat_priv, orig_addr_gw); if (orig_node_gw) { is_gw = batadv_bla_is_backbone_gw(skb, orig_node_gw, @@ -997,6 +995,8 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, } if (is4addr) { + unicast_4addr_packet = + (struct batadv_unicast_4addr_packet *)skb->data; subtype = unicast_4addr_packet->subtype; batadv_dat_inc_counter(bat_priv, subtype); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 2c2670b85fa941f768b0c50c892add075b72e457..dbc516824175bb5ea7f3d5abf0ef07f6a5bdc9a2 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -872,7 +872,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, struct batadv_orig_node_vlan *vlan; u8 *tt_change_ptr; - rcu_read_lock(); + spin_lock_bh(&orig_node->vlan_list_lock); hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { num_vlan++; num_entries += atomic_read(&vlan->tt.num_entries); @@ -910,7 +910,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; out: - rcu_read_unlock(); + spin_unlock_bh(&orig_node->vlan_list_lock); return tvlv_len; } @@ -941,15 +941,20 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_softif_vlan *vlan; u16 num_vlan = 0; - u16 num_entries = 0; + u16 vlan_entries = 0; + u16 total_entries = 0; u16 tvlv_len; u8 *tt_change_ptr; int change_offset; - rcu_read_lock(); + spin_lock_bh(&bat_priv->softif_vlan_list_lock); hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { + vlan_entries = atomic_read(&vlan->tt.num_entries); + if (vlan_entries < 1) + continue; + num_vlan++; - num_entries += atomic_read(&vlan->tt.num_entries); + total_entries += vlan_entries; } change_offset = sizeof(**tt_data); @@ -957,7 +962,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, /* if tt_len is negative, allocate the space needed by the full table */ if (*tt_len < 0) - *tt_len = batadv_tt_len(num_entries); + *tt_len = batadv_tt_len(total_entries); tvlv_len = *tt_len; tvlv_len += change_offset; @@ -974,6 +979,10 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { + vlan_entries = atomic_read(&vlan->tt.num_entries); + if (vlan_entries < 1) + continue; + tt_vlan->vid = htons(vlan->vid); tt_vlan->crc = htonl(vlan->tt.crc); @@ -984,7 +993,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; out: - rcu_read_unlock(); + spin_unlock_bh(&bat_priv->softif_vlan_list_lock); return tvlv_len; } @@ -1544,6 +1553,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, * by a given originator * @entry: the TT global entry to check * @orig_node: the originator to search in the list + * @flags: a pointer to store TT flags for the given @entry received + * from @orig_node * * find out if an orig_node is already in the list of a tt_global_entry. * @@ -1551,7 +1562,8 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, */ static bool batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, - const struct batadv_orig_node *orig_node) + const struct batadv_orig_node *orig_node, + u8 *flags) { struct batadv_tt_orig_list_entry *orig_entry; bool found = false; @@ -1559,6 +1571,10 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); if (orig_entry) { found = true; + + if (flags) + *flags = orig_entry->flags; + batadv_tt_orig_list_entry_put(orig_entry); } @@ -1741,7 +1757,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, if (!(common->flags & BATADV_TT_CLIENT_TEMP)) goto out; if (batadv_tt_global_entry_has_orig(tt_global_entry, - orig_node)) + orig_node, NULL)) goto out_remove; batadv_tt_global_del_orig_list(tt_global_entry); goto add_orig_entry; @@ -2884,23 +2900,46 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv, } /** - * batadv_tt_local_valid - verify that given tt entry is a valid one + * batadv_tt_local_valid() - verify local tt entry and get flags * @entry_ptr: to be checked local tt entry * @data_ptr: not used but definition required to satisfy the callback prototype + * @flags: a pointer to store TT flags for this client to + * + * Checks the validity of the given local TT entry. If it is, then the provided + * flags pointer is updated. * * Return: true if the entry is a valid, false otherwise. */ -static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) +static bool batadv_tt_local_valid(const void *entry_ptr, + const void *data_ptr, + u8 *flags) { const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) return false; + + if (flags) + *flags = tt_common_entry->flags; + return true; } +/** + * batadv_tt_global_valid() - verify global tt entry and get flags + * @entry_ptr: to be checked global tt entry + * @data_ptr: an orig_node object (may be NULL) + * @flags: a pointer to store TT flags for this client to + * + * Checks the validity of the given global TT entry. If it is, then the provided + * flags pointer is updated either with the common (summed) TT flags if data_ptr + * is NULL or the specific, per originator TT flags otherwise. + * + * Return: true if the entry is a valid, false otherwise. + */ static bool batadv_tt_global_valid(const void *entry_ptr, - const void *data_ptr) + const void *data_ptr, + u8 *flags) { const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; const struct batadv_tt_global_entry *tt_global_entry; @@ -2914,7 +2953,8 @@ static bool batadv_tt_global_valid(const void *entry_ptr, struct batadv_tt_global_entry, common); - return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); + return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node, + flags); } /** @@ -2924,25 +2964,34 @@ static bool batadv_tt_global_valid(const void *entry_ptr, * @hash: hash table containing the tt entries * @tt_len: expected tvlv tt data buffer length in number of bytes * @tvlv_buff: pointer to the buffer to fill with the TT data - * @valid_cb: function to filter tt change entries + * @valid_cb: function to filter tt change entries and to return TT flags * @cb_data: data passed to the filter function as argument + * + * Fills the tvlv buff with the tt entries from the specified hash. If valid_cb + * is not provided then this becomes a no-op. */ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, struct batadv_hashtable *hash, void *tvlv_buff, u16 tt_len, bool (*valid_cb)(const void *, - const void *), + const void *, + u8 *flags), void *cb_data) { struct batadv_tt_common_entry *tt_common_entry; struct batadv_tvlv_tt_change *tt_change; struct hlist_head *head; u16 tt_tot, tt_num_entries = 0; + u8 flags; + bool ret; u32 i; tt_tot = batadv_tt_entries(tt_len); tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; + if (!valid_cb) + return; + rcu_read_lock(); for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2952,11 +3001,12 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, if (tt_tot == tt_num_entries) break; - if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) + ret = valid_cb(tt_common_entry, cb_data, &flags); + if (!ret) continue; ether_addr_copy(tt_change->addr, tt_common_entry->addr); - tt_change->flags = tt_common_entry->flags; + tt_change->flags = flags; tt_change->vid = htons(tt_common_entry->vid); memset(tt_change->reserved, 0, sizeof(tt_change->reserved)); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index d5e3968619b8e36f52875623e062dcad1c0e43a7..540a9c5c2270842050e2883ff6869604e6d30c4b 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include /* for linux/wait.h */ @@ -81,11 +82,13 @@ enum batadv_dhcp_recipient { * @ogm_buff: buffer holding the OGM packet * @ogm_buff_len: length of the OGM packet buffer * @ogm_seqno: OGM sequence number - used to identify each OGM + * @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */ struct batadv_hard_iface_bat_iv { unsigned char *ogm_buff; int ogm_buff_len; atomic_t ogm_seqno; + struct mutex ogm_buff_mutex; }; /** @@ -155,7 +158,7 @@ enum batadv_hard_iface_wifi_flags { */ struct batadv_hard_iface { struct list_head list; - s16 if_num; + unsigned int if_num; char if_status; u8 num_bcasts; u32 wifi_flags; @@ -989,12 +992,14 @@ struct batadv_softif_vlan { * @ogm_buff: buffer holding the OGM packet * @ogm_buff_len: length of the OGM packet buffer * @ogm_seqno: OGM sequence number - used to identify each OGM + * @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len * @ogm_wq: workqueue used to schedule OGM transmissions */ struct batadv_priv_bat_v { unsigned char *ogm_buff; int ogm_buff_len; atomic_t ogm_seqno; + struct mutex ogm_buff_mutex; struct delayed_work ogm_wq; }; @@ -1081,7 +1086,7 @@ struct batadv_priv { atomic_t bcast_seqno; atomic_t bcast_queue_left; atomic_t batman_queue_left; - char num_ifaces; + unsigned int num_ifaces; struct kobject *mesh_obj; struct dentry *debug_dir; struct hlist_head forw_bat_list; @@ -1424,6 +1429,7 @@ struct batadv_forw_packet { * @activate: start routing mechanisms when hard-interface is brought up * (optional) * @enable: init routing info when hard-interface is enabled + * @enabled: notification when hard-interface was enabled (optional) * @disable: de-init routing info when hard-interface is disabled * @update_mac: (re-)init mac addresses of the protocol information * belonging to this hard-interface @@ -1432,6 +1438,7 @@ struct batadv_forw_packet { struct batadv_algo_iface_ops { void (*activate)(struct batadv_hard_iface *hard_iface); int (*enable)(struct batadv_hard_iface *hard_iface); + void (*enabled)(struct batadv_hard_iface *hard_iface); void (*disable)(struct batadv_hard_iface *hard_iface); void (*update_mac)(struct batadv_hard_iface *hard_iface); void (*primary_set)(struct batadv_hard_iface *hard_iface); @@ -1479,9 +1486,10 @@ struct batadv_algo_neigh_ops { */ struct batadv_algo_orig_ops { void (*free)(struct batadv_orig_node *orig_node); - int (*add_if)(struct batadv_orig_node *orig_node, int max_if_num); - int (*del_if)(struct batadv_orig_node *orig_node, int max_if_num, - int del_if_num); + int (*add_if)(struct batadv_orig_node *orig_node, + unsigned int max_if_num); + int (*del_if)(struct batadv_orig_node *orig_node, + unsigned int max_if_num, unsigned int del_if_num); #ifdef CONFIG_BATMAN_ADV_DEBUGFS void (*print)(struct batadv_priv *priv, struct seq_file *seq, struct batadv_hard_iface *hard_iface); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 5f3074cb6b4db67aad4491e99e291f073e1876c5..b6f26ec9e90cdaea9107ac11f8b6427c663b7cda 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -413,10 +413,8 @@ static int __rfcomm_create_dev(struct sock *sk, void __user *arg) dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel); if (IS_ERR(dlc)) return PTR_ERR(dlc); - else if (dlc) { - rfcomm_dlc_put(dlc); + if (dlc) return -EBUSY; - } dlc = rfcomm_dlc_alloc(GFP_KERNEL); if (!dlc) return -ENOMEM; diff --git a/net/core/dev.c b/net/core/dev.c index 9c533ee7fcf44b89a745f8bbe19802bf956397bd..e8d1af5f95007dedbaea62d0856078442492329a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3581,7 +3581,8 @@ EXPORT_SYMBOL(netdev_max_backlog); int netdev_tstamp_prequeue __read_mostly = 1; int netdev_budget __read_mostly = 300; -unsigned int __read_mostly netdev_budget_usecs = 2000; +/* Must be at least 2 jiffes to guarantee 1 jiffy timeout */ +unsigned int __read_mostly netdev_budget_usecs = 2 * USEC_PER_SEC / HZ; int weight_p __read_mostly = 64; /* old backlog weight */ int dev_weight_rx_bias __read_mostly = 1; /* bias for backlog weight */ int dev_weight_tx_bias __read_mostly = 1; /* bias for output_queue quota */ diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 9a6d97c1d8104eac629273337ca8999a86118533..9bb321df08698137897c2d8b5740a2e309d01522 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -799,7 +799,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, frh = nlmsg_data(nlh); frh->family = ops->family; - frh->table = rule->table; + frh->table = rule->table < 256 ? rule->table : RT_TABLE_COMPAT; if (nla_put_u32(skb, FRA_TABLE, rule->table)) goto nla_put_failure; if (nla_put_u32(skb, FRA_SUPPRESS_PREFIXLEN, rule->suppress_prefixlen)) diff --git a/net/core/filter.c b/net/core/filter.c index 715c56a742466dd389703685ba9b1471b4e255b8..b19fbab3395ad8a19847a30c81a5e363b9e74889 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3262,6 +3262,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) return &bpf_skb_adjust_room_proto; case BPF_FUNC_skb_change_tail: return &bpf_skb_change_tail_proto; + case BPF_FUNC_skb_change_head: + return &bpf_skb_change_head_proto; case BPF_FUNC_skb_get_tunnel_key: return &bpf_skb_get_tunnel_key_proto; case BPF_FUNC_skb_set_tunnel_key: diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 7bf83359861527564087e179760be87498cba600..668330ace961607c07ce98e9de0edf843c96b26e 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -57,30 +57,60 @@ static void cgrp_css_free(struct cgroup_subsys_state *css) kfree(css_cls_state(css)); } +/* + * To avoid freezing of sockets creation for tasks with big number of threads + * and opened sockets lets release file_lock every 1000 iterated descriptors. + * New sockets will already have been created with new classid. + */ + +struct update_classid_context { + u32 classid; + unsigned int batch; +}; + +#define UPDATE_CLASSID_BATCH 1000 + static int update_classid_sock(const void *v, struct file *file, unsigned n) { int err; + struct update_classid_context *ctx = (void *)v; struct socket *sock = sock_from_file(file, &err); if (sock) { spin_lock(&cgroup_sk_update_lock); - sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, - (unsigned long)v); + sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, ctx->classid); spin_unlock(&cgroup_sk_update_lock); } + if (--ctx->batch == 0) { + ctx->batch = UPDATE_CLASSID_BATCH; + return n + 1; + } return 0; } +static void update_classid_task(struct task_struct *p, u32 classid) +{ + struct update_classid_context ctx = { + .classid = classid, + .batch = UPDATE_CLASSID_BATCH + }; + unsigned int fd = 0; + + do { + task_lock(p); + fd = iterate_fd(p->files, fd, update_classid_sock, &ctx); + task_unlock(p); + cond_resched(); + } while (fd); +} + static void cgrp_attach(struct cgroup_taskset *tset) { struct cgroup_subsys_state *css; struct task_struct *p; cgroup_taskset_for_each(p, css, tset) { - task_lock(p); - iterate_fd(p->files, 0, update_classid_sock, - (void *)(unsigned long)css_cls_state(css)->classid); - task_unlock(p); + update_classid_task(p, css_cls_state(css)->classid); } } @@ -101,13 +131,8 @@ static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft, cs->classid = (u32)value; css_task_iter_start(css, 0, &it); - while ((p = css_task_iter_next(&it))) { - task_lock(p); - iterate_fd(p->files, 0, update_classid_sock, - (void *)(unsigned long)cs->classid); - task_unlock(p); - cond_resched(); - } + while ((p = css_task_iter_next(&it))) + update_classid_task(p, cs->classid); css_task_iter_end(&it); return 0; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 7c479c1ffd77ff1bc2827ef659f6f29e0183ee64..cb15338cfda4d25b0ed849fb7d88f3a6f9f2e354 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2424,7 +2424,7 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) } if (dev->rtnl_link_state == RTNL_LINK_INITIALIZED) { - __dev_notify_flags(dev, old_flags, 0U); + __dev_notify_flags(dev, old_flags, (old_flags ^ dev->flags)); } else { dev->rtnl_link_state = RTNL_LINK_INITIALIZED; __dev_notify_flags(dev, old_flags, ~0U); diff --git a/net/core/sock.c b/net/core/sock.c index 4e934404aeaf0edf7df2c3d79cdc05540f5c70b9..bed67e70ec1e936614b2fcfec8e0cdd908700740 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1684,7 +1684,10 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) atomic_set(&newsk->sk_zckey, 0); sock_reset_flag(newsk, SOCK_DONE); - mem_cgroup_sk_alloc(newsk); + + /* sk->sk_memcg will be populated at accept() time */ + newsk->sk_memcg = NULL; + cgroup_sk_alloc(&newsk->sk_cgrp_data); rcu_read_lock(); diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index 5f5d9eafccf5965b3deb23b2449a1392e07e6c61..ea133857f19eb16e70684b3e0d5d597638d8757e 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -242,7 +242,7 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m) * - the key's semaphore is read-locked */ static long dns_resolver_read(const struct key *key, - char __user *buffer, size_t buflen) + char *buffer, size_t buflen) { int err = PTR_ERR(key->payload.data[dns_key_error]); diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index de92fc1fc3be6d996e9e0ec0b16ba4a3cc89f959..b3b918afd2127c58edee244a3d83ef4cfa6951ea 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -134,6 +134,8 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, skb->dev = ds->ports[source_port].netdev; + skb->offload_fwd_mark = 1; + return skb; } diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index af3a12a36d882645ba929d4a28ee066e0d12df03..f268c5c3eedb6d55e028185a80f02afcb15a0596 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -41,7 +41,7 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) struct dsa_slave_priv *p = netdev_priv(dev); u16 *phdr, hdr; - if (skb_cow_head(skb, 0) < 0) + if (skb_cow_head(skb, QCA_HDR_LEN) < 0) return NULL; skb_push(skb, QCA_HDR_LEN); diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 6705420b3111f528a930f6410473beb47793cee7..d7206581145d54be739b80f0066a438849a83752 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -468,13 +468,9 @@ int hsr_get_node_data(struct hsr_priv *hsr, struct hsr_port *port; unsigned long tdiff; - - rcu_read_lock(); node = find_node_by_AddrA(&hsr->node_db, addr); - if (!node) { - rcu_read_unlock(); - return -ENOENT; /* No such entry */ - } + if (!node) + return -ENOENT; ether_addr_copy(addr_b, node->MacAddressB); @@ -509,7 +505,5 @@ int hsr_get_node_data(struct hsr_priv *hsr, *addr_b_ifindex = -1; } - rcu_read_unlock(); - return 0; } diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index b9cce0fd56966bbd8a16c8bc51555dfab467b6d0..606bc7fe5cc7c994de77d8ecd5a1ac5900954b9c 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -64,10 +64,16 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, else multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]); - if (!data[IFLA_HSR_VERSION]) + if (!data[IFLA_HSR_VERSION]) { hsr_version = 0; - else + } else { hsr_version = nla_get_u8(data[IFLA_HSR_VERSION]); + if (hsr_version > 1) { + NL_SET_ERR_MSG_MOD(extack, + "Only versions 0..1 are supported"); + return -EINVAL; + } + } return hsr_dev_finalize(dev, link, multicast_spec, hsr_version); } @@ -259,17 +265,16 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) if (!na) goto invalid; - hsr_dev = __dev_get_by_index(genl_info_net(info), - nla_get_u32(info->attrs[HSR_A_IFINDEX])); + rcu_read_lock(); + hsr_dev = dev_get_by_index_rcu(genl_info_net(info), + nla_get_u32(info->attrs[HSR_A_IFINDEX])); if (!hsr_dev) - goto invalid; + goto rcu_unlock; if (!is_hsr_master(hsr_dev)) - goto invalid; - + goto rcu_unlock; /* Send reply */ - - skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); if (!skb_out) { res = -ENOMEM; goto fail; @@ -321,12 +326,10 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); if (res < 0) goto nla_put_failure; - rcu_read_lock(); port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); if (port) res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, port->dev->ifindex); - rcu_read_unlock(); if (res < 0) goto nla_put_failure; @@ -336,20 +339,22 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); if (res < 0) goto nla_put_failure; - rcu_read_lock(); port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); if (port) res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, port->dev->ifindex); - rcu_read_unlock(); if (res < 0) goto nla_put_failure; + rcu_read_unlock(); + genlmsg_end(skb_out, msg_head); genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); return 0; +rcu_unlock: + rcu_read_unlock(); invalid: netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL); return 0; @@ -359,6 +364,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) /* Fall through */ fail: + rcu_read_unlock(); return res; } @@ -366,16 +372,14 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) */ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) { - /* For receiving */ - struct nlattr *na; + unsigned char addr[ETH_ALEN]; struct net_device *hsr_dev; - - /* For sending */ struct sk_buff *skb_out; - void *msg_head; struct hsr_priv *hsr; - void *pos; - unsigned char addr[ETH_ALEN]; + bool restart = false; + struct nlattr *na; + void *pos = NULL; + void *msg_head; int res; if (!info) @@ -385,17 +389,17 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) if (!na) goto invalid; - hsr_dev = __dev_get_by_index(genl_info_net(info), - nla_get_u32(info->attrs[HSR_A_IFINDEX])); + rcu_read_lock(); + hsr_dev = dev_get_by_index_rcu(genl_info_net(info), + nla_get_u32(info->attrs[HSR_A_IFINDEX])); if (!hsr_dev) - goto invalid; + goto rcu_unlock; if (!is_hsr_master(hsr_dev)) - goto invalid; - + goto rcu_unlock; +restart: /* Send reply */ - - skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb_out) { res = -ENOMEM; goto fail; @@ -409,18 +413,26 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) goto nla_put_failure; } - res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); - if (res < 0) - goto nla_put_failure; + if (!restart) { + res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); + if (res < 0) + goto nla_put_failure; + } hsr = netdev_priv(hsr_dev); - rcu_read_lock(); - pos = hsr_get_next_node(hsr, NULL, addr); + if (!pos) + pos = hsr_get_next_node(hsr, NULL, addr); while (pos) { res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); if (res < 0) { - rcu_read_unlock(); + if (res == -EMSGSIZE) { + genlmsg_end(skb_out, msg_head); + genlmsg_unicast(genl_info_net(info), skb_out, + info->snd_portid); + restart = true; + goto restart; + } goto nla_put_failure; } pos = hsr_get_next_node(hsr, pos, addr); @@ -432,15 +444,18 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) return 0; +rcu_unlock: + rcu_read_unlock(); invalid: netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL); return 0; nla_put_failure: - kfree_skb(skb_out); + nlmsg_free(skb_out); /* Fall through */ fail: + rcu_read_unlock(); return res; } @@ -467,6 +482,7 @@ static struct genl_family hsr_genl_family __ro_after_init = { .name = "HSR", .version = 1, .maxattr = HSR_A_MAX, + .netnsok = true, .module = THIS_MODULE, .ops = hsr_ops, .n_ops = ARRAY_SIZE(hsr_ops), diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index 56080da4aa77ef581f4a3c23b4179d72e511980b..b215df0bce0e01eaaae6746fdedf40e6d648f339 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -32,6 +32,8 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) rcu_read_lock(); /* hsr->node_db, hsr->ports */ port = hsr_port_get_rcu(skb->dev); + if (!port) + goto finish_pass; if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) { /* Directly kill frames sent by ourselves */ @@ -150,16 +152,16 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, if (port == NULL) return -ENOMEM; + port->hsr = hsr; + port->dev = dev; + port->type = type; + if (type != HSR_PT_MASTER) { res = hsr_portdev_setup(dev, port); if (res) goto fail_dev_setup; } - port->hsr = hsr; - port->dev = dev; - port->type = type; - list_add_tail_rcu(&port->port_list, &hsr->ports); synchronize_rcu(); diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index 35c4326684548d88f408f84ded46ce6ac2d04ebc..040983fc15da37583fb5822df3cad04e3884948d 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c @@ -30,7 +30,13 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, }, [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, }, [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, }, + [IEEE802154_ATTR_BCN_ORD] = { .type = NLA_U8, }, + [IEEE802154_ATTR_SF_ORD] = { .type = NLA_U8, }, + [IEEE802154_ATTR_PAN_COORD] = { .type = NLA_U8, }, + [IEEE802154_ATTR_BAT_EXT] = { .type = NLA_U8, }, + [IEEE802154_ATTR_COORD_REALIGN] = { .type = NLA_U8, }, [IEEE802154_ATTR_PAGE] = { .type = NLA_U8, }, + [IEEE802154_ATTR_DEV_TYPE] = { .type = NLA_U8, }, [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, }, [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, }, [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, }, diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index f48fe6fc7e8c413d7d7e4d7d37d1d859a566e8fb..4abc4ba733bf0312cc95b4dfbcd6756d6f06dcab 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -297,6 +297,7 @@ config SYN_COOKIES config NET_IPVTI tristate "Virtual (secure) IP: tunneling" + depends on IPV6 || IPV6=n select INET_TUNNEL select NET_IP_TUNNEL depends on INET_XFRM_MODE_TUNNEL diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index f0165c5f376b398950db7696e813c94b19034068..1c21dc5d6dd4049c47f947ac727516500d534ff2 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1738,6 +1738,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) { unsigned char optbuf[sizeof(struct ip_options) + 40]; struct ip_options *opt = (struct ip_options *)optbuf; + int res; if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES) return; @@ -1749,7 +1750,11 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) memset(opt, 0, sizeof(struct ip_options)); opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr); - if (__ip_options_compile(dev_net(skb->dev), opt, skb, NULL)) + rcu_read_lock(); + res = __ip_options_compile(dev_net(skb->dev), opt, skb, NULL); + rcu_read_unlock(); + + if (res) return; if (gateway) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 9a849d7eb55d0f1599f499e01171bbc510a9d9af..7d9165beca8ac32c289ff84c73ba46583dab2fbe 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -579,12 +579,15 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, return NULL; } -static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa) +static int ip_mc_autojoin_config(struct net *net, bool join, + const struct in_ifaddr *ifa) { +#if defined(CONFIG_IP_MULTICAST) struct ip_mreqn mreq = { .imr_multiaddr.s_addr = ifa->ifa_address, .imr_ifindex = ifa->ifa_dev->dev->ifindex, }; + struct sock *sk = net->ipv4.mc_autojoin_sk; int ret; ASSERT_RTNL(); @@ -597,6 +600,9 @@ static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa) release_sock(sk); return ret; +#else + return -EOPNOTSUPP; +#endif } static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -638,7 +644,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, continue; if (ipv4_is_multicast(ifa->ifa_address)) - ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa); + ip_mc_autojoin_config(net, false, ifa); __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid); return 0; } @@ -896,8 +902,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, */ set_ifa_lifetime(ifa, valid_lft, prefered_lft); if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) { - int ret = ip_mc_config(net->ipv4.mc_autojoin_sk, - true, ifa); + int ret = ip_mc_autojoin_config(net, true, ifa); if (ret < 0) { inet_free_ifa(ifa); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index bb847d2807786a9e23c406fddd8c2cbf23636d75..3f9509679f0e1f439d6968ede8c633b39a8ec389 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2319,6 +2319,7 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v) " %zd bytes, size of tnode: %zd bytes.\n", LEAF_SIZE, TNODE_SIZE(0)); + rcu_read_lock(); for (h = 0; h < FIB_TABLE_HASHSZ; h++) { struct hlist_head *head = &net->ipv4.fib_table_hash[h]; struct fib_table *tb; @@ -2338,7 +2339,9 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v) trie_show_usage(seq, t->stats); #endif } + cond_resched_rcu(); } + rcu_read_unlock(); return 0; } diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index 7efe740c06ebff66d5e50f1cc067bc5973fc58e3..4a5e55e94a9e56546729c41fcdeae10d69186dcb 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c @@ -60,7 +60,9 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version) } EXPORT_SYMBOL_GPL(gre_del_protocol); -/* Fills in tpi and returns header length to be pulled. */ +/* Fills in tpi and returns header length to be pulled. + * Note that caller must use pskb_may_pull() before pulling GRE header. + */ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, bool *csum_err, __be16 proto, int nhs) { @@ -114,8 +116,14 @@ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header */ if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { + u8 _val, *val; + + val = skb_header_pointer(skb, nhs + hdr_len, + sizeof(_val), &_val); + if (!val) + return -EINVAL; tpi->proto = proto; - if ((*(u8 *)options & 0xF0) != 0x40) + if ((*val & 0xF0) != 0x40) hdr_len += 4; } tpi->hdr_len = hdr_len; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 45b00b76c430dffaa27c248606bfbf8902c43d4a..a403001c50af20e95b5ef88afd585525d777b9d5 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -482,8 +482,28 @@ struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern) } spin_unlock_bh(&queue->fastopenq.lock); } + out: release_sock(sk); + if (newsk && mem_cgroup_sockets_enabled) { + int amt; + + /* atomically get the memory usage, set and charge the + * newsk->sk_memcg. + */ + lock_sock(newsk); + + /* The socket has not been accepted yet, no need to look at + * newsk->sk_wmem_queued. + */ + amt = sk_mem_pages(newsk->sk_forward_alloc + + atomic_read(&newsk->sk_rmem_alloc)); + mem_cgroup_sk_alloc(newsk); + if (newsk->sk_memcg && amt) + mem_cgroup_charge_skmem(newsk->sk_memcg, amt); + + release_sock(newsk); + } if (req) reqsk_put(req); return newsk; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index eb158badebc43ece6b804d1aaa7a48ec2dad1c80..7ba013d6c00aff5b63c235006b93957801fd6532 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -105,13 +105,9 @@ static size_t inet_sk_attr_size(struct sock *sk, aux = handler->idiag_get_aux_size(sk, net_admin); return nla_total_size(sizeof(struct tcp_info)) - + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ - + nla_total_size(1) /* INET_DIAG_TOS */ - + nla_total_size(1) /* INET_DIAG_TCLASS */ - + nla_total_size(4) /* INET_DIAG_MARK */ - + nla_total_size(4) /* INET_DIAG_CLASS_ID */ - + nla_total_size(sizeof(struct inet_diag_meminfo)) + nla_total_size(sizeof(struct inet_diag_msg)) + + inet_diag_msg_attrs_size() + + nla_total_size(sizeof(struct inet_diag_meminfo)) + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) + nla_total_size(TCP_CA_NAME_MAX) + nla_total_size(sizeof(struct tcpvegas_info)) @@ -152,6 +148,24 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark)) goto errout; + if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) || + ext & (1 << (INET_DIAG_TCLASS - 1))) { + u32 classid = 0; + +#ifdef CONFIG_SOCK_CGROUP_DATA + classid = sock_cgroup_classid(&sk->sk_cgrp_data); +#endif + /* Fallback to socket priority if class id isn't set. + * Classful qdiscs use it as direct reference to class. + * For cgroup2 classid is always zero. + */ + if (!classid) + classid = sk->sk_priority; + + if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid)) + goto errout; + } + r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); r->idiag_inode = sock_i_ino(sk); @@ -289,24 +303,6 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, goto errout; } - if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) || - ext & (1 << (INET_DIAG_TCLASS - 1))) { - u32 classid = 0; - -#ifdef CONFIG_SOCK_CGROUP_DATA - classid = sock_cgroup_classid(&sk->sk_cgrp_data); -#endif - /* Fallback to socket priority if class id isn't set. - * Classful qdiscs use it as direct reference to class. - * For cgroup2 classid is always zero. - */ - if (!classid) - classid = sk->sk_priority; - - if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid)) - goto errout; - } - out: nlmsg_end(skb, nlh); return 0; diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 404dc765f2bf82186ea81783d4829f15856619e0..f6793017a20d95f6af3c889256008459d50342b7 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -155,11 +155,8 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, cand = t; } - if (flags & TUNNEL_NO_KEY) - goto skip_key_lookup; - hlist_for_each_entry_rcu(t, head, hash_node) { - if (t->parms.i_key != key || + if ((!(flags & TUNNEL_NO_KEY) && t->parms.i_key != key) || t->parms.iph.saddr != 0 || t->parms.iph.daddr != 0 || !(t->dev->flags & IFF_UP)) @@ -171,7 +168,6 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, cand = t; } -skip_key_lookup: if (cand) return cand; diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 59384ffe89f730acf5cd32dfc1202af79be70d19..c1693d75e19687f47c9c5cef79fb44fb6b5fb94c 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -208,17 +208,39 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, int mtu; if (!dst) { - struct rtable *rt; - - fl->u.ip4.flowi4_oif = dev->ifindex; - fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC; - rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4); - if (IS_ERR(rt)) { + switch (skb->protocol) { + case htons(ETH_P_IP): { + struct rtable *rt; + + fl->u.ip4.flowi4_oif = dev->ifindex; + fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC; + rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4); + if (IS_ERR(rt)) { + dev->stats.tx_carrier_errors++; + goto tx_error_icmp; + } + dst = &rt->dst; + skb_dst_set(skb, dst); + break; + } +#if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): + fl->u.ip6.flowi6_oif = dev->ifindex; + fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC; + dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6); + if (dst->error) { + dst_release(dst); + dst = NULL; + dev->stats.tx_carrier_errors++; + goto tx_error_icmp; + } + skb_dst_set(skb, dst); + break; +#endif + default: dev->stats.tx_carrier_errors++; goto tx_error_icmp; } - dst = &rt->dst; - skb_dst_set(skb, dst); } dst_hold(dst); @@ -659,10 +681,8 @@ static int __init vti_init(void) msg = "ipip tunnel"; err = xfrm4_tunnel_register(&ipip_handler, AF_INET); - if (err < 0) { - pr_info("%s: cant't register tunnel\n",__func__); + if (err < 0) goto xfrm_tunnel_failed; - } msg = "netlink interface"; err = rtnl_link_register(&vti_link_ops); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 53a11894f9e4e93de80772bca442163d2200b47e..261a9813b88cd1171d0017b0b9bd96637df289a7 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -520,9 +520,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) goto out; /* hdrincl should be READ_ONCE(inet->hdrincl) - * but READ_ONCE() doesn't work with bit fields + * but READ_ONCE() doesn't work with bit fields. + * Doing this indirectly yields the same result. */ hdrincl = inet->hdrincl; + hdrincl = READ_ONCE(hdrincl); /* * Check the flags. */ diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index 6367ecdf76c42ff85ff102a4eb4e5a1e81af1953..1d84b02ec76589897b83eb8b108ea2080df90565 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -99,8 +99,9 @@ static int raw_diag_dump_one(struct sk_buff *in_skb, if (IS_ERR(sk)) return PTR_ERR(sk); - rep = nlmsg_new(sizeof(struct inet_diag_msg) + - sizeof(struct inet_diag_meminfo) + 64, + rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) + + inet_diag_msg_attrs_size() + + nla_total_size(sizeof(struct inet_diag_meminfo)) + 64, GFP_KERNEL); if (!rep) { sock_put(sk); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8b855d3eec9e7562658bce1bfb5a3e34af62ceb6..3c298ec3220027efbfeadd2fc63301ea75df634d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -133,8 +133,6 @@ static int ip_rt_min_advmss __read_mostly = 256; static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; -static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; - /* * Interface to generic destination cache. */ @@ -1014,21 +1012,22 @@ out: kfree_skb(skb); static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) { struct dst_entry *dst = &rt->dst; + u32 old_mtu = ipv4_mtu(dst); struct fib_result res; bool lock = false; if (ip_mtu_locked(dst)) return; - if (ipv4_mtu(dst) < mtu) + if (old_mtu < mtu) return; if (mtu < ip_rt_min_pmtu) { lock = true; - mtu = ip_rt_min_pmtu; + mtu = min(old_mtu, ip_rt_min_pmtu); } - if (rt->rt_pmtu == mtu && + if (rt->rt_pmtu == mtu && !lock && time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) return; @@ -2868,6 +2867,7 @@ void ip_rt_multicast_event(struct in_device *in_dev) static int ip_rt_gc_interval __read_mostly = 60 * HZ; static int ip_rt_gc_min_interval __read_mostly = HZ / 2; static int ip_rt_gc_elasticity __read_mostly = 8; +static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write, void __user *buffer, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 254e3c79b09d8c88d84c1db6a33df95f44d63957..a74298964f4dc6c971105704e40e51b038cf606b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2371,9 +2371,11 @@ int tcp_disconnect(struct sock *sk, int flags) tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_cnt = 0; tp->window_clamp = 0; + tp->delivered = 0; tcp_set_ca_state(sk, TCP_CA_Open); tp->is_sack_reneg = 0; tcp_clear_retrans(tp); + tp->total_retrans = 0; inet_csk_delack_init(sk); /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0 * issue in __tcp_select_window() @@ -2385,8 +2387,12 @@ int tcp_disconnect(struct sock *sk, int flags) dst_release(sk->sk_rx_dst); sk->sk_rx_dst = NULL; tcp_saved_syn_free(tp); + tp->segs_in = 0; + tp->segs_out = 0; tp->bytes_acked = 0; tp->bytes_received = 0; + tp->data_segs_in = 0; + tp->data_segs_out = 0; /* Clean up fastopen related fields */ tcp_free_fastopen_req(tp); diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index d9ad986c7b2c9e073616c63d6d5ab376d2b72d5f..cc3f6da306c6110d9dbf1eac0e5c9874fa58929e 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -67,8 +67,9 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, goto out; err = -ENOMEM; - rep = nlmsg_new(sizeof(struct inet_diag_msg) + - sizeof(struct inet_diag_meminfo) + 64, + rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) + + inet_diag_msg_attrs_size() + + nla_total_size(sizeof(struct inet_diag_meminfo)) + 64, GFP_KERNEL); if (!rep) goto out; diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 94b8702603bc54f36542977ed0d9c3b93d43b6b7..35dbc8eb93964ce56afc320135be87ce336a26c3 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -76,9 +76,7 @@ int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) { memset(IPCB(skb), 0, sizeof(*IPCB(skb))); -#ifdef CONFIG_NETFILTER IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; -#endif return xfrm_output(sk, skb); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0203283272dc1df7e5e7e613652da128dbb53e13..bd7b97ec193ca651b14fd1f3fde04d9a0c08bebc 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3217,6 +3217,10 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) if (netif_is_l3_master(idev->dev)) return; + /* no link local addresses on devices flagged as slaves */ + if (idev->dev->flags & IFF_SLAVE) + return; + ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); switch (idev->cnf.addr_gen_mode) { @@ -3266,6 +3270,10 @@ static void addrconf_dev_config(struct net_device *dev) (dev->type != ARPHRD_NONE) && (dev->type != ARPHRD_RAWIP)) { /* Alas, we support only Ethernet autoconfiguration. */ + idev = __in6_dev_get(dev); + if (!IS_ERR_OR_NULL(idev) && dev->flags & IFF_UP && + dev->flags & IFF_MULTICAST) + ipv6_mc_up(idev); return; } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index e5308d7cbd75c4fb67861082382122d445cf5b74..d43abeb1e4150ffd760fbe6766fdbe11b9b9d266 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -893,8 +893,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, found++; break; } - if (rt_can_ecmp) - fallback_ins = fallback_ins ?: ins; + fallback_ins = fallback_ins ?: ins; goto next_iter; } @@ -934,7 +933,9 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, } if (fallback_ins && !found) { - /* No ECMP-able route found, replace first non-ECMP one */ + /* No matching route with same ecmp-able-ness found, replace + * first matching route + */ ins = fallback_ins; iter = *ins; found++; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 396a0f61f5f88a4aa2ee3b30c1e69ab6b9642e4e..207bf342e99560e7c9dab8ccc085defea3862c39 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -315,7 +315,7 @@ static int vti6_rcv(struct sk_buff *skb) if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { rcu_read_unlock(); - return 0; + goto discard; } ipv6h = ipv6_hdr(skb); @@ -454,15 +454,33 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) int mtu; if (!dst) { - fl->u.ip6.flowi6_oif = dev->ifindex; - fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC; - dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6); - if (dst->error) { - dst_release(dst); - dst = NULL; + switch (skb->protocol) { + case htons(ETH_P_IP): { + struct rtable *rt; + + fl->u.ip4.flowi4_oif = dev->ifindex; + fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC; + rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4); + if (IS_ERR(rt)) + goto tx_err_link_failure; + dst = &rt->dst; + skb_dst_set(skb, dst); + break; + } + case htons(ETH_P_IPV6): + fl->u.ip6.flowi6_oif = dev->ifindex; + fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC; + dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6); + if (dst->error) { + dst_release(dst); + dst = NULL; + goto tx_err_link_failure; + } + skb_dst_set(skb, dst); + break; + default: goto tx_err_link_failure; } - skb_dst_set(skb, dst); } dst_hold(dst); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 5c91b05c8d8feb3207741a4d9b821df7e5a24cc6..337b43d4c3eb81f71e10d3a24f4314c48a3664f1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -185,9 +185,14 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, retv = -EBUSY; break; } - } else if (sk->sk_protocol != IPPROTO_TCP) + } + if (sk->sk_protocol == IPPROTO_TCP && + sk->sk_prot != &tcpv6_prot) { + retv = -EBUSY; + break; + } + if (sk->sk_protocol != IPPROTO_TCP) break; - if (sk->sk_state != TCP_ESTABLISHED) { retv = -ENOTCONN; break; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f98c37a7d5bf7d35ca496aacbfd479cd9af610a1..4eee004a278887f7fecde73ad5c183a93d3f48c8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3255,6 +3255,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, */ cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL | NLM_F_REPLACE); + cfg->fc_nlinfo.nlh->nlmsg_flags |= NLM_F_CREATE; nhn++; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 349e83d182300ce86a7ca965186dfa2296765847..e2cbb6286adf92177467ff7f1bca7a6662a1c3fa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -718,7 +718,6 @@ static void tcp_v6_init_req(struct request_sock *req, const struct sock *sk_listener, struct sk_buff *skb) { - bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); struct inet_request_sock *ireq = inet_rsk(req); const struct ipv6_pinfo *np = inet6_sk(sk_listener); @@ -726,7 +725,7 @@ static void tcp_v6_init_req(struct request_sock *req, ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; /* So that link locals have meaning */ - if ((!sk_listener->sk_bound_dev_if || l3_slave) && + if (!sk_listener->sk_bound_dev_if && ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) ireq->ir_iif = tcp_v6_iif(skb); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 29dae7f2ff14d7bd5c5932b752e72da02b5537ac..aff901be53539a750b54eafc8be34cecf81bc558 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -130,9 +130,7 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) { memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); -#ifdef CONFIG_NETFILTER IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; -#endif return xfrm_output(sk, skb); } diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 6fe90ec21300197ed341a327c34f7f749b5e7e14..d169511ea7e6951262f48e2005a952eb80cfeadf 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -358,8 +358,13 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, spin_lock_bh(&pn->l2tp_session_hlist_lock); + /* IP encap expects session IDs to be globally unique, while + * UDP encap doesn't. + */ hlist_for_each_entry(session_walk, g_head, global_hlist) - if (session_walk->session_id == session->session_id) { + if (session_walk->session_id == session->session_id && + (session_walk->tunnel->encap == L2TP_ENCAPTYPE_IP || + tunnel->encap == L2TP_ENCAPTYPE_IP)) { err = -EEXIST; goto err_tlock_pnlock; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 994dde6e5f9d91df43624915d85d143b8b623de1..986e9b6b961d206caa6dc68dc1d5cbb0c3dcd93e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1137,7 +1137,8 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata, } } - if (!(mpath->flags & MESH_PATH_RESOLVING)) + if (!(mpath->flags & MESH_PATH_RESOLVING) && + mesh_path_sel_is_hwmp(sdata)) mesh_queue_preq(mpath, PREQ_Q_F_START); if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 36bd59ff49c4395281d231459347aa6e62d98f1e..ab26b8b954719652b4af392ae81bb66a533c048c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2273,7 +2273,7 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, if (!ieee80211_is_data(hdr->frame_control)) return; - if (ieee80211_is_nullfunc(hdr->frame_control) && + if (ieee80211_is_any_nullfunc(hdr->frame_control) && sdata->u.mgd.probe_send_count > 0) { if (ack) ieee80211_sta_reset_conn_monitor(sdata); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 31000622376dfe72f2a2ad73342d4d9337f04f84..f44dd79081222a2f807de0213c6e328cd864daae 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1255,8 +1255,7 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (ieee80211_is_ctl(hdr->frame_control) || - ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control) || + ieee80211_is_any_nullfunc(hdr->frame_control) || is_multicast_ether_addr(hdr->addr1)) return RX_CONTINUE; @@ -1643,8 +1642,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) * Drop (qos-)data::nullfunc frames silently, since they * are used only to control station power saving mode. */ - if (ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) { + if (ieee80211_is_any_nullfunc(hdr->frame_control)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); /* @@ -2134,7 +2132,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) /* Drop unencrypted frames if key is set. */ if (unlikely(!ieee80211_has_protected(fc) && - !ieee80211_is_nullfunc(fc) && + !ieee80211_is_any_nullfunc(fc) && ieee80211_is_data(fc) && rx->key)) return -EACCES; @@ -2206,7 +2204,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) if (!sdata->u.mgd.use_4addr) return -1; - else + else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr)) check_port_control = true; } @@ -3862,7 +3860,7 @@ void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->sta_mtx); - list_for_each_entry_rcu(sta, &local->sta_list, list) { + list_for_each_entry(sta, &local->sta_list, list) { if (sdata != sta->sdata && (!sta->sdata->bss || sta->sdata->bss != sdata->bss)) continue; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 627dc642f894ee188c0bd14e6cd9746fa9aaa714..77ab9cc1a230a133df254d14145462b7f024c05f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -3,6 +3,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018-2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -951,6 +952,11 @@ static void __sta_info_destroy_part2(struct sta_info *sta) might_sleep(); lockdep_assert_held(&local->sta_mtx); + while (sta->sta_state == IEEE80211_STA_AUTHORIZED) { + ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); + WARN_ON_ONCE(ret); + } + /* now keys can no longer be reached */ ieee80211_free_sta_keys(local, sta); diff --git a/net/mac80211/status.c b/net/mac80211/status.c index fbe7354aeac7b4750dd7047ec3330d757e5c8d9e..fcfa6714e4924b960234d08eb537200abd2902b9 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -478,8 +478,7 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, rcu_read_lock(); sdata = ieee80211_sdata_from_skb(local, skb); if (sdata) { - if (ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) + if (ieee80211_is_any_nullfunc(hdr->frame_control)) cfg80211_probe_status(sdata->dev, hdr->addr1, cookie, acked, GFP_ATOMIC); @@ -856,7 +855,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, I802_DEBUG_INC(local->dot11FailedCount); } - if ((ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) && + if (ieee80211_is_any_nullfunc(fc) && ieee80211_has_pm(fc) && ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) && !(info->flags & IEEE80211_TX_CTL_INJECTED) && diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 09c7aa519ca82fc17e2261fbf544a9e8f7fb595f..1b1f2d6cb3f4b6fab89676c1b6fa2ec73397e637 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -296,7 +296,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) && !ieee80211_is_probe_req(hdr->frame_control) && - !ieee80211_is_nullfunc(hdr->frame_control)) + !ieee80211_is_any_nullfunc(hdr->frame_control)) /* * When software scanning only nullfunc frames (to notify * the sleep state to the AP) and probe requests (for the @@ -3451,8 +3451,26 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, tx.skb = skb; tx.sdata = vif_to_sdata(info->control.vif); - if (txq->sta) + if (txq->sta) { tx.sta = container_of(txq->sta, struct sta_info, sta); + /* + * Drop unicast frames to unauthorised stations unless they are + * EAPOL frames from the local station. + */ + if (unlikely(ieee80211_is_data(hdr->frame_control) && + !ieee80211_vif_is_mesh(&tx.sdata->vif) && + tx.sdata->vif.type != NL80211_IFTYPE_OCB && + !is_multicast_ether_addr(hdr->addr1) && + !test_sta_flag(tx.sta, WLAN_STA_AUTHORIZED) && + (!(info->control.flags & + IEEE80211_TX_CTRL_PORT_CTRL_PROTO) || + !ether_addr_equal(tx.sdata->vif.addr, + hdr->addr2)))) { + I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); + ieee80211_free_txskb(&local->hw, skb); + goto begin; + } + } /* * The key can be removed while the packet was queued, so need to call diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 81f120466c38b9971a1cf7b02ae4596dfa4ac40e..cd3cdd1a0b57695607ad206cf715d4c004aabd42 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -944,16 +944,22 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, elem_parse_failed = true; break; case WLAN_EID_VHT_OPERATION: - if (elen >= sizeof(struct ieee80211_vht_operation)) + if (elen >= sizeof(struct ieee80211_vht_operation)) { elems->vht_operation = (void *)pos; - else - elem_parse_failed = true; + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + break; + } + elem_parse_failed = true; break; case WLAN_EID_OPMODE_NOTIF: - if (elen > 0) + if (elen > 0) { elems->opmode_notif = pos; - else - elem_parse_failed = true; + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + break; + } + elem_parse_failed = true; break; case WLAN_EID_MESH_ID: elems->mesh_id = pos; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3a7d909a7f544ade465349ae2be19208aa12b1ed..f951c83559aded7fc54bd4368b5ca838cf081388 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -579,6 +579,18 @@ nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, net_eq(net, nf_ct_net(ct)); } +static inline bool +nf_ct_match(const struct nf_conn *ct1, const struct nf_conn *ct2) +{ + return nf_ct_tuple_equal(&ct1->tuplehash[IP_CT_DIR_ORIGINAL].tuple, + &ct2->tuplehash[IP_CT_DIR_ORIGINAL].tuple) && + nf_ct_tuple_equal(&ct1->tuplehash[IP_CT_DIR_REPLY].tuple, + &ct2->tuplehash[IP_CT_DIR_REPLY].tuple) && + nf_ct_zone_equal(ct1, nf_ct_zone(ct2), IP_CT_DIR_ORIGINAL) && + nf_ct_zone_equal(ct1, nf_ct_zone(ct2), IP_CT_DIR_REPLY) && + net_eq(nf_ct_net(ct1), nf_ct_net(ct2)); +} + /* caller must hold rcu readlock and none of the nf_conntrack_locks */ static void nf_ct_gc_expired(struct nf_conn *ct) { @@ -772,19 +784,21 @@ static int nf_ct_resolve_clash(struct net *net, struct sk_buff *skb, /* This is the conntrack entry already in hashes that won race. */ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); const struct nf_conntrack_l4proto *l4proto; + enum ip_conntrack_info oldinfo; + struct nf_conn *loser_ct = nf_ct_get(skb, &oldinfo); l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto->allow_clash && - ((ct->status & IPS_NAT_DONE_MASK) == 0) && !nf_ct_is_dying(ct) && atomic_inc_not_zero(&ct->ct_general.use)) { - enum ip_conntrack_info oldinfo; - struct nf_conn *loser_ct = nf_ct_get(skb, &oldinfo); - - nf_ct_acct_merge(ct, ctinfo, loser_ct); - nf_conntrack_put(&loser_ct->ct_general); - nf_ct_set(skb, ct, oldinfo); - return NF_ACCEPT; + if (((ct->status & IPS_NAT_DONE_MASK) == 0) || + nf_ct_match(ct, loser_ct)) { + nf_ct_acct_merge(ct, ctinfo, loser_ct); + nf_conntrack_put(&loser_ct->ct_general); + nf_ct_set(skb, ct, oldinfo); + return NF_ACCEPT; + } + nf_ct_put(ct); } NF_CT_STAT_INC(net, drop); return NF_DROP; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 91490446ebb42ea9d70d91dd0a5ec1c9b8e02d81..5b8d5bfeb7ac5338aec36193d0a76756dc8167b0 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3129,7 +3129,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, NFT_SET_INTERVAL | NFT_SET_TIMEOUT | NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT)) - return -EINVAL; + return -EOPNOTSUPP; /* Only one of these operations is supported */ if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) == (NFT_SET_MAP | NFT_SET_OBJECT)) @@ -3167,7 +3167,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, objtype = ntohl(nla_get_be32(nla[NFTA_SET_OBJ_TYPE])); if (objtype == NFT_OBJECT_UNSPEC || objtype > NFT_OBJECT_MAX) - return -EINVAL; + return -EOPNOTSUPP; } else if (flags & NFT_SET_OBJECT) return -EINVAL; else diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index d33ce6d5ebce92db2fab30cb4286c11ffd8c321a..dd1030f5dd5e290e88313895f882788272317e22 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -733,6 +733,8 @@ static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = { [NFCTH_NAME] = { .type = NLA_NUL_STRING, .len = NF_CT_HELPER_NAME_LEN-1 }, [NFCTH_QUEUE_NUM] = { .type = NLA_U32, }, + [NFCTH_PRIV_DATA_LEN] = { .type = NLA_U32, }, + [NFCTH_STATUS] = { .type = NLA_U32, }, }; static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = { diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c index ce13a50b91893fd67a9c8586f7cca53278b1067d..ee190fa4dc34700db740fc81a070ea1ea309c40c 100644 --- a/net/netfilter/nft_fwd_netdev.c +++ b/net/netfilter/nft_fwd_netdev.c @@ -62,6 +62,13 @@ static int nft_fwd_netdev_dump(struct sk_buff *skb, const struct nft_expr *expr) return -1; } +static int nft_fwd_validate(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nft_data **data) +{ + return nft_chain_validate_hooks(ctx->chain, (1 << NF_NETDEV_INGRESS)); +} + static struct nft_expr_type nft_fwd_netdev_type; static const struct nft_expr_ops nft_fwd_netdev_ops = { .type = &nft_fwd_netdev_type, @@ -69,6 +76,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = { .eval = nft_fwd_netdev_eval, .init = nft_fwd_netdev_init, .dump = nft_fwd_netdev_dump, + .validate = nft_fwd_validate, }; static struct nft_expr_type nft_fwd_netdev_type __read_mostly = { diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c index e110b0ebbf58b02b5b4ae8e9b8f9ad804ac861ba..19446a89a2a8158317c011fb662e406c4adafa91 100644 --- a/net/netfilter/nft_payload.c +++ b/net/netfilter/nft_payload.c @@ -121,6 +121,7 @@ static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = { [NFTA_PAYLOAD_LEN] = { .type = NLA_U32 }, [NFTA_PAYLOAD_CSUM_TYPE] = { .type = NLA_U32 }, [NFTA_PAYLOAD_CSUM_OFFSET] = { .type = NLA_U32 }, + [NFTA_PAYLOAD_CSUM_FLAGS] = { .type = NLA_U32 }, }; static int nft_payload_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index fe8e8a1622b59f3986a1cc65ba569a521b09f762..186f97f1c6c01fa57b0174c9d62d177d756b2fb2 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -845,6 +845,8 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) return hashlimit_mt_common(skb, par, hinfo, &info->cfg, 3); } +#define HASHLIMIT_MAX_SIZE 1048576 + static int hashlimit_mt_check_common(const struct xt_mtchk_param *par, struct xt_hashlimit_htable **hinfo, struct hashlimit_cfg3 *cfg, @@ -855,6 +857,14 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par, if (cfg->gc_interval == 0 || cfg->expire == 0) return -EINVAL; + if (cfg->size > HASHLIMIT_MAX_SIZE) { + cfg->size = HASHLIMIT_MAX_SIZE; + pr_info_ratelimited("size too large, truncated to %u\n", cfg->size); + } + if (cfg->max > HASHLIMIT_MAX_SIZE) { + cfg->max = HASHLIMIT_MAX_SIZE; + pr_info_ratelimited("max too large, truncated to %u\n", cfg->max); + } if (par->family == NFPROTO_IPV4) { if (cfg->srcmask > 32 || cfg->dstmask > 32) return -EINVAL; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c67abda5d6391b3a208ab949913a8d2b9df9fc30..3e4e07559272286b0c74b21a9524728dd6ff8fe2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -997,7 +997,8 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, if (nlk->netlink_bind && groups) { int group; - for (group = 0; group < nlk->ngroups; group++) { + /* nl_groups is a u32, so cap the maximum groups we can bind */ + for (group = 0; group < BITS_PER_TYPE(u32); group++) { if (!test_bit(group, &groups)) continue; err = nlk->netlink_bind(net, group + 1); @@ -1016,7 +1017,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, netlink_insert(sk, nladdr->nl_pid) : netlink_autobind(sock); if (err) { - netlink_undo_bind(nlk->ngroups, groups, sk); + netlink_undo_bind(BITS_PER_TYPE(u32), groups, sk); goto unlock; } } @@ -2388,7 +2389,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err, in_skb->len)) WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS, (u8 *)extack->bad_attr - - in_skb->data)); + (u8 *)nlh)); } else { if (extack->cookie_len) WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE, diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index 0c59354e280ed1fa5fc5e78c6ac0dd53d4fb5d70..d098bb8d53aa404ba5fbe9cae03d43d43a469451 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -199,6 +199,7 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic, /* refcount initialized at 1 */ spin_unlock_bh(&nr_node_list_lock); + nr_neigh_put(nr_neigh); return 0; } nr_node_lock(nr_node); diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 6bf14f4f4b428e8283d19460331a7b9f26334b72..ae315dbd37322685d31a6e1e2772b6a656af1bc0 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -193,13 +193,20 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, struct sk_buff *skb) { - u8 gate = hdev->pipes[pipe].gate; u8 status = NFC_HCI_ANY_OK; struct hci_create_pipe_resp *create_info; struct hci_delete_pipe_noti *delete_info; struct hci_all_pipe_cleared_noti *cleared_info; + u8 gate; - pr_debug("from gate %x pipe %x cmd %x\n", gate, pipe, cmd); + pr_debug("from pipe %x cmd %x\n", pipe, cmd); + + if (pipe >= NFC_HCI_MAX_PIPES) { + status = NFC_HCI_ANY_E_NOK; + goto exit; + } + + gate = hdev->pipes[pipe].gate; switch (cmd) { case NFC_HCI_ADM_NOTIFY_PIPE_CREATED: @@ -387,8 +394,14 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, struct sk_buff *skb) { int r = 0; - u8 gate = hdev->pipes[pipe].gate; + u8 gate; + + if (pipe >= NFC_HCI_MAX_PIPES) { + pr_err("Discarded event %x to invalid pipe %x\n", event, pipe); + goto exit; + } + gate = hdev->pipes[pipe].gate; if (gate == NFC_HCI_INVALID_GATE) { pr_err("Discarded event %x to unopened pipe %x\n", event, pipe); goto exit; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 7b8d4d235a3a14d19d7a47d53b3338668c2572c2..6199f4334fbd271c26726a482cc0bca74ebd9192 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -55,7 +55,10 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED }, [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING, .len = NFC_FIRMWARE_NAME_MAXSIZE }, + [NFC_ATTR_SE_INDEX] = { .type = NLA_U32 }, [NFC_ATTR_SE_APDU] = { .type = NLA_BINARY }, + [NFC_ATTR_VENDOR_ID] = { .type = NLA_U32 }, + [NFC_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 }, [NFC_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, }; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 69a50fad81dcb95aee22742822365105259b5e3d..42ee9a5bfc5c0358736668e738a2a0f80b4f4a08 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2204,6 +2204,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct timespec ts; __u32 ts_status; bool is_drop_n_account = false; + unsigned int slot_id = 0; bool do_vnet = false; /* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT. @@ -2299,6 +2300,20 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, TP_STATUS_KERNEL, (macoff+snaplen)); if (!h.raw) goto drop_n_account; + + if (po->tp_version <= TPACKET_V2) { + slot_id = po->rx_ring.head; + if (test_bit(slot_id, po->rx_ring.rx_owner_map)) + goto drop_n_account; + __set_bit(slot_id, po->rx_ring.rx_owner_map); + } + + if (do_vnet && + virtio_net_hdr_from_skb(skb, h.raw + macoff - + sizeof(struct virtio_net_hdr), + vio_le(), true, 0)) + goto drop_n_account; + if (po->tp_version <= TPACKET_V2) { packet_increment_rx_head(po, &po->rx_ring); /* @@ -2311,12 +2326,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, status |= TP_STATUS_LOSING; } - if (do_vnet && - virtio_net_hdr_from_skb(skb, h.raw + macoff - - sizeof(struct virtio_net_hdr), - vio_le(), true, 0)) - goto drop_n_account; - po->stats.stats1.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; @@ -2404,7 +2413,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, #endif if (po->tp_version <= TPACKET_V2) { + spin_lock(&sk->sk_receive_queue.lock); __packet_set_status(po, h.raw, status); + __clear_bit(slot_id, po->rx_ring.rx_owner_map); + spin_unlock(&sk->sk_receive_queue.lock); sk->sk_data_ready(sk); } else { prb_clear_blk_fill_status(&po->rx_ring); @@ -4297,6 +4309,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, { struct pgv *pg_vec = NULL; struct packet_sock *po = pkt_sk(sk); + unsigned long *rx_owner_map = NULL; int was_running, order = 0; struct packet_ring_buffer *rb; struct sk_buff_head *rb_queue; @@ -4382,6 +4395,12 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, } break; default: + if (!tx_ring) { + rx_owner_map = bitmap_alloc(req->tp_frame_nr, + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); + if (!rx_owner_map) + goto out_free_pg_vec; + } break; } } @@ -4411,6 +4430,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, err = 0; spin_lock_bh(&rb_queue->lock); swap(rb->pg_vec, pg_vec); + if (po->tp_version <= TPACKET_V2) + swap(rb->rx_owner_map, rx_owner_map); rb->frame_max = (req->tp_frame_nr - 1); rb->head = 0; rb->frame_size = req->tp_frame_size; @@ -4442,6 +4463,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, } out_free_pg_vec: + bitmap_free(rx_owner_map); if (pg_vec) free_pg_vec(pg_vec, order, req->tp_block_nr); out: diff --git a/net/packet/internal.h b/net/packet/internal.h index c70a2794456f15559a31de428f6fa6cc8604e090..f10294800aafb3673083acd87c21944e313d9a6a 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -70,7 +70,10 @@ struct packet_ring_buffer { unsigned int __percpu *pending_refcnt; - struct tpacket_kbdq_core prb_bdqc; + union { + unsigned long *rx_owner_map; + struct tpacket_kbdq_core prb_bdqc; + }; }; extern struct mutex fanout_mutex; diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 15182efbbf4e04e38c9d6815b53e3ecce8783ddd..d838f5aca42a004fa3fa3eb1876abc60c96dddf4 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -1540,20 +1540,21 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) node = NULL; srv_node = NULL; if (addr->sq_node == QRTR_NODE_BCAST) { - enqueue_fn = qrtr_bcast_enqueue; - if (addr->sq_port != QRTR_PORT_CTRL) { + if (addr->sq_port != QRTR_PORT_CTRL && + qrtr_local_nid != QRTR_NODE_BCAST) { release_sock(sk); - return -EINVAL; + return -ENOTCONN; } + enqueue_fn = qrtr_bcast_enqueue; } else if (addr->sq_node == ipc->us.sq_node) { enqueue_fn = qrtr_local_enqueue; } else { - enqueue_fn = qrtr_node_enqueue; node = qrtr_node_lookup(addr->sq_node); if (!node) { release_sock(sk); return -ECONNRESET; } + enqueue_fn = qrtr_node_enqueue; if (ipc->state > QRTR_STATE_INIT && ipc->state != node->nid) ipc->state = QRTR_STATE_MULTI; diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 71c7f1dd4599e8d75fe32c62efc01173c42635e9..b5581b0b9480840332155fc573bff331d628220c 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -451,6 +451,7 @@ enum rxrpc_call_flag { RXRPC_CALL_SEND_PING, /* A ping will need to be sent */ RXRPC_CALL_PINGING, /* Ping in process */ RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */ + RXRPC_CALL_DISCONNECTED, /* The call has been disconnected */ }; /* diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index ddaa471a26076f9cdddba51eaa3d576e31187ff8..7021725fa38a76c8dd85f5cc9980502738b7a418 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -505,7 +505,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn); - if (conn) + if (conn && !test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) rxrpc_disconnect_call(call); for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) { @@ -639,6 +639,7 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu) { struct rxrpc_call *call = container_of(rcu, struct rxrpc_call, rcu); + rxrpc_put_connection(call->conn); rxrpc_put_peer(call->peer); kfree(call->rxtx_buffer); kfree(call->rxtx_annotations); @@ -660,7 +661,6 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags)); - ASSERTCMP(call->conn, ==, NULL); /* Clean up the Rx/Tx buffer */ for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 0aa4bf09fb9c9bae0622919d5502b0c296b7cf6d..05d17ec63635ec0d7c8a226dd960e3ed5ef3648f 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -762,9 +762,9 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) struct rxrpc_net *rxnet = rxrpc_net(sock_net(&call->socket->sk)); trace_rxrpc_client(conn, channel, rxrpc_client_chan_disconnect); - call->conn = NULL; spin_lock(&conn->channel_lock); + set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); /* Calls that have never actually been assigned a channel can simply be * discarded. If the conn didn't get used either, it will follow @@ -863,7 +863,6 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call) spin_unlock(&rxnet->client_conn_cache_lock); out_2: spin_unlock(&conn->channel_lock); - rxrpc_put_connection(conn); _leave(""); return; diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index a48c817b792b7588d9d8389b9f8cef910a355c00..af02328205979c5705a0b36b73058031dbc15e0d 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -207,9 +207,8 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) __rxrpc_disconnect_call(conn, call); spin_unlock(&conn->channel_lock); - call->conn = NULL; + set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); conn->idle_timestamp = jiffies; - rxrpc_put_connection(conn); } /* diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index ea506a77f3c811950b8c6ebbf8203c8d797766ca..18ce6f97462b6c23372df33a75614e5dfcf9d0ad 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -585,8 +585,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb, immediate_ack, true, rxrpc_propose_ack_input_data); - if (sp->hdr.seq == READ_ONCE(call->rx_hard_ack) + 1) - rxrpc_notify_socket(call); + rxrpc_notify_socket(call); _leave(" [queued]"); } diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c index e7f6b8823eb6e6c6794ed78e1197c1cf8aab4858..ad9d1b21cb0ba4ead61569fec8a125e30576e1c7 100644 --- a/net/rxrpc/key.c +++ b/net/rxrpc/key.c @@ -35,7 +35,7 @@ static void rxrpc_free_preparse_s(struct key_preparsed_payload *); static void rxrpc_destroy(struct key *); static void rxrpc_destroy_s(struct key *); static void rxrpc_describe(const struct key *, struct seq_file *); -static long rxrpc_read(const struct key *, char __user *, size_t); +static long rxrpc_read(const struct key *, char *, size_t); /* * rxrpc defined keys take an arbitrary string as the description and an @@ -1044,12 +1044,12 @@ EXPORT_SYMBOL(rxrpc_get_null_key); * - this returns the result in XDR form */ static long rxrpc_read(const struct key *key, - char __user *buffer, size_t buflen) + char *buffer, size_t buflen) { const struct rxrpc_key_token *token; const struct krb5_principal *princ; size_t size; - __be32 __user *xdr, *oldxdr; + __be32 *xdr, *oldxdr; u32 cnlen, toksize, ntoks, tok, zero; u16 toksizes[AFSTOKEN_MAX]; int loop; @@ -1126,30 +1126,25 @@ static long rxrpc_read(const struct key *key, if (!buffer || buflen < size) return size; - xdr = (__be32 __user *) buffer; + xdr = (__be32 *)buffer; zero = 0; #define ENCODE(x) \ do { \ - __be32 y = htonl(x); \ - if (put_user(y, xdr++) < 0) \ - goto fault; \ + *xdr++ = htonl(x); \ } while(0) #define ENCODE_DATA(l, s) \ do { \ u32 _l = (l); \ ENCODE(l); \ - if (copy_to_user(xdr, (s), _l) != 0) \ - goto fault; \ - if (_l & 3 && \ - copy_to_user((u8 __user *)xdr + _l, &zero, 4 - (_l & 3)) != 0) \ - goto fault; \ + memcpy(xdr, (s), _l); \ + if (_l & 3) \ + memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \ xdr += (_l + 3) >> 2; \ } while(0) #define ENCODE64(x) \ do { \ __be64 y = cpu_to_be64(x); \ - if (copy_to_user(xdr, &y, 8) != 0) \ - goto fault; \ + memcpy(xdr, &y, 8); \ xdr += 8 >> 2; \ } while(0) #define ENCODE_STR(s) \ @@ -1240,8 +1235,4 @@ static long rxrpc_read(const struct key *key, ASSERTCMP((char __user *) xdr - buffer, ==, size); _leave(" = %zu", size); return size; - -fault: - _leave(" = -EFAULT"); - return -EFAULT; } diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index edddbacf33bc8682125eceebc5e1ebf748a227ba..9619c56ef4cd5f03a090156f747d770ce1fcd78f 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -96,7 +96,7 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_call *call, */ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping) { - struct rxrpc_connection *conn = NULL; + struct rxrpc_connection *conn; struct rxrpc_ack_buffer *pkt; struct msghdr msg; struct kvec iov[2]; @@ -106,18 +106,14 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping) int ret; u8 reason; - spin_lock_bh(&call->lock); - if (call->conn) - conn = rxrpc_get_connection_maybe(call->conn); - spin_unlock_bh(&call->lock); - if (!conn) + if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) return -ECONNRESET; pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); - if (!pkt) { - rxrpc_put_connection(conn); + if (!pkt) return -ENOMEM; - } + + conn = call->conn; msg.msg_name = &call->peer->srx.transport; msg.msg_namelen = call->peer->srx.transport_len; @@ -204,7 +200,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping) } out: - rxrpc_put_connection(conn); kfree(pkt); return ret; } @@ -214,20 +209,18 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping) */ int rxrpc_send_abort_packet(struct rxrpc_call *call) { - struct rxrpc_connection *conn = NULL; + struct rxrpc_connection *conn; struct rxrpc_abort_buffer pkt; struct msghdr msg; struct kvec iov[1]; rxrpc_serial_t serial; int ret; - spin_lock_bh(&call->lock); - if (call->conn) - conn = rxrpc_get_connection_maybe(call->conn); - spin_unlock_bh(&call->lock); - if (!conn) + if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) return -ECONNRESET; + conn = call->conn; + msg.msg_name = &call->peer->srx.transport; msg.msg_namelen = call->peer->srx.transport_len; msg.msg_control = NULL; @@ -255,7 +248,6 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call) ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 1, sizeof(pkt)); - rxrpc_put_connection(conn); return ret; } diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 1879665e5a2bcd567d0a3926d329d7ccf8836f8f..8974bd25c71e8b85f3fccb388176f1ea1f6baf6e 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -160,6 +160,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, if (!atomic_read(&head->ht.nelems)) return -1; + flow_dissector_init_keys(&skb_key.control, &skb_key.basic); fl_clear_masked_range(&skb_key, &head->mask); info = skb_tunnel_info(skb); @@ -445,6 +446,7 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_IP_TTL] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NLA_U8 }, + [TCA_FLOWER_FLAGS] = { .type = NLA_U32 }, }; static void fl_set_key_val(struct nlattr **tb, diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c index d8fd152779c8d451bfaa0b028f3e3a94b723731d..a985f91e8b476222aefa72df3c8e4a4df9f2cc67 100644 --- a/net/sched/cls_matchall.c +++ b/net/sched/cls_matchall.c @@ -136,6 +136,7 @@ static void *mall_get(struct tcf_proto *tp, u32 handle) static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = { [TCA_MATCHALL_UNSPEC] = { .type = NLA_UNSPEC }, [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 }, + [TCA_MATCHALL_FLAGS] = { .type = NLA_U32 }, }; static int mall_set_parms(struct net *net, struct tcf_proto *tp, diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index ac9a5b8825b9d572a0e60453fc6c68e82bdab320..4f133faa9e60d73808770358877732af3b02d29d 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -539,8 +539,8 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, fp = &b->ht[h]; for (pfp = rtnl_dereference(*fp); pfp; fp = &pfp->next, pfp = rtnl_dereference(*fp)) { - if (pfp == f) { - *fp = f->next; + if (pfp == fold) { + rcu_assign_pointer(*fp, fold->next); break; } } diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index cf325625c99da83df0503a7a324d1b962540a34a..89259819e9edd68bef09530549bbd7157cb317f8 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -475,10 +475,8 @@ static u32 gen_tunnel(struct rsvp_head *data) static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = { [TCA_RSVP_CLASSID] = { .type = NLA_U32 }, - [TCA_RSVP_DST] = { .type = NLA_BINARY, - .len = RSVP_DST_LEN * sizeof(u32) }, - [TCA_RSVP_SRC] = { .type = NLA_BINARY, - .len = RSVP_DST_LEN * sizeof(u32) }, + [TCA_RSVP_DST] = { .len = RSVP_DST_LEN * sizeof(u32) }, + [TCA_RSVP_SRC] = { .len = RSVP_DST_LEN * sizeof(u32) }, [TCA_RSVP_PINFO] = { .len = sizeof(struct tc_rsvp_pinfo) }, }; diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 75c7c7cc74999ba3d414c3b71a309ab69fc9bf73..c2d2c054a4e495a7df305842e10345b5bb893e36 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -351,12 +351,32 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, cp->fall_through = p->fall_through; cp->tp = tp; + if (tb[TCA_TCINDEX_HASH]) + cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); + + if (tb[TCA_TCINDEX_MASK]) + cp->mask = nla_get_u16(tb[TCA_TCINDEX_MASK]); + + if (tb[TCA_TCINDEX_SHIFT]) + cp->shift = nla_get_u32(tb[TCA_TCINDEX_SHIFT]); + + if (!cp->hash) { + /* Hash not specified, use perfect hash if the upper limit + * of the hashing index is below the threshold. + */ + if ((cp->mask >> cp->shift) < PERFECT_HASH_THRESHOLD) + cp->hash = (cp->mask >> cp->shift) + 1; + else + cp->hash = DEFAULT_HASH_SIZE; + } + if (p->perfect) { int i; if (tcindex_alloc_perfect_hash(cp) < 0) goto errout; - for (i = 0; i < cp->hash; i++) + cp->alloc_hash = cp->hash; + for (i = 0; i < min(cp->hash, p->hash); i++) cp->perfect[i].res = p->perfect[i].res; balloc = 1; } @@ -364,19 +384,10 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, err = tcindex_filter_result_init(&new_filter_result); if (err < 0) - goto errout1; + goto errout_alloc; if (old_r) cr = r->res; - if (tb[TCA_TCINDEX_HASH]) - cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); - - if (tb[TCA_TCINDEX_MASK]) - cp->mask = nla_get_u16(tb[TCA_TCINDEX_MASK]); - - if (tb[TCA_TCINDEX_SHIFT]) - cp->shift = nla_get_u32(tb[TCA_TCINDEX_SHIFT]); - err = -EBUSY; /* Hash already allocated, make sure that we still meet the @@ -394,16 +405,6 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, if (tb[TCA_TCINDEX_FALL_THROUGH]) cp->fall_through = nla_get_u32(tb[TCA_TCINDEX_FALL_THROUGH]); - if (!cp->hash) { - /* Hash not specified, use perfect hash if the upper limit - * of the hashing index is below the threshold. - */ - if ((cp->mask >> cp->shift) < PERFECT_HASH_THRESHOLD) - cp->hash = (cp->mask >> cp->shift) + 1; - else - cp->hash = DEFAULT_HASH_SIZE; - } - if (!cp->perfect && !cp->h) cp->alloc_hash = cp->hash; @@ -502,7 +503,6 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, tcindex_free_perfect_hash(cp); else if (balloc == 2) kfree(cp->h); -errout1: tcf_exts_destroy(&new_filter_result.exts); errout: kfree(cp); diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 7a944f508cae82d07669db3a0219aff7fc424d40..66f1d40b910aca458ea1553a13b0be64ad59df11 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -695,6 +695,7 @@ static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = { [TCA_FQ_FLOW_MAX_RATE] = { .type = NLA_U32 }, [TCA_FQ_BUCKETS_LOG] = { .type = NLA_U32 }, [TCA_FQ_FLOW_REFILL_DELAY] = { .type = NLA_U32 }, + [TCA_FQ_ORPHAN_MASK] = { .type = NLA_U32 }, [TCA_FQ_LOW_RATE_THRESHOLD] = { .type = NLA_U32 }, }; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 53a66ee1331f0915bf04969603e51c8cf3515577..18efb8cc46932735123fa41e7c3c6b56d0bf9ba7 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -235,7 +235,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, { struct sctp_association *asoc = t->asoc; struct dst_entry *dst = NULL; - struct flowi6 *fl6 = &fl->u.ip6; + struct flowi _fl; + struct flowi6 *fl6 = &_fl.u.ip6; struct sctp_bind_addr *bp; struct ipv6_pinfo *np = inet6_sk(sk); struct sctp_sockaddr_entry *laddr; @@ -245,7 +246,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, enum sctp_scope scope; __u8 matchlen = 0; - memset(fl6, 0, sizeof(struct flowi6)); + memset(&_fl, 0, sizeof(_fl)); fl6->daddr = daddr->v6.sin6_addr; fl6->fl6_dport = daddr->v6.sin6_port; fl6->flowi6_proto = IPPROTO_SCTP; @@ -271,8 +272,11 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, rcu_read_unlock(); dst = ip6_dst_lookup_flow(sk, fl6, final_p); - if (!asoc || saddr) + if (!asoc || saddr) { + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); goto out; + } bp = &asoc->base.bind_addr; scope = sctp_scope(daddr); @@ -295,6 +299,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if ((laddr->a.sa.sa_family == AF_INET6) && (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) { rcu_read_unlock(); + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); goto out; } } @@ -333,6 +339,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if (!IS_ERR_OR_NULL(dst)) dst_release(dst); dst = bdst; + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); break; } @@ -346,6 +354,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, dst_release(dst); dst = bdst; matchlen = bmatchlen; + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); } rcu_read_unlock(); @@ -354,14 +364,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, struct rt6_info *rt; rt = (struct rt6_info *)dst; - t->dst = dst; t->dst_cookie = rt6_get_cookie(rt); pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n", &rt->rt6i_dst.addr, rt->rt6i_dst.plen, - &fl6->saddr); + &fl->u.ip6.saddr); } else { t->dst = NULL; - pr_debug("no route\n"); } } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index bf39f317953afdf5bacadda70bbf881ceb57278d..785456df750518aacd7bdc03e1922d1c2a67bfee 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -435,14 +435,15 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, { struct sctp_association *asoc = t->asoc; struct rtable *rt; - struct flowi4 *fl4 = &fl->u.ip4; + struct flowi _fl; + struct flowi4 *fl4 = &_fl.u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; - memset(fl4, 0x0, sizeof(struct flowi4)); + memset(&_fl, 0x0, sizeof(_fl)); fl4->daddr = daddr->v4.sin_addr.s_addr; fl4->fl4_dport = daddr->v4.sin_port; fl4->flowi4_proto = IPPROTO_SCTP; @@ -460,8 +461,11 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, &fl4->saddr); rt = ip_route_output_key(sock_net(sk), fl4); - if (!IS_ERR(rt)) + if (!IS_ERR(rt)) { dst = &rt->dst; + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); + } /* If there is no association or if a source address is passed, no * more validation is required. @@ -524,27 +528,33 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, false); if (!odev || odev->ifindex != fl4->flowi4_oif) { - if (!dst) + if (!dst) { dst = &rt->dst; - else + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); + } else { dst_release(&rt->dst); + } continue; } dst_release(dst); dst = &rt->dst; + t->dst = dst; + memcpy(fl, &_fl, sizeof(_fl)); break; } out_unlock: rcu_read_unlock(); out: - t->dst = dst; - if (dst) + if (dst) { pr_debug("rt_dst:%pI4, rt_src:%pI4\n", - &fl4->daddr, &fl4->saddr); - else + &fl->u.ip4.daddr, &fl->u.ip4.saddr); + } else { + t->dst = NULL; pr_debug("no route\n"); + } } /* For v4, the source address is cached in the route entry(dst). So no need diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c index 75274a60b77ab0f40903ae0ea38c633085b0a336..6a5a3dfa6c8d660fdd6b311d043776c7c51e7591 100644 --- a/net/sctp/sctp_diag.c +++ b/net/sctp/sctp_diag.c @@ -221,15 +221,11 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc) addrcnt++; return nla_total_size(sizeof(struct sctp_info)) - + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ - + nla_total_size(1) /* INET_DIAG_TOS */ - + nla_total_size(1) /* INET_DIAG_TCLASS */ - + nla_total_size(4) /* INET_DIAG_MARK */ - + nla_total_size(4) /* INET_DIAG_CLASS_ID */ + nla_total_size(addrlen * asoc->peer.transport_count) + nla_total_size(addrlen * addrcnt) - + nla_total_size(sizeof(struct inet_diag_meminfo)) + nla_total_size(sizeof(struct inet_diag_msg)) + + inet_diag_msg_attrs_size() + + nla_total_size(sizeof(struct inet_diag_meminfo)) + 64; } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f67df16bd3409b6a4427b2d102ec4f25e0c2cae7..e698edd56bd56295f9155566e3b1f322d34fe1f8 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -858,7 +858,11 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, struct sctp_chunk *retval; __u32 ctsn; - ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); + if (chunk && chunk->asoc) + ctsn = sctp_tsnmap_get_ctsn(&chunk->asoc->peer.tsn_map); + else + ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); + shut.cum_tsn_ack = htonl(ctsn); retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0, diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a2e058127ef7a77b29afb9a6a7578c7ce670b06b..ba29d782af30d52c5f45df6b25cbcf4411243c8c 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -182,6 +182,16 @@ static inline bool sctp_chunk_length_valid(struct sctp_chunk *chunk, return true; } +/* Check for format error in an ABORT chunk */ +static inline bool sctp_err_chunk_valid(struct sctp_chunk *chunk) +{ + struct sctp_errhdr *err; + + sctp_walk_errors(err, chunk->chunk_hdr); + + return (void *)err == (void *)chunk->chunk_end; +} + /********************************************************** * These are the state functions for handling chunk events. **********************************************************/ @@ -2202,6 +2212,9 @@ enum sctp_disposition sctp_sf_shutdown_pending_abort( sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest)) return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); + if (!sctp_err_chunk_valid(chunk)) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + return __sctp_sf_do_9_1_abort(net, ep, asoc, type, arg, commands); } @@ -2245,6 +2258,9 @@ enum sctp_disposition sctp_sf_shutdown_sent_abort( sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest)) return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); + if (!sctp_err_chunk_valid(chunk)) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + /* Stop the T2-shutdown timer. */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); @@ -2512,6 +2528,9 @@ enum sctp_disposition sctp_sf_do_9_1_abort( sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest)) return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); + if (!sctp_err_chunk_valid(chunk)) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + return __sctp_sf_do_9_1_abort(net, ep, asoc, type, arg, commands); } @@ -2529,16 +2548,8 @@ static enum sctp_disposition __sctp_sf_do_9_1_abort( /* See if we have an error cause code in the chunk. */ len = ntohs(chunk->chunk_hdr->length); - if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) { - struct sctp_errhdr *err; - - sctp_walk_errors(err, chunk->chunk_hdr); - if ((void *)err != (void *)chunk->chunk_end) - return sctp_sf_pdiscard(net, ep, asoc, type, arg, - commands); - + if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) error = ((struct sctp_errhdr *)chunk->skb->data)->cause; - } sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET)); /* ASSOC_FAILED will DELETE_TCB. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 09cda66d0567ac5f1f8c8691a51b665d78553639..442780515760e290915e0f61f2671b5ec2ef7b6a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -175,29 +175,44 @@ static void sctp_clear_owner_w(struct sctp_chunk *chunk) skb_orphan(chunk->skb); } +#define traverse_and_process() \ +do { \ + msg = chunk->msg; \ + if (msg == prev_msg) \ + continue; \ + list_for_each_entry(c, &msg->chunks, frag_list) { \ + if ((clear && asoc->base.sk == c->skb->sk) || \ + (!clear && asoc->base.sk != c->skb->sk)) \ + cb(c); \ + } \ + prev_msg = msg; \ +} while (0) + static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, + bool clear, void (*cb)(struct sctp_chunk *)) { + struct sctp_datamsg *msg, *prev_msg = NULL; struct sctp_outq *q = &asoc->outqueue; + struct sctp_chunk *chunk, *c; struct sctp_transport *t; - struct sctp_chunk *chunk; list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) list_for_each_entry(chunk, &t->transmitted, transmitted_list) - cb(chunk); + traverse_and_process(); list_for_each_entry(chunk, &q->retransmit, transmitted_list) - cb(chunk); + traverse_and_process(); list_for_each_entry(chunk, &q->sacked, transmitted_list) - cb(chunk); + traverse_and_process(); list_for_each_entry(chunk, &q->abandoned, transmitted_list) - cb(chunk); + traverse_and_process(); list_for_each_entry(chunk, &q->out_chunk_list, list) - cb(chunk); + traverse_and_process(); } /* Verify that this is a valid address. */ @@ -8280,9 +8295,9 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, * paths won't try to lock it and then oldsk. */ lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); - sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w); + sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w); sctp_assoc_migrate(assoc, newsk); - sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w); + sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag. diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c index d2d01cf7022445d3d55f7d791b07f36655726d0d..576c37d860514b0d8014d97904791aa4bcb2c07d 100644 --- a/net/smc/smc_diag.c +++ b/net/smc/smc_diag.c @@ -38,15 +38,14 @@ static void smc_diag_msg_common_fill(struct smc_diag_msg *r, struct sock *sk) { struct smc_sock *smc = smc_sk(sk); + memset(r, 0, sizeof(*r)); r->diag_family = sk->sk_family; + sock_diag_save_cookie(sk, r->id.idiag_cookie); if (!smc->clcsock) return; r->id.idiag_sport = htons(smc->clcsock->sk->sk_num); r->id.idiag_dport = smc->clcsock->sk->sk_dport; r->id.idiag_if = smc->clcsock->sk->sk_bound_dev_if; - sock_diag_save_cookie(sk, r->id.idiag_cookie); - memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src)); - memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst)); r->id.idiag_src[0] = smc->clcsock->sk->sk_rcv_saddr; r->id.idiag_dst[0] = smc->clcsock->sk->sk_daddr; } diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 4410d007151542c8dfc12e57f2c942662b9958d3..7d89b0584944bf15f0dcda1a1c7a1f6e242c6d52 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -513,6 +513,8 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data) struct smc_ib_device *smcibdev; smcibdev = ib_get_client_data(ibdev, &smc_ib_client); + if (!smcibdev || smcibdev->ibdev != ibdev) + return; ib_set_client_data(ibdev, &smc_ib_client, NULL); spin_lock(&smc_ib_devices.lock); list_del_init(&smcibdev->list); /* remove from smc_ib_devices */ diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index cc08cb1292a9aad3cfa4000b6ce294f019f13354..a457e7afb7688c628395f5596d348a640d5f3f5f 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1188,6 +1188,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, dprintk("RPC: No creds found!\n"); goto out; } else { + struct timespec64 boot; /* steal creds */ rsci.cred = ud->creds; @@ -1208,6 +1209,9 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, &expiry, GFP_KERNEL); if (status) goto out; + + getboottime64(&boot); + expiry -= boot.tv_sec; } rsci.h.expiry_time = expiry; diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c index 6614512f818008c6cb34ed19d86e677b9e86fcfa..736b76ec8cf012a9c4410529918634cd76f6ed46 100644 --- a/net/vmw_vsock/hyperv_transport.c +++ b/net/vmw_vsock/hyperv_transport.c @@ -144,28 +144,15 @@ struct hvsock { **************************************************************************** * The only valid Service GUIDs, from the perspectives of both the host and * * Linux VM, that can be connected by the other end, must conform to this * - * format: -facb-11e6-bd58-64006a7986d3, and the "port" must be in * - * this range [0, 0x7FFFFFFF]. * + * format: -facb-11e6-bd58-64006a7986d3. * **************************************************************************** * * When we write apps on the host to connect(), the GUID ServiceID is used. * When we write apps in Linux VM to connect(), we only need to specify the * port and the driver will form the GUID and use that to request the host. * - * From the perspective of Linux VM: - * 1. the local ephemeral port (i.e. the local auto-bound port when we call - * connect() without explicit bind()) is generated by __vsock_bind_stream(), - * and the range is [1024, 0xFFFFFFFF). - * 2. the remote ephemeral port (i.e. the auto-generated remote port for - * a connect request initiated by the host's connect()) is generated by - * hvs_remote_addr_init() and the range is [0x80000000, 0xFFFFFFFF). */ -#define MAX_LISTEN_PORT ((u32)0x7FFFFFFF) -#define MAX_VM_LISTEN_PORT MAX_LISTEN_PORT -#define MAX_HOST_LISTEN_PORT MAX_LISTEN_PORT -#define MIN_HOST_EPHEMERAL_PORT (MAX_HOST_LISTEN_PORT + 1) - /* 00000000-facb-11e6-bd58-64006a7986d3 */ static const uuid_le srv_id_template = UUID_LE(0x00000000, 0xfacb, 0x11e6, 0xbd, 0x58, @@ -188,33 +175,6 @@ static void hvs_addr_init(struct sockaddr_vm *addr, const uuid_le *svr_id) vsock_addr_init(addr, VMADDR_CID_ANY, port); } -static void hvs_remote_addr_init(struct sockaddr_vm *remote, - struct sockaddr_vm *local) -{ - static u32 host_ephemeral_port = MIN_HOST_EPHEMERAL_PORT; - struct sock *sk; - - vsock_addr_init(remote, VMADDR_CID_ANY, VMADDR_PORT_ANY); - - while (1) { - /* Wrap around ? */ - if (host_ephemeral_port < MIN_HOST_EPHEMERAL_PORT || - host_ephemeral_port == VMADDR_PORT_ANY) - host_ephemeral_port = MIN_HOST_EPHEMERAL_PORT; - - remote->svm_port = host_ephemeral_port++; - - sk = vsock_find_connected_socket(remote, local); - if (!sk) { - /* Found an available ephemeral port */ - return; - } - - /* Release refcnt got in vsock_find_connected_socket */ - sock_put(sk); - } -} - static void hvs_set_channel_pending_send_size(struct vmbus_channel *chan) { set_channel_pending_send_size(chan, @@ -342,12 +302,7 @@ static void hvs_open_connection(struct vmbus_channel *chan) if_type = &chan->offermsg.offer.if_type; if_instance = &chan->offermsg.offer.if_instance; conn_from_host = chan->offermsg.offer.u.pipe.user_def[0]; - - /* The host or the VM should only listen on a port in - * [0, MAX_LISTEN_PORT] - */ - if (!is_valid_srv_id(if_type) || - get_port_by_srv_id(if_type) > MAX_LISTEN_PORT) + if (!is_valid_srv_id(if_type)) return; hvs_addr_init(&addr, conn_from_host ? if_type : if_instance); @@ -372,6 +327,13 @@ static void hvs_open_connection(struct vmbus_channel *chan) new->sk_state = TCP_SYN_SENT; vnew = vsock_sk(new); + + hvs_addr_init(&vnew->local_addr, if_type); + + /* Remote peer is always the host */ + vsock_addr_init(&vnew->remote_addr, + VMADDR_CID_HOST, VMADDR_PORT_ANY); + vnew->remote_addr.svm_port = get_port_by_srv_id(if_instance); hvs_new = vnew->trans; hvs_new->chan = chan; } else { @@ -411,8 +373,6 @@ static void hvs_open_connection(struct vmbus_channel *chan) sk->sk_ack_backlog++; hvs_addr_init(&vnew->local_addr, if_type); - hvs_remote_addr_init(&vnew->remote_addr, &vnew->local_addr); - hvs_new->vm_srv_id = *if_type; hvs_new->host_srv_id = *if_instance; @@ -717,16 +677,6 @@ static bool hvs_stream_is_active(struct vsock_sock *vsk) static bool hvs_stream_allow(u32 cid, u32 port) { - /* The host's port range [MIN_HOST_EPHEMERAL_PORT, 0xFFFFFFFF) is - * reserved as ephemeral ports, which are used as the host's ports - * when the host initiates connections. - * - * Perform this check in the guest so an immediate error is produced - * instead of a timeout. - */ - if (port > MAX_HOST_LISTEN_PORT) - return false; - if (cid == VMADDR_CID_HOST) return true; diff --git a/net/wireless/core.c b/net/wireless/core.c index 0d67dbc0559adbc85f44c72bcba04c9e417dba6a..03adeb7cdb089287046f76a43ae1ccdb745a0909 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -3,7 +3,7 @@ * * Copyright 2006-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright 2015 Intel Deutschland GmbH + * Copyright 2015-2017 Intel Deutschland GmbH */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -740,6 +740,8 @@ int wiphy_register(struct wiphy *wiphy) /* sanity check supported bands/channels */ for (band = 0; band < NUM_NL80211_BANDS; band++) { + u16 types = 0; + sband = wiphy->bands[band]; if (!sband) continue; @@ -784,6 +786,23 @@ int wiphy_register(struct wiphy *wiphy) sband->channels[i].band = band; } + for (i = 0; i < sband->n_iftype_data; i++) { + const struct ieee80211_sband_iftype_data *iftd; + + iftd = &sband->iftype_data[i]; + + if (WARN_ON(!iftd->types_mask)) + return -EINVAL; + if (WARN_ON(types & iftd->types_mask)) + return -EINVAL; + + /* at least one piece of information must be present */ + if (WARN_ON(!iftd->he_cap.has_he)) + return -EINVAL; + + types |= iftd->types_mask; + } + have_band = true; } diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index a9c0f368db5d27ed72159a2395a4a4ec60234ed0..24e18405cdb48fff6090831f656b4f883c926109 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c @@ -7,9 +7,13 @@ void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct device *pdev = wiphy_dev(wdev->wiphy); - strlcpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name, - sizeof(info->driver)); + if (pdev->driver) + strlcpy(info->driver, pdev->driver->name, + sizeof(info->driver)); + else + strlcpy(info->driver, "N/A", sizeof(info->driver)); strlcpy(info->version, init_utsname()->release, sizeof(info->version)); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ad044bfe07779e21563cfd11832aa78a907d0a0e..3a3b7cd9d9fb10ae1cf87005b312edb17ffb7190 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -321,6 +321,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 }, [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, + [NL80211_ATTR_STATUS_CODE] = { .type = NLA_U16 }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, [NL80211_ATTR_PID] = { .type = NLA_U32 }, @@ -346,6 +347,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_ATTR_MEASUREMENT_DURATION] = { .type = NLA_U16 }, + [NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY] = { .type = NLA_FLAG }, [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED }, @@ -394,6 +397,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MDID] = { .type = NLA_U16 }, [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_CRIT_PROT_ID] = { .type = NLA_U16 }, + [NL80211_ATTR_MAX_CRIT_PROT_DURATION] = { .type = NLA_U16 }, [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 }, [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 }, [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG }, @@ -419,6 +424,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, + [NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 }, [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, @@ -455,6 +461,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN }, [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG }, [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY, + .len = NL80211_HE_MAX_CAPABILITY_LEN }, }; /* policy for the key attributes */ @@ -1254,6 +1262,34 @@ static int nl80211_send_coalesce(struct sk_buff *msg, return 0; } +static int +nl80211_send_iftype_data(struct sk_buff *msg, + const struct ieee80211_sband_iftype_data *iftdata) +{ + const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap; + + if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES, + iftdata->types_mask)) + return -ENOBUFS; + + if (he_cap->has_he) { + if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, + sizeof(he_cap->he_cap_elem.mac_cap_info), + he_cap->he_cap_elem.mac_cap_info) || + nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, + sizeof(he_cap->he_cap_elem.phy_cap_info), + he_cap->he_cap_elem.phy_cap_info) || + nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, + sizeof(he_cap->he_mcs_nss_supp), + &he_cap->he_mcs_nss_supp) || + nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, + sizeof(he_cap->ppe_thres), he_cap->ppe_thres)) + return -ENOBUFS; + } + + return 0; +} + static int nl80211_send_band_rateinfo(struct sk_buff *msg, struct ieee80211_supported_band *sband) { @@ -1283,6 +1319,32 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg, sband->vht_cap.cap))) return -ENOBUFS; + if (sband->n_iftype_data) { + struct nlattr *nl_iftype_data = + nla_nest_start(msg, NL80211_BAND_ATTR_IFTYPE_DATA); + int err; + + if (!nl_iftype_data) + return -ENOBUFS; + + for (i = 0; i < sband->n_iftype_data; i++) { + struct nlattr *iftdata; + + iftdata = nla_nest_start(msg, i + 1); + if (!iftdata) + return -ENOBUFS; + + err = nl80211_send_iftype_data(msg, + &sband->iftype_data[i]); + if (err) + return err; + + nla_nest_end(msg, iftdata); + } + + nla_nest_end(msg, nl_iftype_data); + } + /* add bitrates */ nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); if (!nl_rates) @@ -4373,6 +4435,9 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, case RATE_INFO_BW_160: rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH; break; + case RATE_INFO_BW_HE_RU: + rate_flg = 0; + WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS)); } if (rate_flg && nla_put_flag(msg, rate_flg)) @@ -4392,6 +4457,19 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, if (info->flags & RATE_INFO_FLAGS_SHORT_GI && nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) return false; + } else if (info->flags & RATE_INFO_FLAGS_HE_MCS) { + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs)) + return false; + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss)) + return false; + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi)) + return false; + if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm)) + return false; + if (info->bw == RATE_INFO_BW_HE_RU && + nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC, + info->he_ru_alloc)) + return false; } nla_nest_end(msg, rate); @@ -4776,7 +4854,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, return -EINVAL; if (params->supported_rates) return -EINVAL; - if (params->ext_capab || params->ht_capa || params->vht_capa) + if (params->ext_capab || params->ht_capa || params->vht_capa || + params->he_capa) return -EINVAL; } @@ -4982,6 +5061,15 @@ static int nl80211_set_station_tdls(struct genl_info *info, if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) params->vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) { + params->he_capa = + nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + params->he_capa_len = + nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + + if (params->he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN) + return -EINVAL; + } err = nl80211_parse_sta_channel_info(info, params); if (err) @@ -5209,6 +5297,17 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) { + params.he_capa = + nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + params.he_capa_len = + nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + + /* max len is validated in nla policy */ + if (params.he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN) + return -EINVAL; + } + if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { params.opmode_notif_used = true; params.opmode_notif = @@ -5241,6 +5340,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) { params.ht_capa = NULL; params.vht_capa = NULL; + + /* HE requires WME */ + if (params.he_capa_len) + return -EINVAL; } /* When you run into this, adjust the code below for the new flag */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8692ef603e76f8a79c06407438cd66b00ea55f94..23a6f7ff2d4707d4f4f50c80534f8fe3368936e5 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1740,7 +1740,7 @@ static void handle_channel_custom(struct wiphy *wiphy, break; } - if (IS_ERR(reg_rule)) { + if (IS_ERR_OR_NULL(reg_rule)) { pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n", chan->center_freq); if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { diff --git a/net/wireless/util.c b/net/wireless/util.c index 81b9585ef16c2b010b4cd479aa02411efc57693e..bf688167da3fd7b9839022c6e81e4a1bac79b879 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -4,6 +4,7 @@ * * Copyright 2007-2009 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright 2017 Intel Deutschland GmbH */ #include #include @@ -1263,6 +1264,85 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) return 0; } +static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) +{ +#define SCALE 2048 + u16 mcs_divisors[12] = { + 34133, /* 16.666666... */ + 17067, /* 8.333333... */ + 11378, /* 5.555555... */ + 8533, /* 4.166666... */ + 5689, /* 2.777777... */ + 4267, /* 2.083333... */ + 3923, /* 1.851851... */ + 3413, /* 1.666666... */ + 2844, /* 1.388888... */ + 2560, /* 1.250000... */ + 2276, /* 1.111111... */ + 2048, /* 1.000000... */ + }; + u32 rates_160M[3] = { 960777777, 907400000, 816666666 }; + u32 rates_969[3] = { 480388888, 453700000, 408333333 }; + u32 rates_484[3] = { 229411111, 216666666, 195000000 }; + u32 rates_242[3] = { 114711111, 108333333, 97500000 }; + u32 rates_106[3] = { 40000000, 37777777, 34000000 }; + u32 rates_52[3] = { 18820000, 17777777, 16000000 }; + u32 rates_26[3] = { 9411111, 8888888, 8000000 }; + u64 tmp; + u32 result; + + if (WARN_ON_ONCE(rate->mcs > 11)) + return 0; + + if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2)) + return 0; + if (WARN_ON_ONCE(rate->he_ru_alloc > + NL80211_RATE_INFO_HE_RU_ALLOC_2x996)) + return 0; + if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8)) + return 0; + + if (rate->bw == RATE_INFO_BW_160) + result = rates_160M[rate->he_gi]; + else if (rate->bw == RATE_INFO_BW_80 || + (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996)) + result = rates_969[rate->he_gi]; + else if (rate->bw == RATE_INFO_BW_40 || + (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484)) + result = rates_484[rate->he_gi]; + else if (rate->bw == RATE_INFO_BW_20 || + (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242)) + result = rates_242[rate->he_gi]; + else if (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106) + result = rates_106[rate->he_gi]; + else if (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52) + result = rates_52[rate->he_gi]; + else if (rate->bw == RATE_INFO_BW_HE_RU && + rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26) + result = rates_26[rate->he_gi]; + else if (WARN(1, "invalid HE MCS: bw:%d, ru:%d\n", + rate->bw, rate->he_ru_alloc)) + return 0; + + /* now scale to the appropriate MCS */ + tmp = result; + tmp *= SCALE; + do_div(tmp, mcs_divisors[rate->mcs]); + result = tmp; + + /* and take NSS, DCM into account */ + result = (result * rate->nss) / 8; + if (rate->he_dcm) + result /= 2; + + return result; +} + u32 cfg80211_calculate_bitrate(struct rate_info *rate) { if (rate->flags & RATE_INFO_FLAGS_MCS) @@ -1271,6 +1351,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) return cfg80211_calculate_bitrate_60g(rate); if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) return cfg80211_calculate_bitrate_vht(rate); + if (rate->flags & RATE_INFO_FLAGS_HE_MCS) + return cfg80211_calculate_bitrate_he(rate); return rate->legacy; } diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 39231237e1c3b3806dc956429195a59edf46bfd6..30f71620d4e3f3273fc5e682eee5fd3112acab55 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -120,8 +120,10 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, goto drop; } - if (!pskb_may_pull(skb, 1)) + if (!pskb_may_pull(skb, 1)) { + x25_neigh_put(nb); return 0; + } switch (skb->data[0]) { diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index f1edb3584efc77b9d827f3e8665017fa62eb434c..f8a71a5b4507fe0f001cddf0b1980acb73c4a6d7 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -188,6 +188,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void return xfrm_dev_feat_change(dev); case NETDEV_DOWN: + case NETDEV_UNREGISTER: return xfrm_dev_down(dev); } return NOTIFY_DONE; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3607538387f81131f33eb10dde67e9a78d8d2418..5f5ad0dff5a40d8ba5b6a243c0de35cfb3ce82d7 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -309,7 +309,9 @@ EXPORT_SYMBOL(xfrm_policy_destroy); static void xfrm_policy_kill(struct xfrm_policy *policy) { + write_lock_bh(&policy->lock); policy->walk.dead = 1; + write_unlock_bh(&policy->lock); atomic_inc(&policy->genid); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ba152c510eb2b2850e07319c65827f334aed28b4..cf220e77a59dab743f1d950269aca7b90b6417b4 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -109,7 +109,8 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs) return 0; uctx = nla_data(rt); - if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) + if (uctx->len > nla_len(rt) || + uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) return -EINVAL; return 0; @@ -2265,6 +2266,9 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, xfrm_mark_get(attrs, &mark); err = verify_newpolicy_info(&ua->policy); + if (err) + goto free_state; + err = verify_sec_ctx_len(attrs); if (err) goto free_state; diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index c1dc632d4ea486ec9eab31203a6f684a5fc5e6dc..3460036621e4cc1216a823dc2746383f3c9dd1e8 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -184,7 +184,7 @@ all: $(LIBBPF) clean: $(MAKE) -C ../../ M=$(CURDIR) clean - @rm -f *~ + @find $(CURDIR) -type f -name '*~' -delete $(LIBBPF): FORCE $(MAKE) -C $(dir $@) $(notdir $@) diff --git a/scripts/Makefile b/scripts/Makefile index 25ab143cbe148b3fcd04432b77ceb929c0dc5d8f..c1d31dd3d760c67fd6f338ae40e27a314324ea6c 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -30,6 +30,8 @@ always := $(hostprogs-y) $(hostprogs-m) # The following hostprogs-y programs are only build on demand hostprogs-y += unifdef +extra-$(CONFIG_LTO_CLANG) += module-lto.lds + # These targets are used internally to avoid "is up to date" messages PHONY += build_unifdef build_unifdef: $(obj)/unifdef diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 8d5357053f8653d83e51f86d935341dd9f39f53d..486e135d3e30a57a9eb1d3b27139545161cc6df1 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -72,5 +72,6 @@ KBUILD_CFLAGS += $(call cc-disable-warning, format) KBUILD_CFLAGS += $(call cc-disable-warning, sign-compare) KBUILD_CFLAGS += $(call cc-disable-warning, format-zero-length) KBUILD_CFLAGS += $(call cc-disable-warning, uninitialized) +KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast) endif endif diff --git a/scripts/config b/scripts/config index e0e39826dae90ab735d1510e882bd32a9536e005..eee5b7f3a092ae4ac46bcdf92ffe8bb3c643aafd 100755 --- a/scripts/config +++ b/scripts/config @@ -7,6 +7,9 @@ myname=${0##*/} # If no prefix forced, use the default CONFIG_ CONFIG_="${CONFIG_-CONFIG_}" +# We use an uncommon delimiter for sed substitutions +SED_DELIM=$(echo -en "\001") + usage() { cat >&2 <"$tmpfile" + sed -e "s$SED_DELIM$before$SED_DELIM$after$SED_DELIM" "$infile" >"$tmpfile" # replace original file with the edited one mv "$tmpfile" "$infile" } diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index fd825ebba69cb25e160e057f53bef994970093fc..24af549977584c33b302a470fe90fd9b42e6539d 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -38,7 +38,6 @@ LINECOMMENT "//".*\n #include "srcpos.h" #include "dtc-parser.tab.h" -YYLTYPE yylloc; extern bool treesource_error; /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 64c243772398d614d7cd0a6ec9cfd0d6baeb8da3..9db3a409c5071a2eda0981648978f999d6dc200d 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -631,7 +631,6 @@ char *yytext; #include "srcpos.h" #include "dtc-parser.tab.h" -YYLTYPE yylloc; extern bool treesource_error; /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 27aac273205bacf5456680a914a024bbf36960e0..fa423fcd1a9285b12c024b8829f26ace0f2a99a0 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -1238,7 +1238,7 @@ bool conf_set_all_new_symbols(enum conf_def_mode mode) sym_calc_value(csym); if (mode == def_random) - has_changed = randomize_choice_values(csym); + has_changed |= randomize_choice_values(csym); else { set_all_choice_values(csym); has_changed = true; diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh index 67d1314476314590f285a63700c13e047dc17c80..b5115c6b22f602d35b618b19a51c06041c436232 100755 --- a/scripts/kconfig/merge_config.sh +++ b/scripts/kconfig/merge_config.sh @@ -151,7 +151,7 @@ fi # Use the merged file as the starting point for: # alldefconfig: Fills in any missing symbols with Kconfig default # allnoconfig: Fills in any missing symbols with # CONFIG_* is not set -make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET +make $MAKE_ARGS KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET # Check all specified config values took (might have missed-dependency issues) diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index 959199c3147ec79e2797e0c87cf47b0e03723a25..29a1589e2f0bcef277e5a21fe7b7ad90f052ae83 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -6,6 +6,7 @@ ARCH=$2 SMP=$3 PREEMPT=$4 CC=$5 +LD=$6 vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; } @@ -77,7 +78,10 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\" echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\" - echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//'`\" + CC_VERSION=$($CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//') + LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \ + | sed 's/[[:space:]]*$//') + printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION" ) > .tmpcompile # Only replace the real compile.h if the new one is different, diff --git a/scripts/module-lto.lds b/scripts/module-lto.lds deleted file mode 100644 index f5ee544a877d13f72ca12882bc16dab7a3eaa0bf..0000000000000000000000000000000000000000 --- a/scripts/module-lto.lds +++ /dev/null @@ -1,22 +0,0 @@ -/* - * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and - * -ffunction-sections, which increases the size of the final module. - * Merge the split sections in the final binary. - */ -SECTIONS { - /* - * LLVM may emit .eh_frame with CONFIG_CFI_CLANG despite - * -fno-asynchronous-unwind-tables. Discard the section. - */ - /DISCARD/ : { - *(.eh_frame) - } - - .bss : { *(.bss .bss[.0-9a-zA-Z_]*) } - .data : { *(.data .data[.0-9a-zA-Z_]*) } - .rela.data : { *(.rela.data .rela.data[.0-9a-zA-Z_]*) } - .rela.rodata : { *(.rela.rodata .rela.rodata[.0-9a-zA-Z_]*) } - .rela.text : { *(.rela.text .rela.text[.0-9a-zA-Z_]*) } - .rodata : { *(.rodata .rodata[.0-9a-zA-Z_]*) } - .text : { *(.text .text[.0-9a-zA-Z_]*) } -} diff --git a/scripts/module-lto.lds.S b/scripts/module-lto.lds.S new file mode 100644 index 0000000000000000000000000000000000000000..c0f4fdeb84a08334f8ff413ddc833fc2c0bfc6ca --- /dev/null +++ b/scripts/module-lto.lds.S @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include + +/* + * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and + * -ffunction-sections, which increases the size of the final module. + * Merge the split sections in the final binary. + */ +SECTIONS { + /* + * LLVM may emit .eh_frame with CONFIG_CFI_CLANG despite + * -fno-asynchronous-unwind-tables. Discard the section. + */ + /DISCARD/ : { + *(.eh_frame) + } + + .bss : { *(.bss .bss.[0-9a-zA-Z_]*) } + .data : { *(.data .data.[0-9a-zA-Z_]*) } + .rela.data : { *(.rela.data .rela.data.[0-9a-zA-Z_]*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.[0-9a-zA-Z_]*) } + .rela.text : { *(.rela.text .rela.text.[0-9a-zA-Z_]*) } + .rodata : { *(.rodata .rodata.[0-9a-zA-Z_]*) } + + /* + * With CFI_CLANG, ensure __cfi_check is at the beginning of the + * .text section, and that the section is aligned to page size. + */ + .text : ALIGN(PAGE_SIZE) { + *(.text.__cfi_check) + *(.text .text.[0-9a-zA-Z_]* .text..L.cfi*) + } + +} diff --git a/scripts/parse-maintainers.pl b/scripts/parse-maintainers.pl old mode 100644 new mode 100755 diff --git a/security/Kconfig b/security/Kconfig index daaf13e06d83d92ecaf69ff6f7d10879975da9e0..8b6c5e9528e03437e866ad2e4f4b92c7ba87991c 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -6,10 +6,6 @@ menu "Security options" source security/keys/Kconfig -if ARCH_QCOM -source security/pfe/Kconfig -endif - config SECURITY_DMESG_RESTRICT bool "Restrict unprivileged access to the kernel syslog" default n diff --git a/security/Makefile b/security/Makefile index 47bffaa3f5f8de2e2aaf1d3058ce7586f01ff8a2..4d2d3782ddefd3fbdd6d2984a1faa8a2bd6561ae 100644 --- a/security/Makefile +++ b/security/Makefile @@ -10,7 +10,6 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin -subdir-$(CONFIG_ARCH_QCOM) += pfe # always enable default capabilities obj-y += commoncap.o @@ -27,7 +26,6 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o -obj-$(CONFIG_ARCH_QCOM) += pfe/ # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 929e14978c421b227e592e937d9157ca2235b2f7..1957275ad2af38a1559baa67ca057301d8d78324 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -22,6 +22,13 @@ #include #include +struct big_key_buf { + unsigned int nr_pages; + void *virt; + struct scatterlist *sg; + struct page *pages[]; +}; + /* * Layout of key payload words. */ @@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock); /* * Encrypt/decrypt big_key data */ -static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) +static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key) { int ret; - struct scatterlist sgio; struct aead_request *aead_req; /* We always use a zero nonce. The reason we can get away with this is * because we're using a different randomly generated key for every @@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) return -ENOMEM; memset(zero_nonce, 0, sizeof(zero_nonce)); - sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); - aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); + aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce); aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); aead_request_set_ad(aead_req, 0); @@ -129,22 +134,82 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) return ret; } +/* + * Free up the buffer. + */ +static void big_key_free_buffer(struct big_key_buf *buf) +{ + unsigned int i; + + if (buf->virt) { + memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); + vunmap(buf->virt); + } + + for (i = 0; i < buf->nr_pages; i++) + if (buf->pages[i]) + __free_page(buf->pages[i]); + + kfree(buf); +} + +/* + * Allocate a buffer consisting of a set of pages with a virtual mapping + * applied over them. + */ +static void *big_key_alloc_buffer(size_t len) +{ + struct big_key_buf *buf; + unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned int i, l; + + buf = kzalloc(sizeof(struct big_key_buf) + + sizeof(struct page) * npg + + sizeof(struct scatterlist) * npg, + GFP_KERNEL); + if (!buf) + return NULL; + + buf->nr_pages = npg; + buf->sg = (void *)(buf->pages + npg); + sg_init_table(buf->sg, npg); + + for (i = 0; i < buf->nr_pages; i++) { + buf->pages[i] = alloc_page(GFP_KERNEL); + if (!buf->pages[i]) + goto nomem; + + l = min_t(size_t, len, PAGE_SIZE); + sg_set_page(&buf->sg[i], buf->pages[i], l, 0); + len -= l; + } + + buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); + if (!buf->virt) + goto nomem; + + return buf; + +nomem: + big_key_free_buffer(buf); + return NULL; +} + /* * Preparse a big key */ int big_key_preparse(struct key_preparsed_payload *prep) { + struct big_key_buf *buf; struct path *path = (struct path *)&prep->payload.data[big_key_path]; struct file *file; u8 *enckey; - u8 *data = NULL; ssize_t written; - size_t datalen = prep->datalen; + size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE; int ret; - ret = -EINVAL; if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) - goto error; + return -EINVAL; /* Set an arbitrary quota */ prep->quotalen = 16; @@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep) * * File content is stored encrypted with randomly generated key. */ - size_t enclen = datalen + ENC_AUTHTAG_SIZE; loff_t pos = 0; - data = kmalloc(enclen, GFP_KERNEL); - if (!data) + buf = big_key_alloc_buffer(enclen); + if (!buf) return -ENOMEM; - memcpy(data, prep->data, datalen); + memcpy(buf->virt, prep->data, datalen); /* generate random key */ enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); @@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) goto err_enckey; /* encrypt aligned data */ - ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); + ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey); if (ret) goto err_enckey; @@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) goto err_enckey; } - written = kernel_write(file, data, enclen, &pos); + written = kernel_write(file, buf->virt, enclen, &pos); if (written != enclen) { ret = written; if (written >= 0) @@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) *path = file->f_path; path_get(path); fput(file); - kzfree(data); + big_key_free_buffer(buf); } else { /* Just store the data in a buffer */ void *data = kmalloc(datalen, GFP_KERNEL); @@ -220,7 +284,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) err_enckey: kzfree(enckey); error: - kzfree(data); + big_key_free_buffer(buf); return ret; } @@ -289,7 +353,7 @@ void big_key_describe(const struct key *key, struct seq_file *m) * read the key data * - the key's semaphore is read-locked */ -long big_key_read(const struct key *key, char __user *buffer, size_t buflen) +long big_key_read(const struct key *key, char *buffer, size_t buflen) { size_t datalen = (size_t)key->payload.data[big_key_len]; long ret; @@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) return datalen; if (datalen > BIG_KEY_FILE_THRESHOLD) { + struct big_key_buf *buf; struct path *path = (struct path *)&key->payload.data[big_key_path]; struct file *file; - u8 *data; u8 *enckey = (u8 *)key->payload.data[big_key_data]; size_t enclen = datalen + ENC_AUTHTAG_SIZE; loff_t pos = 0; - data = kmalloc(enclen, GFP_KERNEL); - if (!data) + buf = big_key_alloc_buffer(enclen); + if (!buf) return -ENOMEM; file = dentry_open(path, O_RDONLY, current_cred()); @@ -316,31 +380,28 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) } /* read file to kernel and decrypt */ - ret = kernel_read(file, data, enclen, &pos); + ret = kernel_read(file, buf->virt, enclen, &pos); if (ret >= 0 && ret != enclen) { ret = -EIO; goto err_fput; } - ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); + ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey); if (ret) goto err_fput; ret = datalen; - /* copy decrypted data to user */ - if (copy_to_user(buffer, data, datalen) != 0) - ret = -EFAULT; + /* copy out decrypted data */ + memcpy(buffer, buf->virt, datalen); err_fput: fput(file); error: - kzfree(data); + big_key_free_buffer(buf); } else { ret = datalen; - if (copy_to_user(buffer, key->payload.data[big_key_data], - datalen) != 0) - ret = -EFAULT; + memcpy(buffer, key->payload.data[big_key_data], datalen); } return ret; diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index d92cbf9687c33f090865f6d0caa99d9936f49e3a..571f6d486838ec2af8af5fecc6928ac7b5fcd785 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -895,14 +895,14 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) } /* - * encrypted_read - format and copy the encrypted data to userspace + * encrypted_read - format and copy out the encrypted data * * The resulting datablob format is: * * * On success, return to userspace the encrypted key datablob size. */ -static long encrypted_read(const struct key *key, char __user *buffer, +static long encrypted_read(const struct key *key, char *buffer, size_t buflen) { struct encrypted_key_payload *epayload; @@ -950,8 +950,7 @@ static long encrypted_read(const struct key *key, char __user *buffer, key_put(mkey); memzero_explicit(derived_key, sizeof(derived_key)); - if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0) - ret = -EFAULT; + memcpy(buffer, ascii_buf, asciiblob_len); kzfree(ascii_buf); return asciiblob_len; diff --git a/security/keys/internal.h b/security/keys/internal.h index e3a573840186667bed09d8e1c790245abec34e67..7ed723d858499ea9cbe0a580e3fa2ea459f400f3 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -20,6 +20,8 @@ #include #include #include +#include +#include struct iovec; @@ -158,8 +160,6 @@ extern struct key *request_key_and_link(struct key_type *type, extern bool lookup_user_key_possessed(const struct key *key, const struct key_match_data *match_data); -extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, - key_perm_t perm); #define KEY_LOOKUP_CREATE 0x01 #define KEY_LOOKUP_PARTIAL 0x02 #define KEY_LOOKUP_FOR_UNLINK 0x04 @@ -305,4 +305,14 @@ static inline void key_check(const struct key *key) #endif +/* + * Helper function to clear and free a kvmalloc'ed memory object. + */ +static inline void __kvzfree(const void *addr, size_t len) +{ + if (addr) { + memset((void *)addr, 0, len); + kvfree(addr); + } +} #endif /* _INTERNAL_H */ diff --git a/security/keys/key.c b/security/keys/key.c index 17244f5f54c6987cafdb656b62a65d54e15dbb68..5f4cb271464a06bbb3a46fb33ed746d46dae4e5a 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -383,7 +383,7 @@ int key_payload_reserve(struct key *key, size_t datalen) spin_lock(&key->user->lock); if (delta > 0 && - (key->user->qnbytes + delta >= maxbytes || + (key->user->qnbytes + delta > maxbytes || key->user->qnbytes + delta < key->user->qnbytes)) { ret = -EDQUOT; } diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index ca31af186abd8a71aa2721d06ede9e7f30970974..c07c2e2b2478399328d3d8b445adc2d837079257 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -330,7 +330,7 @@ long keyctl_update_key(key_serial_t id, payload = NULL; if (plen) { ret = -ENOMEM; - payload = kmalloc(plen, GFP_KERNEL); + payload = kvmalloc(plen, GFP_KERNEL); if (!payload) goto error; @@ -351,7 +351,7 @@ long keyctl_update_key(key_serial_t id, key_ref_put(key_ref); error2: - kzfree(payload); + __kvzfree(payload, plen); error: return ret; } @@ -742,6 +742,21 @@ long keyctl_keyring_search(key_serial_t ringid, return ret; } +/* + * Call the read method + */ +static long __keyctl_read_key(struct key *key, char *buffer, size_t buflen) +{ + long ret; + + down_read(&key->sem); + ret = key_validate(key); + if (ret == 0) + ret = key->type->read(key, buffer, buflen); + up_read(&key->sem); + return ret; +} + /* * Read a key's payload. * @@ -757,26 +772,28 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) struct key *key; key_ref_t key_ref; long ret; + char *key_data = NULL; + size_t key_data_len; /* find the key first */ key_ref = lookup_user_key(keyid, 0, 0); if (IS_ERR(key_ref)) { ret = -ENOKEY; - goto error; + goto out; } key = key_ref_to_ptr(key_ref); ret = key_read_state(key); if (ret < 0) - goto error2; /* Negatively instantiated */ + goto key_put_out; /* Negatively instantiated */ /* see if we can read it directly */ ret = key_permission(key_ref, KEY_NEED_READ); if (ret == 0) goto can_read_key; if (ret != -EACCES) - goto error2; + goto key_put_out; /* we can't; see if it's searchable from this process's keyrings * - we automatically take account of the fact that it may be @@ -784,26 +801,78 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) */ if (!is_key_possessed(key_ref)) { ret = -EACCES; - goto error2; + goto key_put_out; } /* the key is probably readable - now try to read it */ can_read_key: - ret = -EOPNOTSUPP; - if (key->type->read) { - /* Read the data with the semaphore held (since we might sleep) - * to protect against the key being updated or revoked. + if (!key->type->read) { + ret = -EOPNOTSUPP; + goto key_put_out; + } + + if (!buffer || !buflen) { + /* Get the key length from the read method */ + ret = __keyctl_read_key(key, NULL, 0); + goto key_put_out; + } + + /* + * Read the data with the semaphore held (since we might sleep) + * to protect against the key being updated or revoked. + * + * Allocating a temporary buffer to hold the keys before + * transferring them to user buffer to avoid potential + * deadlock involving page fault and mmap_sem. + * + * key_data_len = (buflen <= PAGE_SIZE) + * ? buflen : actual length of key data + * + * This prevents allocating arbitrary large buffer which can + * be much larger than the actual key length. In the latter case, + * at least 2 passes of this loop is required. + */ + key_data_len = (buflen <= PAGE_SIZE) ? buflen : 0; + for (;;) { + if (key_data_len) { + key_data = kvmalloc(key_data_len, GFP_KERNEL); + if (!key_data) { + ret = -ENOMEM; + goto key_put_out; + } + } + + ret = __keyctl_read_key(key, key_data, key_data_len); + + /* + * Read methods will just return the required length without + * any copying if the provided length isn't large enough. + */ + if (ret <= 0 || ret > buflen) + break; + + /* + * The key may change (unlikely) in between 2 consecutive + * __keyctl_read_key() calls. In this case, we reallocate + * a larger buffer and redo the key read when + * key_data_len < ret <= buflen. */ - down_read(&key->sem); - ret = key_validate(key); - if (ret == 0) - ret = key->type->read(key, buffer, buflen); - up_read(&key->sem); + if (ret > key_data_len) { + if (unlikely(key_data)) + __kvzfree(key_data, key_data_len); + key_data_len = ret; + continue; /* Allocate buffer */ + } + + if (copy_to_user(buffer, key_data, ret)) + ret = -EFAULT; + break; } + __kvzfree(key_data, key_data_len); -error2: +key_put_out: key_put(key); -error: +out: return ret; } @@ -882,8 +951,8 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) key_quota_root_maxbytes : key_quota_maxbytes; spin_lock(&newowner->lock); - if (newowner->qnkeys + 1 >= maxkeys || - newowner->qnbytes + key->quotalen >= maxbytes || + if (newowner->qnkeys + 1 > maxkeys || + newowner->qnbytes + key->quotalen > maxbytes || newowner->qnbytes + key->quotalen < newowner->qnbytes) goto quota_overrun; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 359b9cba3d0de894c7914c41b7a48b4213259a8f..f7cf371bcd2a8588f56e059ba6ab548c9d60063b 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -432,7 +432,6 @@ static int keyring_read_iterator(const void *object, void *data) { struct keyring_read_iterator_context *ctx = data; const struct key *key = keyring_ptr_to_key(object); - int ret; kenter("{%s,%d},,{%zu/%zu}", key->type->name, key->serial, ctx->count, ctx->buflen); @@ -440,10 +439,7 @@ static int keyring_read_iterator(const void *object, void *data) if (ctx->count >= ctx->buflen) return 1; - ret = put_user(key->serial, ctx->buffer); - if (ret < 0) - return ret; - ctx->buffer++; + *ctx->buffer++ = key->serial; ctx->count += sizeof(key->serial); return 0; } diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 5f2993ab2d504cf1a1415ae91233d0d7643383bb..8968a3db1add914b3f3037f5c744d4f4a4acf354 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -756,6 +756,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, put_cred(ctx.cred); goto try_again; } +EXPORT_SYMBOL(lookup_user_key); /* * Join the named keyring as the session keyring if possible else attempt to diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 1d34b2a5f485e2380e8b092cfb62955434c3f908..13ac3b1e57da61ea6bb8af8f46c875fe61e38a7d 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -27,7 +27,7 @@ static int request_key_auth_instantiate(struct key *, static void request_key_auth_describe(const struct key *, struct seq_file *); static void request_key_auth_revoke(struct key *); static void request_key_auth_destroy(struct key *); -static long request_key_auth_read(const struct key *, char __user *, size_t); +static long request_key_auth_read(const struct key *, char *, size_t); /* * The request-key authorisation key type definition. @@ -85,7 +85,7 @@ static void request_key_auth_describe(const struct key *key, * - the key's semaphore is read-locked */ static long request_key_auth_read(const struct key *key, - char __user *buffer, size_t buflen) + char *buffer, size_t buflen) { struct request_key_auth *rka = get_request_key_auth(key); size_t datalen; @@ -102,8 +102,7 @@ static long request_key_auth_read(const struct key *key, if (buflen > datalen) buflen = datalen; - if (copy_to_user(buffer, rka->callout_info, buflen) != 0) - ret = -EFAULT; + memcpy(buffer, rka->callout_info, buflen); } return ret; diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 98aa89ff7bfd9ed57662116ca455f3a5628ec380..01e8544f79a539b7ded48c9c17fc88348f9e6bac 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -1136,11 +1136,10 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) * trusted_read - copy the sealed blob data to userspace in hex. * On success, return to userspace the trusted key datablob size. */ -static long trusted_read(const struct key *key, char __user *buffer, +static long trusted_read(const struct key *key, char *buffer, size_t buflen) { const struct trusted_key_payload *p; - char *ascii_buf; char *bufp; int i; @@ -1149,18 +1148,9 @@ static long trusted_read(const struct key *key, char __user *buffer, return -EINVAL; if (buffer && buflen >= 2 * p->blob_len) { - ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL); - if (!ascii_buf) - return -ENOMEM; - - bufp = ascii_buf; + bufp = buffer; for (i = 0; i < p->blob_len; i++) bufp = hex_byte_pack(bufp, p->blob[i]); - if (copy_to_user(buffer, ascii_buf, 2 * p->blob_len) != 0) { - kzfree(ascii_buf); - return -EFAULT; - } - kzfree(ascii_buf); } return 2 * p->blob_len; } diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 9f558bedba23a338da5980ab11dd1b716c7b0b67..0e723b676aef1c7e5bfcb4abf6d75e531513b2da 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -172,7 +172,7 @@ EXPORT_SYMBOL_GPL(user_describe); * read the key data * - the key's semaphore is read-locked */ -long user_read(const struct key *key, char __user *buffer, size_t buflen) +long user_read(const struct key *key, char *buffer, size_t buflen) { const struct user_key_payload *upayload; long ret; @@ -185,8 +185,7 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen) if (buflen > upayload->datalen) buflen = upayload->datalen; - if (copy_to_user(buffer, upayload->data, buflen) != 0) - ret = -EFAULT; + memcpy(buffer, upayload->data, buflen); } return ret; diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig deleted file mode 100644 index 923fe1cd99871803b1ab7697aec637b9f852d3cd..0000000000000000000000000000000000000000 --- a/security/pfe/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -menu "Qualcomm Technologies, Inc Per File Encryption security device drivers" - depends on ARCH_QCOM - -config PFT - bool "Per-File-Tagger driver" - depends on SECURITY - default n - help - This driver is used for tagging enterprise files. - It is part of the Per-File-Encryption (PFE) feature. - The driver is tagging files when created by - registered application. - Tagged files are encrypted using the dm-req-crypt driver. - -config PFK - bool "Per-File-Key driver" - depends on SECURITY - depends on SECURITY_SELINUX - default n - help - This driver is used for storing eCryptfs information - in file node. - This is part of eCryptfs hardware enhanced solution - provided by Qualcomm Technologies, Inc. - Information is used when file is encrypted later using - ICE or dm crypto engine - -config PFK_WRAPPED_KEY_SUPPORTED - bool "Per-File-Key driver with wrapped key support" - depends on SECURITY - depends on SECURITY_SELINUX - depends on QSEECOM - depends on PFK - default n - help - Adds wrapped key support in PFK driver. Instead of setting - the key directly in ICE, it unwraps the key and sets the key - in ICE. - -config PFK_VIRTUALIZED - bool "Per-File-Key driver virtualized version" - depends on SECURITY - depends on SECURITY_SELINUX - depends on QSEECOM - depends on PFK - depends on MSM_HAB - help - Makes the driver to use the hypervisor back end for ICE HW - operation virtualization instead of calling directly to TZ. -endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile deleted file mode 100644 index c95f02a46bbae22f27e0ebf0e5d4c745ab4dc0b8..0000000000000000000000000000000000000000 --- a/security/pfe/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for the MSM specific security device drivers. -# - -ccflags-y += -Isecurity/selinux -Isecurity/selinux/include -ccflags-y += -Ifs/crypto -ccflags-y += -Idrivers/misc - -obj-$(CONFIG_PFT) += pft.o -obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ext4.o pfk_f2fs.o -ifdef CONFIG_PFK_VIRTUALIZED -obj-$(CONFIG_PFK_VIRTUALIZED) += pfk_ice_virt.o -else -obj-$(CONFIG_PFK) += pfk_ice.o -endif diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c deleted file mode 100644 index ae681487248cc9fd9dcc24dad71d8e21f18a26db..0000000000000000000000000000000000000000 --- a/security/pfe/pfk.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * Per-File-Key (PFK). - * - * This driver is responsible for overall management of various - * Per File Encryption variants that work on top of or as part of different - * file systems. - * - * The driver has the following purpose : - * 1) Define priorities between PFE's if more than one is enabled - * 2) Extract key information from inode - * 3) Load and manage various keys in ICE HW engine - * 4) It should be invoked from various layers in FS/BLOCK/STORAGE DRIVER - * that need to take decision on HW encryption management of the data - * Some examples: - * BLOCK LAYER: when it takes decision on whether 2 chunks can be united - * to one encryption / decryption request sent to the HW - * - * UFS DRIVER: when it need to configure ICE HW with a particular key slot - * to be used for encryption / decryption - * - * PFE variants can differ on particular way of storing the cryptographic info - * inside inode, actions to be taken upon file operations, etc., but the common - * properties are described above - * - */ - - -/* Uncomment the line below to enable debug messages */ -/* #define DEBUG 1 */ -#define pr_fmt(fmt) "pfk [%s]: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "pfk_kc.h" -#include "objsec.h" -#include "pfk_ice.h" -#include "pfk_ext4.h" -#include "pfk_f2fs.h" -#include "pfk_internal.h" - -static bool pfk_ready; - - -/* might be replaced by a table when more than one cipher is supported */ -#define PFK_SUPPORTED_KEY_SIZE 32 -#define PFK_SUPPORTED_SALT_SIZE 32 - -/* Various PFE types and function tables to support each one of them */ -enum pfe_type {EXT4_CRYPT_PFE, F2FS_CRYPT_PFE, INVALID_PFE}; - -typedef int (*pfk_parse_inode_type)(const struct bio *bio, - const struct inode *inode, - struct pfk_key_info *key_info, - enum ice_cryto_algo_mode *algo, - bool *is_pfe); - -typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, - const struct bio *bio2, const struct inode *inode1, - const struct inode *inode2); - -static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { - /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, - /* F2FS_CRYPT_PFE */ &pfk_f2fs_parse_inode, -}; - -static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { - /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, - /* F2FS_CRYPT_PFE */ &pfk_f2fs_allow_merge_bio, -}; - -static void __exit pfk_exit(void) -{ - pfk_ready = false; - pfk_ext4_deinit(); - pfk_f2fs_deinit(); - pfk_kc_deinit(); -} - -static int __init pfk_init(void) -{ - - int ret = 0; - - ret = pfk_ext4_init(); - if (ret != 0) - goto fail; - - ret = pfk_f2fs_init(); - if (ret != 0) - goto fail; - - ret = pfk_kc_init(true); - if (ret != 0 && ret != -EAGAIN) { - pr_err("could init pfk key cache, error %d\n", ret); - pfk_ext4_deinit(); - pfk_f2fs_deinit(); - goto fail; - } - - pfk_ready = true; - pr_info("Driver initialized successfully\n"); - - return 0; - -fail: - pr_err("Failed to init driver\n"); - return -ENODEV; -} - -/* - * If more than one type is supported simultaneously, this function will also - * set the priority between them - */ -static enum pfe_type pfk_get_pfe_type(const struct inode *inode) -{ - if (!inode) - return INVALID_PFE; - - if (pfk_is_ext4_type(inode)) - return EXT4_CRYPT_PFE; - - if (pfk_is_f2fs_type(inode)) - return F2FS_CRYPT_PFE; - - return INVALID_PFE; -} - -/** - * inode_to_filename() - get the filename from inode pointer. - * @inode: inode pointer - * - * it is used for debug prints. - * - * Return: filename string or "unknown". - */ -char *inode_to_filename(const struct inode *inode) -{ - struct dentry *dentry = NULL; - char *filename = NULL; - - if (!inode) - return "NULL"; - - if (hlist_empty(&inode->i_dentry)) - return "unknown"; - - dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); - filename = dentry->d_iname; - - return filename; -} - -/** - * pfk_is_ready() - driver is initialized and ready. - * - * Return: true if the driver is ready. - */ -static inline bool pfk_is_ready(void) -{ - return pfk_ready; -} - -/** - * pfk_bio_get_inode() - get the inode from a bio. - * @bio: Pointer to BIO structure. - * - * Walk the bio struct links to get the inode. - * Please note, that in general bio may consist of several pages from - * several files, but in our case we always assume that all pages come - * from the same file, since our logic ensures it. That is why we only - * walk through the first page to look for inode. - * - * Return: pointer to the inode struct if successful, or NULL otherwise. - * - */ -static struct inode *pfk_bio_get_inode(const struct bio *bio) -{ - struct address_space *mapping = NULL; - - if (!bio) - return NULL; - if (!bio_has_data((struct bio *)bio)) - return NULL; - if (!bio->bi_io_vec) - return NULL; - if (!bio->bi_io_vec->bv_page) - return NULL; - - if (PageAnon(bio->bi_io_vec->bv_page)) { - struct inode *inode; - - /* Using direct-io (O_DIRECT) without page cache */ - inode = dio_bio_get_inode((struct bio *)bio); - pr_debug("inode on direct-io, inode = 0x%pK.\n", inode); - - return inode; - } - - mapping = page_mapping(bio->bi_io_vec->bv_page); - if (!mapping) - return NULL; - - return mapping->host; -} - -/** - * pfk_key_size_to_key_type() - translate key size to key size enum - * @key_size: key size in bytes - * @key_size_type: pointer to store the output enum (can be null) - * - * return 0 in case of success, error otherwise (i.e not supported key size) - */ -int pfk_key_size_to_key_type(size_t key_size, - enum ice_crpto_key_size *key_size_type) -{ - /* - * currently only 32 bit key size is supported - * in the future, table with supported key sizes might - * be introduced - */ - - if (key_size != PFK_SUPPORTED_KEY_SIZE) { - pr_err("not supported key size %zu\n", key_size); - return -EINVAL; - } - - if (key_size_type) - *key_size_type = ICE_CRYPTO_KEY_SIZE_256; - - return 0; -} - -/* - * Retrieves filesystem type from inode's superblock - */ -bool pfe_is_inode_filesystem_type(const struct inode *inode, - const char *fs_type) -{ - if (!inode || !fs_type) - return false; - - if (!inode->i_sb) - return false; - - if (!inode->i_sb->s_type) - return false; - - return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); -} - -/** - * pfk_get_key_for_bio() - get the encryption key to be used for a bio - * - * @bio: pointer to the BIO - * @key_info: pointer to the key information which will be filled in - * @algo_mode: optional pointer to the algorithm identifier which will be set - * @is_pfe: will be set to false if the BIO should be left unencrypted - * - * Return: 0 if a key is being used, otherwise a -errno value - */ -static int pfk_get_key_for_bio(const struct bio *bio, - struct pfk_key_info *key_info, - enum ice_cryto_algo_mode *algo_mode, - bool *is_pfe, unsigned int *data_unit) -{ - const struct inode *inode; - enum pfe_type which_pfe; - const struct blk_encryption_key *key = NULL; - char *s_type = NULL; - - inode = pfk_bio_get_inode(bio); - which_pfe = pfk_get_pfe_type(inode); - s_type = (char *)pfk_kc_get_storage_type(); - - /* - * Update dun based on storage type. - * 512 byte dun - For ext4 emmc - * 4K dun - For ext4 ufs, f2fs ufs and f2fs emmc - */ - - if (data_unit && bio) { - if (!bio_dun(bio) && !memcmp(s_type, "sdcc", strlen("sdcc"))) - *data_unit = 1 << ICE_CRYPTO_DATA_UNIT_512_B; - else - *data_unit = 1 << ICE_CRYPTO_DATA_UNIT_4_KB; - } - - if (which_pfe != INVALID_PFE) { - /* Encrypted file; override ->bi_crypt_key */ - pr_debug("parsing inode %lu with PFE type %d\n", - inode->i_ino, which_pfe); - return (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, key_info, algo_mode, is_pfe); - } - - /* - * bio is not for an encrypted file. Use ->bi_crypt_key if it was set. - * Otherwise, don't encrypt/decrypt the bio. - */ -#ifdef CONFIG_DM_DEFAULT_KEY - key = bio->bi_crypt_key; -#endif - if (!key) { - *is_pfe = false; - return -EINVAL; - } - - /* Note: the "salt" is really just the second half of the XTS key. */ - BUILD_BUG_ON(sizeof(key->raw) != - PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE); - key_info->key = &key->raw[0]; - key_info->key_size = PFK_SUPPORTED_KEY_SIZE; - key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE]; - key_info->salt_size = PFK_SUPPORTED_SALT_SIZE; - if (algo_mode) - *algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; - return 0; -} - - -/** - * pfk_load_key_start() - loads PFE encryption key to the ICE - * Can also be invoked from non - * PFE context, in this case it - * is not relevant and is_pfe - * flag is set to false - * - * @bio: Pointer to the BIO structure - * @ice_setting: Pointer to ice setting structure that will be filled with - * ice configuration values, including the index to which the key was loaded - * @is_pfe: will be false if inode is not relevant to PFE, in such a case - * it should be treated as non PFE by the block layer - * - * Returns the index where the key is stored in encryption hw and additional - * information that will be used later for configuration of the encryption hw. - * - * Must be followed by pfk_load_key_end when key is no longer used by ice - * - */ -int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, bool *is_pfe, - bool async) -{ - int ret = 0; - struct pfk_key_info key_info = {NULL, NULL, 0, 0}; - enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; - enum ice_crpto_key_size key_size_type = 0; - unsigned int data_unit = 1 << ICE_CRYPTO_DATA_UNIT_512_B; - u32 key_index = 0; - - if (!is_pfe) { - pr_err("is_pfe is NULL\n"); - return -EINVAL; - } - - /* - * only a few errors below can indicate that - * this function was not invoked within PFE context, - * otherwise we will consider it PFE - */ - *is_pfe = true; - - if (!pfk_is_ready()) - return -ENODEV; - - if (!ice_setting) { - pr_err("ice setting is NULL\n"); - return -EINVAL; - } - - ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe, - &data_unit); - - if (ret != 0) - return ret; - - ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type); - if (ret != 0) - return ret; - - ret = pfk_kc_load_key_start(key_info.key, key_info.key_size, - key_info.salt, key_info.salt_size, &key_index, async, - data_unit); - if (ret) { - if (ret != -EBUSY && ret != -EAGAIN) - pr_err("start: could not load key into pfk key cache, error %d\n", - ret); - - return ret; - } - - ice_setting->key_size = key_size_type; - ice_setting->algo_mode = algo_mode; - /* hardcoded for now */ - ice_setting->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY; - ice_setting->key_index = key_index; - - pr_debug("loaded key for file %s key_index %d\n", - inode_to_filename(pfk_bio_get_inode(bio)), key_index); - - return 0; -} - -/** - * pfk_load_key_end() - marks the PFE key as no longer used by ICE - * Can also be invoked from non - * PFE context, in this case it is not - * relevant and is_pfe flag is - * set to false - * - * @bio: Pointer to the BIO structure - * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked - * from PFE context - */ -int pfk_load_key_end(const struct bio *bio, bool *is_pfe) -{ - int ret = 0; - struct pfk_key_info key_info = {NULL, NULL, 0, 0}; - - if (!is_pfe) { - pr_err("is_pfe is NULL\n"); - return -EINVAL; - } - - /* only a few errors below can indicate that - * this function was not invoked within PFE context, - * otherwise we will consider it PFE - */ - *is_pfe = true; - - if (!pfk_is_ready()) - return -ENODEV; - - ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe, NULL); - if (ret != 0) - return ret; - - pfk_kc_load_key_end(key_info.key, key_info.key_size, - key_info.salt, key_info.salt_size); - - pr_debug("finished using key for file %s\n", - inode_to_filename(pfk_bio_get_inode(bio))); - - return 0; -} - -/** - * pfk_allow_merge_bio() - Check if 2 BIOs can be merged. - * @bio1: Pointer to first BIO structure. - * @bio2: Pointer to second BIO structure. - * - * Prevent merging of BIOs from encrypted and non-encrypted - * files, or files encrypted with different key. - * Also prevent non encrypted and encrypted data from the same file - * to be merged (ecryptfs header if stored inside file should be non - * encrypted) - * This API is called by the file system block layer. - * - * Return: true if the BIOs allowed to be merged, false - * otherwise. - */ -bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) -{ - const struct blk_encryption_key *key1 = NULL; - const struct blk_encryption_key *key2 = NULL; - const struct inode *inode1; - const struct inode *inode2; - enum pfe_type which_pfe1; - enum pfe_type which_pfe2; - -#ifdef CONFIG_DM_DEFAULT_KEY - key1 = bio1->bi_crypt_key; - key2 = bio2->bi_crypt_key; -#endif - - if (!pfk_is_ready()) - return false; - - if (!bio1 || !bio2) - return false; - - if (bio1 == bio2) - return true; - - key1 = bio1->bi_crypt_key; - key2 = bio2->bi_crypt_key; - - inode1 = pfk_bio_get_inode(bio1); - inode2 = pfk_bio_get_inode(bio2); - - which_pfe1 = pfk_get_pfe_type(inode1); - which_pfe2 = pfk_get_pfe_type(inode2); - - /* - * If one bio is for an encrypted file and the other is for a different - * type of encrypted file or for blocks that are not part of an - * encrypted file, do not merge. - */ - if (which_pfe1 != which_pfe2) - return false; - - if (which_pfe1 != INVALID_PFE) { - /* Both bios are for the same type of encrypted file. */ - return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, - inode1, inode2); - } - - /* - * Neither bio is for an encrypted file. Merge only if the default keys - * are the same (or both are NULL). - */ - return key1 == key2 || - (key1 && key2 && - !crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw))); -} - -int pfk_fbe_clear_key(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size) -{ - int ret = -EINVAL; - - if (!key || !salt) - return ret; - - ret = pfk_kc_remove_key_with_salt(key, key_size, salt, salt_size); - if (ret) - pr_err("Clear key error: ret value %d\n", ret); - return ret; -} - -/** - * Flush key table on storage core reset. During core reset key configuration - * is lost in ICE. We need to flash the cache, so that the keys will be - * reconfigured again for every subsequent transaction - */ -void pfk_clear_on_reset(void) -{ - if (!pfk_is_ready()) - return; - - pfk_kc_clear_on_reset(); -} - -module_init(pfk_init); -module_exit(pfk_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Per-File-Key driver"); diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c deleted file mode 100644 index 0eb122565ecc047e3c8244fa1073b0a5cc8c4591..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_ext4.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * Per-File-Key (PFK) - EXT4 - * - * This driver is used for working with EXT4 crypt extension - * - * The key information is stored in node by EXT4 when file is first opened - * and will be later accessed by Block Device Driver to actually load the key - * to encryption hw. - * - * PFK exposes API's for loading and removing keys from encryption hw - * and also API to determine whether 2 adjacent blocks can be agregated by - * Block Layer in one request to encryption hw. - * - */ - - -/* Uncomment the line below to enable debug messages */ -/* #define DEBUG 1 */ -#define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__ - -#include -#include -#include -#include - -#include "fscrypt_ice.h" -#include "pfk_ext4.h" -//#include "ext4_ice.h" - -static bool pfk_ext4_ready; - -/* - * pfk_ext4_deinit() - Deinit function, should be invoked by upper PFK layer - */ -void pfk_ext4_deinit(void) -{ - pfk_ext4_ready = false; -} - -/* - * pfk_ecryptfs_init() - Init function, should be invoked by upper PFK layer - */ -int __init pfk_ext4_init(void) -{ - pfk_ext4_ready = true; - pr_info("PFK EXT4 inited successfully\n"); - - return 0; -} - -/** - * pfk_ecryptfs_is_ready() - driver is initialized and ready. - * - * Return: true if the driver is ready. - */ -static inline bool pfk_ext4_is_ready(void) -{ - return pfk_ext4_ready; -} - -/** - * pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen - * - * - */ -/* - * static void pfk_ext4_dump_inode(const struct inode* inode) - * { - * struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode); - * - * pr_debug("dumping inode with address 0x%p\n", inode); - * pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode)); - * pr_debug("EXT4_INODE_ENCRYPT flag is %d\n", - * ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT)); - * if (ci) { - * pr_debug("crypt_info address 0x%p\n", ci); - * pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode); - * } else { - * pr_debug("crypt_info is NULL\n"); - * } - * } - */ - -/** - * pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE - * @inode: inode pointer - */ -bool pfk_is_ext4_type(const struct inode *inode) -{ - if (!pfe_is_inode_filesystem_type(inode, "ext4")) - return false; - - return fscrypt_should_be_processed_by_ice(inode); -} - -/** - * pfk_ext4_parse_cipher() - parse cipher from inode to enum - * @inode: inode - * @algo: pointer to store the output enum (can be null) - * - * return 0 in case of success, error otherwise (i.e not supported cipher) - */ -static int pfk_ext4_parse_cipher(const struct inode *inode, - enum ice_cryto_algo_mode *algo) -{ - /* - * currently only AES XTS algo is supported - * in the future, table with supported ciphers might - * be introduced - */ - - if (!inode) - return -EINVAL; - - if (!fscrypt_is_aes_xts_cipher(inode)) { - pr_err("ext4 alghoritm is not supported by pfk\n"); - return -EINVAL; - } - - if (algo) - *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; - - return 0; -} - - -int pfk_ext4_parse_inode(const struct bio *bio, - const struct inode *inode, - struct pfk_key_info *key_info, - enum ice_cryto_algo_mode *algo, - bool *is_pfe) -{ - int ret = 0; - - if (!is_pfe) - return -EINVAL; - - /* - * only a few errors below can indicate that - * this function was not invoked within PFE context, - * otherwise we will consider it PFE - */ - *is_pfe = true; - - if (!pfk_ext4_is_ready()) - return -ENODEV; - - if (!inode) - return -EINVAL; - - if (!key_info) - return -EINVAL; - - key_info->key = fscrypt_get_ice_encryption_key(inode); - if (!key_info->key) { - pr_err("could not parse key from ext4\n"); - return -EINVAL; - } - - key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); - if (!key_info->key_size) { - pr_err("could not parse key size from ext4\n"); - return -EINVAL; - } - - key_info->salt = fscrypt_get_ice_encryption_salt(inode); - if (!key_info->salt) { - pr_err("could not parse salt from ext4\n"); - return -EINVAL; - } - - key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); - if (!key_info->salt_size) { - pr_err("could not parse salt size from ext4\n"); - return -EINVAL; - } - - ret = pfk_ext4_parse_cipher(inode, algo); - if (ret != 0) { - pr_err("not supported cipher\n"); - return ret; - } - - return 0; -} - -bool pfk_ext4_allow_merge_bio(const struct bio *bio1, - const struct bio *bio2, const struct inode *inode1, - const struct inode *inode2) -{ - /* if there is no ext4 pfk, don't disallow merging blocks */ - if (!pfk_ext4_is_ready()) - return true; - - if (!inode1 || !inode2) - return false; - - return fscrypt_is_ice_encryption_info_equal(inode1, inode2); -} diff --git a/security/pfe/pfk_ext4.h b/security/pfe/pfk_ext4.h deleted file mode 100644 index c33232f35a1474e6dae4a8f39a884b638c369b46..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_ext4.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _PFK_EXT4_H_ -#define _PFK_EXT4_H_ - -#include -#include -#include -#include "pfk_internal.h" - -bool pfk_is_ext4_type(const struct inode *inode); - -int pfk_ext4_parse_inode(const struct bio *bio, - const struct inode *inode, - struct pfk_key_info *key_info, - enum ice_cryto_algo_mode *algo, - bool *is_pfe); - -bool pfk_ext4_allow_merge_bio(const struct bio *bio1, - const struct bio *bio2, const struct inode *inode1, - const struct inode *inode2); - -int __init pfk_ext4_init(void); - -void pfk_ext4_deinit(void); - -#endif /* _PFK_EXT4_H_ */ diff --git a/security/pfe/pfk_f2fs.c b/security/pfe/pfk_f2fs.c deleted file mode 100644 index 8b9d515043e8693291fd2c44f5d168f4b3ae62e1..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_f2fs.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * Per-File-Key (PFK) - f2fs - * - * This driver is used for working with EXT4/F2FS crypt extension - * - * The key information is stored in node by EXT4/F2FS when file is first opened - * and will be later accessed by Block Device Driver to actually load the key - * to encryption hw. - * - * PFK exposes API's for loading and removing keys from encryption hw - * and also API to determine whether 2 adjacent blocks can be agregated by - * Block Layer in one request to encryption hw. - * - */ - - -/* Uncomment the line below to enable debug messages */ -#define DEBUG 1 -#define pr_fmt(fmt) "pfk_f2fs [%s]: " fmt, __func__ - -#include -#include -#include -#include - -#include "fscrypt_ice.h" -#include "pfk_f2fs.h" - -static bool pfk_f2fs_ready; - -/* - * pfk_f2fs_deinit() - Deinit function, should be invoked by upper PFK layer - */ -void pfk_f2fs_deinit(void) -{ - pfk_f2fs_ready = false; -} - -/* - * pfk_f2fs_init() - Init function, should be invoked by upper PFK layer - */ -int __init pfk_f2fs_init(void) -{ - pfk_f2fs_ready = true; - pr_info("PFK F2FS inited successfully\n"); - - return 0; -} - -/** - * pfk_f2fs_is_ready() - driver is initialized and ready. - * - * Return: true if the driver is ready. - */ -static inline bool pfk_f2fs_is_ready(void) -{ - return pfk_f2fs_ready; -} - -/** - * pfk_is_f2fs_type() - return true if inode belongs to ICE F2FS PFE - * @inode: inode pointer - */ -bool pfk_is_f2fs_type(const struct inode *inode) -{ - if (!pfe_is_inode_filesystem_type(inode, "f2fs")) - return false; - - return fscrypt_should_be_processed_by_ice(inode); -} - -/** - * pfk_f2fs_parse_cipher() - parse cipher from inode to enum - * @inode: inode - * @algo: pointer to store the output enum (can be null) - * - * return 0 in case of success, error otherwise (i.e not supported cipher) - */ -static int pfk_f2fs_parse_cipher(const struct inode *inode, - enum ice_cryto_algo_mode *algo) -{ - /* - * currently only AES XTS algo is supported - * in the future, table with supported ciphers might - * be introduced - */ - if (!inode) - return -EINVAL; - - if (!fscrypt_is_aes_xts_cipher(inode)) { - pr_err("f2fs alghoritm is not supported by pfk\n"); - return -EINVAL; - } - - if (algo) - *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; - - return 0; -} - - -int pfk_f2fs_parse_inode(const struct bio *bio, - const struct inode *inode, - struct pfk_key_info *key_info, - enum ice_cryto_algo_mode *algo, - bool *is_pfe) -{ - int ret = 0; - - if (!is_pfe) - return -EINVAL; - - /* - * only a few errors below can indicate that - * this function was not invoked within PFE context, - * otherwise we will consider it PFE - */ - *is_pfe = true; - - if (!pfk_f2fs_is_ready()) - return -ENODEV; - - if (!inode) - return -EINVAL; - - if (!key_info) - return -EINVAL; - - key_info->key = fscrypt_get_ice_encryption_key(inode); - if (!key_info->key) { - pr_err("could not parse key from f2fs\n"); - return -EINVAL; - } - - key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); - if (!key_info->key_size) { - pr_err("could not parse key size from f2fs\n"); - return -EINVAL; - } - - key_info->salt = fscrypt_get_ice_encryption_salt(inode); - if (!key_info->salt) { - pr_err("could not parse salt from f2fs\n"); - return -EINVAL; - } - - key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); - if (!key_info->salt_size) { - pr_err("could not parse salt size from f2fs\n"); - return -EINVAL; - } - - ret = pfk_f2fs_parse_cipher(inode, algo); - if (ret != 0) { - pr_err("not supported cipher\n"); - return ret; - } - - return 0; -} - -bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, - const struct bio *bio2, const struct inode *inode1, - const struct inode *inode2) -{ - bool mergeable; - - /* if there is no f2fs pfk, don't disallow merging blocks */ - if (!pfk_f2fs_is_ready()) - return true; - - if (!inode1 || !inode2) - return false; - - mergeable = fscrypt_is_ice_encryption_info_equal(inode1, inode2); - if (!mergeable) - return false; - - - /* ICE allows only consecutive iv_key stream. */ - if (!bio_dun(bio1) && !bio_dun(bio2)) - return true; - else if (!bio_dun(bio1) || !bio_dun(bio2)) - return false; - - return bio_end_dun(bio1) == bio_dun(bio2); -} diff --git a/security/pfe/pfk_f2fs.h b/security/pfe/pfk_f2fs.h deleted file mode 100644 index 551d529bced6afb58bdb66be95d8552925e7864b..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_f2fs.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _PFK_F2FS_H_ -#define _PFK_F2FS_H_ - -#include -#include -#include -#include "pfk_internal.h" - -bool pfk_is_f2fs_type(const struct inode *inode); - -int pfk_f2fs_parse_inode(const struct bio *bio, - const struct inode *inode, - struct pfk_key_info *key_info, - enum ice_cryto_algo_mode *algo, - bool *is_pfe); - -bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, - const struct bio *bio2, const struct inode *inode1, - const struct inode *inode2); - -int __init pfk_f2fs_init(void); - -void pfk_f2fs_deinit(void); - -#endif /* _PFK_F2FS_H_ */ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c deleted file mode 100644 index b627c92aaf5dfd663497dce48c0c8486f68d8f5d..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_ice.c +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pfk_ice.h" - -/**********************************/ -/** global definitions **/ -/**********************************/ - -#define TZ_ES_INVALIDATE_ICE_KEY 0x3 -#define TZ_ES_CONFIG_SET_ICE_KEY 0x4 - -/* index 0 and 1 is reserved for FDE */ -#define MIN_ICE_KEY_INDEX 2 -#define NUM_ICE_SLOTS 32 -#define MAX_ICE_KEY_INDEX (NUM_ICE_SLOTS - 1) - -#define TZ_ES_CONFIG_SET_ICE_KEY_ID \ - TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, \ - TZ_ES_CONFIG_SET_ICE_KEY) - -#define TZ_ES_INVALIDATE_ICE_KEY_ID \ - TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ - TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY) - -#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \ - TZ_SYSCALL_CREATE_PARAM_ID_1( \ - TZ_SYSCALL_PARAM_TYPE_VAL) - -#define TZ_ES_CONFIG_SET_ICE_KEY_PARAM_ID \ - TZ_SYSCALL_CREATE_PARAM_ID_5( \ - TZ_SYSCALL_PARAM_TYPE_VAL, \ - TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ - TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL) - -#define CONTEXT_SIZE 0x1000 - -#define ICE_BUFFER_SIZE 64 - -static uint8_t ice_buffer[ICE_BUFFER_SIZE]; - -enum { - ICE_CIPHER_MODE_XTS_128 = 0, - ICE_CIPHER_MODE_CBC_128 = 1, - ICE_CIPHER_MODE_XTS_256 = 3, - ICE_CIPHER_MODE_CBC_256 = 4 -}; - -static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt, - unsigned int data_unit) -{ - struct scm_desc desc = {0}; - int ret = 0; - uint32_t smc_id = 0; - char *tzbuf = (char *)ice_buffer; - uint32_t size = ICE_BUFFER_SIZE / 2; - - if (!tzbuf) { - pr_err("%s No Memory\n", __func__); - return -ENOMEM; - } - - memset(tzbuf, 0, ICE_BUFFER_SIZE); - - memcpy(ice_buffer, key, size); - memcpy(ice_buffer+size, salt, size); - - dmac_flush_range(tzbuf, tzbuf + ICE_BUFFER_SIZE); - - smc_id = TZ_ES_CONFIG_SET_ICE_KEY_ID; - - desc.arginfo = TZ_ES_CONFIG_SET_ICE_KEY_PARAM_ID; - desc.args[0] = index; - desc.args[1] = virt_to_phys(tzbuf); - desc.args[2] = ICE_BUFFER_SIZE; - desc.args[3] = ICE_CIPHER_MODE_XTS_256; - desc.args[4] = data_unit; - - ret = scm_call2_noretry(smc_id, &desc); - if (ret) - pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); - - return ret; -} - -static int clear_key(uint32_t index) -{ - struct scm_desc desc = {0}; - int ret = 0; - uint32_t smc_id = 0; - - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - - ret = scm_call2_noretry(smc_id, &desc); - if (ret) - pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); - return ret; -} - -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type, unsigned int data_unit) -{ - int ret = 0, ret1 = 0; - char *s_type = storage_type; - - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - if (!key || !salt) { - pr_err("%s Invalid key/salt\n", __func__); - return -EINVAL; - } - - if (s_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - - ret = qcom_ice_setup_ice_hw((const char *)s_type, true); - if (ret) { - pr_err("%s: could not enable clocks: %d\n", __func__, ret); - goto out; - } - - ret = set_key(index, key, salt, data_unit); - if (ret) { - pr_err("%s: Set Key Error: %d\n", __func__, ret); - if (ret == -EBUSY) { - if (qcom_ice_setup_ice_hw((const char *)s_type, false)) - pr_err("%s: clock disable failed\n", __func__); - goto out; - } - /* Try to invalidate the key to keep ICE in proper state */ - ret1 = clear_key(index); - if (ret1) - pr_err("%s: Invalidate key error: %d\n", __func__, ret); - } - - ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); - if (ret) - pr_err("%s: Error %d disabling clocks\n", __func__, ret); - -out: - return ret; -} - -int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) -{ - int ret = 0; - - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - - if (storage_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - - ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); - if (ret) { - pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); - return ret; - } - - ret = clear_key(index); - if (ret) - pr_err("%s: Invalidate key error: %d\n", __func__, ret); - - if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) - pr_err("%s: could not disable clocks\n", __func__); - - return ret; -} - -int qti_pfk_ice_get_info(uint32_t *min_slot_index, uint32_t *total_num_slots, - bool async) -{ - - if (!min_slot_index || !total_num_slots) { - pr_err("%s Null input\n", __func__); - return -EINVAL; - } - - *min_slot_index = MIN_ICE_KEY_INDEX; - *total_num_slots = NUM_ICE_SLOTS - MIN_ICE_KEY_INDEX; - - return 0; -} diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h deleted file mode 100644 index bc919744e7a232098491a767c3b6efb527e405e4..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_ice.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef PFK_ICE_H_ -#define PFK_ICE_H_ - -/* - * PFK ICE - * - * ICE keys configuration through scm calls. - * - */ - -#include - -int pfk_ice_init(void); -int pfk_ice_deinit(void); - -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type, unsigned int data_unit); -int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); -int qti_pfk_ice_get_info(uint32_t *min_slot_index, uint32_t *total_num_slots, - bool async); - -#endif /* PFK_ICE_H_ */ diff --git a/security/pfe/pfk_internal.h b/security/pfe/pfk_internal.h deleted file mode 100644 index 3214327b8bcd14c425ff3030728b54841ac77d6d..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_internal.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _PFK_INTERNAL_H_ -#define _PFK_INTERNAL_H_ - -#include -#include - -struct pfk_key_info { - const unsigned char *key; - const unsigned char *salt; - size_t key_size; - size_t salt_size; -}; - -int pfk_key_size_to_key_type(size_t key_size, - enum ice_crpto_key_size *key_size_type); - -bool pfe_is_inode_filesystem_type(const struct inode *inode, - const char *fs_type); - -char *inode_to_filename(const struct inode *inode); - -#endif /* _PFK_INTERNAL_H_ */ diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c deleted file mode 100644 index c07c82c5260d42c4ee23dc58c90cbc0302ce0fc2..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_kc.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * PFK Key Cache - * - * Key Cache used internally in PFK. - * The purpose of the cache is to save access time to QSEE when loading keys. - * Currently the cache is the same size as the total number of keys that can - * be loaded to ICE. Since this number is relatively small, the algorithms for - * cache eviction are simple, linear and based on last usage timestamp, i.e - * the node that will be evicted is the one with the oldest timestamp. - * Empty entries always have the oldest timestamp. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pfk_kc.h" -#include "pfk_ice.h" - -/** currently the only supported key and salt sizes */ -#define PFK_KC_KEY_SIZE 32 -#define PFK_KC_SALT_SIZE 32 - -/** Table size limitations */ -#define PFK_KC_MAX_TABLE_SIZE (32) -#define PFK_KC_MIN_TABLE_SIZE (1) - -/** The maximum key and salt size */ -#define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE -#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE -#define PFK_UFS "ufs" - -static DEFINE_SPINLOCK(kc_lock); -static unsigned long flags; -static bool kc_ready; -static char *s_type = "sdcc"; - - -/** Actual table size */ -static uint32_t kc_table_size; - -/** - * enum pfk_kc_entry_state - state of the entry inside kc table - * - * @FREE: entry is free - * @ACTIVE_ICE_PRELOAD: entry is actively used by ICE engine - and cannot be used by others. SCM call - to load key to ICE is pending to be performed - * @ACTIVE_ICE_LOADED: entry is actively used by ICE engine and - cannot be used by others. SCM call to load the - key to ICE was successfully executed and key is - now loaded - * @INACTIVE_INVALIDATING: entry is being invalidated during file close - and cannot be used by others until invalidation - is complete - * @INACTIVE: entry's key is already loaded, but is not - currently being used. It can be re-used for - optimization and to avoid SCM call cost or - it can be taken by another key if there are - no FREE entries - * @SCM_ERROR: error occurred while scm call was performed to - load the key to ICE - */ -enum pfk_kc_entry_state { - FREE, - ACTIVE_ICE_PRELOAD, - ACTIVE_ICE_LOADED, - INACTIVE_INVALIDATING, - INACTIVE, - SCM_ERROR -}; - -struct kc_entry { - unsigned char key[PFK_MAX_KEY_SIZE]; - size_t key_size; - - unsigned char salt[PFK_MAX_SALT_SIZE]; - size_t salt_size; - - u64 time_stamp; - u32 key_index; - - struct task_struct *thread_pending; - - enum pfk_kc_entry_state state; - - /* ref count for the number of requests in the HW queue for this key */ - int loaded_ref_cnt; - int scm_error; -}; - -static struct kc_entry kc_table[PFK_KC_MAX_TABLE_SIZE]; - - - -static inline void kc_spin_lock(void) -{ - spin_lock_irqsave(&kc_lock, flags); -} - -static inline void kc_spin_unlock(void) -{ - spin_unlock_irqrestore(&kc_lock, flags); -} -/** - * kc_is_ready() - driver is initialized and ready. - * - * Return: true if the key cache is ready. - */ -static inline bool kc_is_ready(void) -{ - bool res; - - kc_spin_lock(); - res = kc_ready; - kc_spin_unlock(); - return res; -} -/** - * pfk_kc_get_storage_type() - return the hardware storage type. - * - * Return: storage type queried during bootup. - */ -const char *pfk_kc_get_storage_type(void) -{ - return s_type; -} - -/** - * kc_entry_is_available() - checks whether the entry is available - * - * Return true if it is , false otherwise or if invalid - * Should be invoked under spinlock - */ -static bool kc_entry_is_available(const struct kc_entry *entry) -{ - if (!entry) - return false; - - return (entry->state == FREE || entry->state == INACTIVE); -} - -/** - * kc_entry_wait_till_available() - waits till entry is available - * - * Returns 0 in case of success or -ERESTARTSYS if the wait was interrupted - * by signal - * - * Should be invoked under spinlock - */ -static int kc_entry_wait_till_available(struct kc_entry *entry) -{ - int res = 0; - - while (!kc_entry_is_available(entry)) { - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - res = -ERESTARTSYS; - break; - } - /* assuming only one thread can try to invalidate - * the same entry - */ - entry->thread_pending = current; - kc_spin_unlock(); - schedule(); - kc_spin_lock(); - } - set_current_state(TASK_RUNNING); - - return res; -} - -/** - * kc_entry_start_invalidating() - moves entry to state - * INACTIVE_INVALIDATING - * If entry is in use, waits till - * it gets available - * @entry: pointer to entry - * - * Return 0 in case of success, otherwise error - * Should be invoked under spinlock - */ -static int kc_entry_start_invalidating(struct kc_entry *entry) -{ - int res; - - res = kc_entry_wait_till_available(entry); - if (res) - return res; - - entry->state = INACTIVE_INVALIDATING; - - return 0; -} - -/** - * kc_entry_finish_invalidating() - moves entry to state FREE - * wakes up all the tasks waiting - * on it - * - * @entry: pointer to entry - * - * Return 0 in case of success, otherwise error - * Should be invoked under spinlock - */ -static void kc_entry_finish_invalidating(struct kc_entry *entry) -{ - if (!entry) - return; - - if (entry->state != INACTIVE_INVALIDATING) - return; - - entry->state = FREE; -} - -/** - * kc_min_entry() - compare two entries to find one with minimal time - * @a: ptr to the first entry. If NULL the other entry will be returned - * @b: pointer to the second entry - * - * Return the entry which timestamp is the minimal, or b if a is NULL - */ -static inline struct kc_entry *kc_min_entry(struct kc_entry *a, - struct kc_entry *b) -{ - if (!a) - return b; - - if (time_before64(b->time_stamp, a->time_stamp)) - return b; - - return a; -} - -/** - * kc_entry_at_index() - return entry at specific index - * @index: index of entry to be accessed - * - * Return entry - * Should be invoked under spinlock - */ -static struct kc_entry *kc_entry_at_index(int index) -{ - return &(kc_table[index]); -} - -/** - * kc_find_key_at_index() - find kc entry starting at specific index - * @key: key to look for - * @key_size: the key size - * @salt: salt to look for - * @salt_size: the salt size - * @sarting_index: index to start search with, if entry found, updated with - * index of that entry - * - * Return entry or NULL in case of error - * Should be invoked under spinlock - */ -static struct kc_entry *kc_find_key_at_index(const unsigned char *key, - size_t key_size, const unsigned char *salt, size_t salt_size, - int *starting_index) -{ - struct kc_entry *entry = NULL; - int i = 0; - - for (i = *starting_index; i < kc_table_size; i++) { - entry = kc_entry_at_index(i); - - if (salt != NULL) { - if (entry->salt_size != salt_size) - continue; - - if (memcmp(entry->salt, salt, salt_size) != 0) - continue; - } - - if (entry->key_size != key_size) - continue; - - if (memcmp(entry->key, key, key_size) == 0) { - *starting_index = i; - return entry; - } - } - - return NULL; -} - -/** - * kc_find_key() - find kc entry - * @key: key to look for - * @key_size: the key size - * @salt: salt to look for - * @salt_size: the salt size - * - * Return entry or NULL in case of error - * Should be invoked under spinlock - */ -static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size) -{ - int index = 0; - - return kc_find_key_at_index(key, key_size, salt, salt_size, &index); -} - -/** - * kc_find_oldest_entry_non_locked() - finds the entry with minimal timestamp - * that is not locked - * - * Returns entry with minimal timestamp. Empty entries have timestamp - * of 0, therefore they are returned first. - * If all the entries are locked, will return NULL - * Should be invoked under spin lock - */ -static struct kc_entry *kc_find_oldest_entry_non_locked(void) -{ - struct kc_entry *curr_min_entry = NULL; - struct kc_entry *entry = NULL; - int i = 0; - - for (i = 0; i < kc_table_size; i++) { - entry = kc_entry_at_index(i); - - if (entry->state == FREE) - return entry; - - if (entry->state == INACTIVE) - curr_min_entry = kc_min_entry(curr_min_entry, entry); - } - - return curr_min_entry; -} - -/** - * kc_update_timestamp() - updates timestamp of entry to current - * - * @entry: entry to update - * - */ -static void kc_update_timestamp(struct kc_entry *entry) -{ - if (!entry) - return; - - entry->time_stamp = get_jiffies_64(); -} - -/** - * kc_clear_entry() - clear the key from entry and mark entry not in use - * - * @entry: pointer to entry - * - * Should be invoked under spinlock - */ -static void kc_clear_entry(struct kc_entry *entry) -{ - if (!entry) - return; - - memset(entry->key, 0, entry->key_size); - memset(entry->salt, 0, entry->salt_size); - - entry->key_size = 0; - entry->salt_size = 0; - - entry->time_stamp = 0; - entry->scm_error = 0; - - entry->state = FREE; - - entry->loaded_ref_cnt = 0; - entry->thread_pending = NULL; -} - -/** - * kc_update_entry() - replaces the key in given entry and - * loads the new key to ICE - * - * @entry: entry to replace key in - * @key: key - * @key_size: key_size - * @salt: salt - * @salt_size: salt_size - * @data_unit: dun size - * - * The previous key is securely released and wiped, the new one is loaded - * to ICE. - * Should be invoked under spinlock - */ -static int kc_update_entry(struct kc_entry *entry, const unsigned char *key, - size_t key_size, const unsigned char *salt, size_t salt_size, - unsigned int data_unit) -{ - int ret; - kc_clear_entry(entry); - - memcpy(entry->key, key, key_size); - entry->key_size = key_size; - - memcpy(entry->salt, salt, salt_size); - entry->salt_size = salt_size; - - /* Mark entry as no longer free before releasing the lock */ - entry->state = ACTIVE_ICE_PRELOAD; - kc_spin_unlock(); - ret = qti_pfk_ice_set_key(entry->key_index, entry->key, - entry->salt, s_type, data_unit); - kc_spin_lock(); - return ret; -} - -/** - * pfk_kc_init() - init function - * - * Return 0 in case of success, error otherwise - */ -int pfk_kc_init(bool async) -{ - int ret = 0; - struct kc_entry *entry = NULL; - uint32_t i = 0, num_ice_slots = 0, kc_starting_index = 0; - - if (kc_is_ready()) - return 0; - - ret = qti_pfk_ice_get_info(&kc_starting_index, &num_ice_slots, async); - if (ret) { - pr_err("qti_pfk_ice_get_info failed ret = %d\n", ret); - return ret; - } - if (num_ice_slots > PFK_KC_MAX_TABLE_SIZE || - num_ice_slots < PFK_KC_MIN_TABLE_SIZE) { - pr_err("Received ICE num slots = %u not in [%u,%u]\n", - num_ice_slots, PFK_KC_MAX_TABLE_SIZE, - PFK_KC_MIN_TABLE_SIZE); - return -E2BIG; - } - - kc_spin_lock(); - if (!kc_ready) { - kc_table_size = num_ice_slots; - for (i = 0; i < kc_table_size; i++) { - entry = kc_entry_at_index(i); - entry->key_index = kc_starting_index + i; - } - kc_ready = true; - } - kc_spin_unlock(); - - return ret; -} - -/** - * pfk_kc_denit() - deinit function - * - * Return 0 in case of success, error otherwise - */ -int pfk_kc_deinit(void) -{ - int res = pfk_kc_clear(); - kc_spin_lock(); - kc_ready = false; - kc_spin_unlock(); - kc_table_size = 0; - - return res; -} - -/** - * pfk_kc_load_key_start() - retrieve the key from cache or add it if - * it's not there and return the ICE hw key index in @key_index. - * @key: pointer to the key - * @key_size: the size of the key - * @salt: pointer to the salt - * @salt_size: the size of the salt - * @key_index: the pointer to key_index where the output will be stored - * @async: whether scm calls are allowed in the caller context - * - * If key is present in cache, than the key_index will be retrieved from cache. - * If it is not present, the oldest entry from kc table will be evicted, - * the key will be loaded to ICE via QSEE to the index that is the evicted - * entry number and stored in cache. - * Entry that is going to be used is marked as being used, it will mark - * as not being used when ICE finishes using it and pfk_kc_load_key_end - * will be invoked. - * As QSEE calls can only be done from a non-atomic context, when @async flag - * is set to 'false', it specifies that it is ok to make the calls in the - * current context. Otherwise, when @async is set, the caller should retry the - * call again from a different context, and -EAGAIN error will be returned. - * - * Return 0 in case of success, error otherwise - */ -int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size, u32 *key_index, - bool async, unsigned int data_unit) -{ - int ret = 0; - struct kc_entry *entry = NULL; - bool entry_exists = false; - - ret = pfk_kc_init(async); - if (ret) - return ret; - - if (!key || !salt || !key_index) { - pr_err("%s key/salt/key_index NULL\n", __func__); - return -EINVAL; - } - - if (key_size != PFK_KC_KEY_SIZE) { - pr_err("unsupported key size %zu\n", key_size); - return -EINVAL; - } - - if (salt_size != PFK_KC_SALT_SIZE) { - pr_err("unsupported salt size %zu\n", salt_size); - return -EINVAL; - } - - kc_spin_lock(); - - entry = kc_find_key(key, key_size, salt, salt_size); - if (!entry) { - if (async) { - pr_debug("%s task will populate entry\n", __func__); - kc_spin_unlock(); - return -EAGAIN; - } - - entry = kc_find_oldest_entry_non_locked(); - if (!entry) { - /* could not find a single non locked entry, - * return EBUSY to upper layers so that the - * request will be rescheduled - */ - kc_spin_unlock(); - return -EBUSY; - } - } else { - entry_exists = true; - } - - pr_debug("entry with index %d is in state %d\n", - entry->key_index, entry->state); - - switch (entry->state) { - case (INACTIVE): - if (entry_exists) { - kc_update_timestamp(entry); - entry->state = ACTIVE_ICE_LOADED; - - if (!strcmp(s_type, (char *)PFK_UFS)) { - if (async) - entry->loaded_ref_cnt++; - } else { - entry->loaded_ref_cnt++; - } - break; - } - case (FREE): - ret = kc_update_entry(entry, key, key_size, salt, salt_size, - data_unit); - if (ret) { - entry->state = SCM_ERROR; - entry->scm_error = ret; - pr_err("%s: key load error (%d)\n", __func__, ret); - } else { - kc_update_timestamp(entry); - entry->state = ACTIVE_ICE_LOADED; - - /* - * In case of UFS only increase ref cnt for async calls, - * sync calls from within work thread do not pass - * requests further to HW - */ - if (!strcmp(s_type, (char *)PFK_UFS)) { - if (async) - entry->loaded_ref_cnt++; - } else { - entry->loaded_ref_cnt++; - } - } - break; - case (ACTIVE_ICE_PRELOAD): - case (INACTIVE_INVALIDATING): - ret = -EAGAIN; - break; - case (ACTIVE_ICE_LOADED): - kc_update_timestamp(entry); - - if (!strcmp(s_type, (char *)PFK_UFS)) { - if (async) - entry->loaded_ref_cnt++; - } else { - entry->loaded_ref_cnt++; - } - break; - case(SCM_ERROR): - ret = entry->scm_error; - kc_clear_entry(entry); - entry->state = FREE; - break; - default: - pr_err("invalid state %d for entry with key index %d\n", - entry->state, entry->key_index); - ret = -EINVAL; - } - - *key_index = entry->key_index; - kc_spin_unlock(); - - return ret; -} - -/** - * pfk_kc_load_key_end() - finish the process of key loading that was started - * by pfk_kc_load_key_start - * by marking the entry as not - * being in use - * @key: pointer to the key - * @key_size: the size of the key - * @salt: pointer to the salt - * @salt_size: the size of the salt - * - */ -void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size) -{ - struct kc_entry *entry = NULL; - struct task_struct *tmp_pending = NULL; - int ref_cnt = 0; - - if (!kc_is_ready()) - return; - - if (!key || !salt) - return; - - if (key_size != PFK_KC_KEY_SIZE) - return; - - if (salt_size != PFK_KC_SALT_SIZE) - return; - - kc_spin_lock(); - - entry = kc_find_key(key, key_size, salt, salt_size); - if (!entry) { - kc_spin_unlock(); - pr_err("internal error, there should an entry to unlock\n"); - - return; - } - ref_cnt = --entry->loaded_ref_cnt; - - if (ref_cnt < 0) - pr_err("internal error, ref count should never be negative\n"); - - if (!ref_cnt) { - entry->state = INACTIVE; - /* - * wake-up invalidation if it's waiting - * for the entry to be released - */ - if (entry->thread_pending) { - tmp_pending = entry->thread_pending; - entry->thread_pending = NULL; - - kc_spin_unlock(); - wake_up_process(tmp_pending); - return; - } - } - - kc_spin_unlock(); -} - -/** - * pfk_kc_remove_key() - remove the key from cache and from ICE engine - * @key: pointer to the key - * @key_size: the size of the key - * @salt: pointer to the key - * @salt_size: the size of the key - * - * Return 0 in case of success, error otherwise (also in case of non - * (existing key) - */ -int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size) -{ - struct kc_entry *entry = NULL; - int res = 0; - - if (!kc_is_ready()) - return -ENODEV; - - if (!key) - return -EINVAL; - - if (!salt) - return -EINVAL; - - if (key_size != PFK_KC_KEY_SIZE) - return -EINVAL; - - if (salt_size != PFK_KC_SALT_SIZE) - return -EINVAL; - - kc_spin_lock(); - - entry = kc_find_key(key, key_size, salt, salt_size); - if (!entry) { - pr_debug("%s: key does not exist\n", __func__); - kc_spin_unlock(); - return -EINVAL; - } - - res = kc_entry_start_invalidating(entry); - if (res != 0) { - kc_spin_unlock(); - return res; - } - kc_clear_entry(entry); - - kc_spin_unlock(); - - qti_pfk_ice_invalidate_key(entry->key_index, s_type); - - kc_spin_lock(); - kc_entry_finish_invalidating(entry); - kc_spin_unlock(); - - return 0; -} - -/** - * pfk_kc_remove_key() - remove the key from cache and from ICE engine - * when no salt is available. Will only search key part, if there are several, - * all will be removed - * - * @key: pointer to the key - * @key_size: the size of the key - * - * Return 0 in case of success, error otherwise (also for non-existing key) - */ -int pfk_kc_remove_key(const unsigned char *key, size_t key_size) -{ - struct kc_entry *entry = NULL; - int index = 0; - int temp_indexes[PFK_KC_MAX_TABLE_SIZE] = {0}; - int temp_indexes_size = 0; - int i = 0; - int res = 0; - - if (!kc_is_ready()) - return -ENODEV; - - if (!key) - return -EINVAL; - - if (key_size != PFK_KC_KEY_SIZE) - return -EINVAL; - - memset(temp_indexes, -1, sizeof(temp_indexes)); - - kc_spin_lock(); - - entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); - if (!entry) { - pr_err("%s: key does not exist\n", __func__); - kc_spin_unlock(); - return -EINVAL; - } - - res = kc_entry_start_invalidating(entry); - if (res != 0) { - kc_spin_unlock(); - return res; - } - - temp_indexes[temp_indexes_size++] = index; - kc_clear_entry(entry); - - /* let's clean additional entries with the same key if there are any */ - do { - index++; - entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); - if (!entry) - break; - - res = kc_entry_start_invalidating(entry); - if (res != 0) { - kc_spin_unlock(); - goto out; - } - - temp_indexes[temp_indexes_size++] = index; - - kc_clear_entry(entry); - - - } while (true); - - kc_spin_unlock(); - - temp_indexes_size--; - for (i = temp_indexes_size; i >= 0 ; i--) - qti_pfk_ice_invalidate_key( - kc_entry_at_index(temp_indexes[i])->key_index, - s_type); - - /* fall through */ - res = 0; - -out: - kc_spin_lock(); - for (i = temp_indexes_size; i >= 0 ; i--) - kc_entry_finish_invalidating( - kc_entry_at_index(temp_indexes[i])); - kc_spin_unlock(); - - return res; -} - -/** - * pfk_kc_clear() - clear the table and remove all keys from ICE - * - * Return 0 on success, error otherwise - * - */ -int pfk_kc_clear(void) -{ - struct kc_entry *entry = NULL; - int i = 0; - int res = 0; - - if (!kc_is_ready()) - return -ENODEV; - - kc_spin_lock(); - for (i = 0; i < kc_table_size; i++) { - entry = kc_entry_at_index(i); - res = kc_entry_start_invalidating(entry); - if (res != 0) { - kc_spin_unlock(); - goto out; - } - kc_clear_entry(entry); - } - kc_spin_unlock(); - - for (i = 0; i < kc_table_size; i++) - qti_pfk_ice_invalidate_key(kc_entry_at_index(i)->key_index, - s_type); - - /* fall through */ - res = 0; -out: - kc_spin_lock(); - for (i = 0; i < kc_table_size; i++) - kc_entry_finish_invalidating(kc_entry_at_index(i)); - kc_spin_unlock(); - - return res; -} - -/** - * pfk_kc_clear_on_reset() - clear the table and remove all keys from ICE - * The assumption is that at this point we don't have any pending transactions - * Also, there is no need to clear keys from ICE - * - * Return 0 on success, error otherwise - * - */ -void pfk_kc_clear_on_reset(void) -{ - struct kc_entry *entry = NULL; - int i = 0; - - if (!kc_is_ready()) - return; - - kc_spin_lock(); - for (i = 0; i < kc_table_size; i++) { - entry = kc_entry_at_index(i); - kc_clear_entry(entry); - } - kc_spin_unlock(); -} - -static int pfk_kc_find_storage_type(char **device) -{ - -#ifdef CONFIG_PFK_VIRTUALIZED - *device = PFK_UFS; - return 0; -#else - char boot[20] = {'\0'}; - char *match = (char *)strnstr(saved_command_line, - "androidboot.bootdevice=", - strlen(saved_command_line)); - if (match) { - memcpy(boot, (match + strlen("androidboot.bootdevice=")), - sizeof(boot) - 1); - if (strnstr(boot, PFK_UFS, strlen(boot))) - *device = PFK_UFS; - - return 0; - } - return -EINVAL; -#endif -} - -static int __init pfk_kc_pre_init(void) -{ - return pfk_kc_find_storage_type(&s_type); -} - -static void __exit pfk_kc_exit(void) -{ - s_type = NULL; -} - -module_init(pfk_kc_pre_init); -module_exit(pfk_kc_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Per-File-Key-KC driver"); diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h deleted file mode 100644 index dc00d286377aa763c11d1c19ebd20f52f0dac2a5..0000000000000000000000000000000000000000 --- a/security/pfe/pfk_kc.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef PFK_KC_H_ -#define PFK_KC_H_ - -#include - -int pfk_kc_init(bool async); -int pfk_kc_deinit(void); -int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size, u32 *key_index, - bool async, unsigned int data_unit); -void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size); -int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, - const unsigned char *salt, size_t salt_size); -int pfk_kc_remove_key(const unsigned char *key, size_t key_size); -int pfk_kc_clear(void); -void pfk_kc_clear_on_reset(void); -const char *pfk_kc_get_storage_type(void); -extern char *saved_command_line; - - -#endif /* PFK_KC_H_ */ diff --git a/security/security.c b/security/security.c index 2655987c96381748b3c6ac4af6980fb4149234ff..5afd1dc81511b6b40050c5dc63fe8815e18ef455 100644 --- a/security/security.c +++ b/security/security.c @@ -614,14 +614,6 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode } EXPORT_SYMBOL_GPL(security_inode_create); -int security_inode_post_create(struct inode *dir, struct dentry *dentry, - umode_t mode) -{ - if (unlikely(IS_PRIVATE(dir))) - return 0; - return call_int_hook(inode_post_create, 0, dir, dentry, mode); -} - int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 84f89ab1f2b594cbb84a29dcc8acc1df3754cefb..21f5c139988d63e14c840f9683a9be280a3d7f74 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5279,40 +5279,60 @@ static int selinux_tun_dev_open(void *security) static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) { - int err = 0; - u32 perm; + int rc = 0; + unsigned int msg_len; + unsigned int data_len = skb->len; + unsigned char *data = skb->data; struct nlmsghdr *nlh; struct sk_security_struct *sksec = sk->sk_security; + u16 sclass = sksec->sclass; + u32 perm; - if (skb->len < NLMSG_HDRLEN) { - err = -EINVAL; - goto out; - } - nlh = nlmsg_hdr(skb); + while (data_len >= nlmsg_total_size(0)) { + nlh = (struct nlmsghdr *)data; - err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); - if (err) { - if (err == -EINVAL) { + /* NOTE: the nlmsg_len field isn't reliably set by some netlink + * users which means we can't reject skb's with bogus + * length fields; our solution is to follow what + * netlink_rcv_skb() does and simply skip processing at + * messages with length fields that are clearly junk + */ + if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len) + return 0; + + rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm); + if (rc == 0) { + rc = sock_has_perm(sk, perm); + if (rc) + return rc; + } else if (rc == -EINVAL) { + /* -EINVAL is a missing msg/perm mapping */ pr_warn_ratelimited("SELinux: unrecognized netlink" - " message: protocol=%hu nlmsg_type=%hu sclass=%s" - " pig=%d comm=%s\n", - sk->sk_protocol, nlh->nlmsg_type, - secclass_map[sksec->sclass - 1].name, - task_pid_nr(current), current->comm); - if (!enforcing_enabled(&selinux_state) || - security_get_allow_unknown(&selinux_state)) - err = 0; + " message: protocol=%hu nlmsg_type=%hu sclass=%s" + " pid=%d comm=%s\n", + sk->sk_protocol, nlh->nlmsg_type, + secclass_map[sclass - 1].name, + task_pid_nr(current), current->comm); + if (enforcing_enabled(&selinux_state)&& + !security_get_allow_unknown(&selinux_state)) + return rc; + rc = 0; + } else if (rc == -ENOENT) { + /* -ENOENT is a missing socket/class mapping, ignore */ + rc = 0; + } else { + return rc; } - /* Ignore */ - if (err == -ENOENT) - err = 0; - goto out; + /* move to the next message after applying netlink padding */ + msg_len = NLMSG_ALIGN(nlh->nlmsg_len); + if (msg_len >= data_len) + return 0; + data_len -= msg_len; + data += msg_len; } - err = sock_has_perm(sk, perm); -out: - return err; + return rc; } #ifdef CONFIG_NETFILTER diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 2ac6edc1d1317a462663d2115339a8cf2e54d732..512908b55ca3d23dcdcbce10c682705bf629f8e7 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -26,9 +26,8 @@ #include #include #include -//#include "flask.h" -//#include "avc.h" -#include "security.h" +#include "flask.h" +#include "avc.h" struct task_security_struct { u32 osid; /* SID prior to last execve */ @@ -65,8 +64,6 @@ struct inode_security_struct { u32 sid; /* SID of this object */ u16 sclass; /* security class of this object */ unsigned char initialized; /* initialization flag */ - u32 tag; /* Per-File-Encryption tag */ - void *pfk_data; /* Per-File-Key data from ecryptfs */ spinlock_t lock; }; diff --git a/sound/core/control.c b/sound/core/control.c index 36571cd49be338131465b2188a680cd74efb82a2..a0ce22164957c3b6baa497cf1bfdf5a71551b02c 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1467,8 +1467,9 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, if (kctl->tlv.c == NULL) return -ENXIO; - /* When locked, this is unavailable. */ - if (vd->owner != NULL && vd->owner != file) + /* Write and command operations are not allowed for locked element. */ + if (op_flag != SNDRV_CTL_TLV_OP_READ && + vd->owner != NULL && vd->owner != file) return -EPERM; return kctl->tlv.c(kctl, op_flag, size, buf); diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index b8ab46b8298ded7d45a094b728d3e393a4348804..c1315ce98b54831fd0af53c711484dec916cb034 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->next) { if (plugin->dst_frames) frames = plugin->dst_frames(plugin, frames); - if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) + if ((snd_pcm_sframes_t)frames <= 0) return -ENXIO; plugin = plugin->next; err = snd_pcm_plugin_alloc(plugin, frames); @@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->prev) { if (plugin->src_frames) frames = plugin->src_frames(plugin, frames); - if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) + if ((snd_pcm_sframes_t)frames <= 0) return -ENXIO; plugin = plugin->prev; err = snd_pcm_plugin_alloc(plugin, frames); @@ -196,7 +196,9 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) return 0; } -snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames) +static snd_pcm_sframes_t plug_client_size(struct snd_pcm_substream *plug, + snd_pcm_uframes_t drv_frames, + bool check_size) { struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; int stream; @@ -212,12 +214,18 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p plugin_prev = plugin->prev; if (plugin->src_frames) drv_frames = plugin->src_frames(plugin, drv_frames); + if (check_size && plugin->buf_frames && + drv_frames > plugin->buf_frames) + drv_frames = plugin->buf_frames; plugin = plugin_prev; } } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { plugin = snd_pcm_plug_first(plug); while (plugin && drv_frames > 0) { plugin_next = plugin->next; + if (check_size && plugin->buf_frames && + drv_frames > plugin->buf_frames) + drv_frames = plugin->buf_frames; if (plugin->dst_frames) drv_frames = plugin->dst_frames(plugin, drv_frames); plugin = plugin_next; @@ -227,7 +235,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p return drv_frames; } -snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames) +static snd_pcm_sframes_t plug_slave_size(struct snd_pcm_substream *plug, + snd_pcm_uframes_t clt_frames, + bool check_size) { struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; snd_pcm_sframes_t frames; @@ -243,6 +253,9 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc plugin = snd_pcm_plug_first(plug); while (plugin && frames > 0) { plugin_next = plugin->next; + if (check_size && plugin->buf_frames && + frames > plugin->buf_frames) + frames = plugin->buf_frames; if (plugin->dst_frames) { frames = plugin->dst_frames(plugin, frames); if (frames < 0) @@ -259,6 +272,9 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc if (frames < 0) return frames; } + if (check_size && plugin->buf_frames && + frames > plugin->buf_frames) + frames = plugin->buf_frames; plugin = plugin_prev; } } else @@ -266,6 +282,18 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc return frames; } +snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, + snd_pcm_uframes_t drv_frames) +{ + return plug_client_size(plug, drv_frames, false); +} + +snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, + snd_pcm_uframes_t clt_frames) +{ + return plug_slave_size(plug, clt_frames, false); +} + static int snd_pcm_plug_formats(const struct snd_mask *mask, snd_pcm_format_t format) { @@ -621,7 +649,7 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st src_channels = dst_channels; plugin = next; } - return snd_pcm_plug_client_size(plug, frames); + return plug_client_size(plug, frames, true); } snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size) @@ -631,7 +659,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str snd_pcm_sframes_t frames = size; int err; - frames = snd_pcm_plug_slave_size(plug, frames); + frames = plug_slave_size(plug, frames, true); if (frames < 0) return frames; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 9debd1b8fd2880fde1e0fe349a4745bdb443b477..cdfb8f92d5545c215ddd477abdf43f660db151f3 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -615,6 +615,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq len = snd_seq_oss_timer_start(dp->timer); if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev); + snd_midi_event_reset_decode(mdev->coder); } else { len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev); if (len > 0) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 92b0d4523a07a3b9d5af03da563182f94d9bdbda..6fe93d5f6f7142db546365aafffd3073a1a2d67d 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -564,7 +564,7 @@ static int update_timestamp_of_queue(struct snd_seq_event *event, event->queue = queue; event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK; if (real_time) { - event->time.time = snd_seq_timer_get_cur_time(q->timer); + event->time.time = snd_seq_timer_get_cur_time(q->timer, true); event->flags |= SNDRV_SEQ_TIME_STAMP_REAL; } else { event->time.tick = snd_seq_timer_get_cur_tick(q->timer); @@ -1639,7 +1639,7 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client, tmr = queue->timer; status->events = queue->tickq->cells + queue->timeq->cells; - status->time = snd_seq_timer_get_cur_time(tmr); + status->time = snd_seq_timer_get_cur_time(tmr, true); status->tick = snd_seq_timer_get_cur_tick(tmr); status->running = tmr->running; diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 1a6dc4ff44a69bb53e4b8ab9009b957ea7fd8689..ea1aa079627618ffae4ca3924a15c941bf40e06f 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -261,6 +261,8 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) { unsigned long flags; struct snd_seq_event_cell *cell; + snd_seq_tick_time_t cur_tick; + snd_seq_real_time_t cur_time; if (q == NULL) return; @@ -277,17 +279,18 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) __again: /* Process tick queue... */ + cur_tick = snd_seq_timer_get_cur_tick(q->timer); for (;;) { - cell = snd_seq_prioq_cell_out(q->tickq, - &q->timer->tick.cur_tick); + cell = snd_seq_prioq_cell_out(q->tickq, &cur_tick); if (!cell) break; snd_seq_dispatch_event(cell, atomic, hop); } /* Process time queue... */ + cur_time = snd_seq_timer_get_cur_time(q->timer, false); for (;;) { - cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time); + cell = snd_seq_prioq_cell_out(q->timeq, &cur_time); if (!cell) break; snd_seq_dispatch_event(cell, atomic, hop); @@ -415,6 +418,7 @@ int snd_seq_queue_check_access(int queueid, int client) int snd_seq_queue_set_owner(int queueid, int client, int locked) { struct snd_seq_queue *q = queueptr(queueid); + unsigned long flags; if (q == NULL) return -EINVAL; @@ -424,8 +428,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked) return -EPERM; } + spin_lock_irqsave(&q->owner_lock, flags); q->locked = locked ? 1 : 0; q->owner = client; + spin_unlock_irqrestore(&q->owner_lock, flags); queue_access_unlock(q); queuefree(q); @@ -564,15 +570,17 @@ void snd_seq_queue_client_termination(int client) unsigned long flags; int i; struct snd_seq_queue *q; + bool matched; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { if ((q = queueptr(i)) == NULL) continue; spin_lock_irqsave(&q->owner_lock, flags); - if (q->owner == client) + matched = (q->owner == client); + if (matched) q->klocked = 1; spin_unlock_irqrestore(&q->owner_lock, flags); - if (q->owner == client) { + if (matched) { if (q->timer->running) snd_seq_timer_stop(q->timer); snd_seq_timer_reset(q->timer); @@ -764,6 +772,8 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, int i, bpm; struct snd_seq_queue *q; struct snd_seq_timer *tmr; + bool locked; + int owner; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { if ((q = queueptr(i)) == NULL) @@ -775,9 +785,14 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, else bpm = 0; + spin_lock_irq(&q->owner_lock); + locked = q->locked; + owner = q->owner; + spin_unlock_irq(&q->owner_lock); + snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name); - snd_iprintf(buffer, "owned by client : %d\n", q->owner); - snd_iprintf(buffer, "lock status : %s\n", q->locked ? "Locked" : "Free"); + snd_iprintf(buffer, "owned by client : %d\n", owner); + snd_iprintf(buffer, "lock status : %s\n", locked ? "Locked" : "Free"); snd_iprintf(buffer, "queued time events : %d\n", snd_seq_prioq_avail(q->timeq)); snd_iprintf(buffer, "queued tick events : %d\n", snd_seq_prioq_avail(q->tickq)); snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped"); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 0e1feb597586fbcab9278b4ed53367a294071c7d..bd5e5a5d52a8d459cc86a30e3c770a433918d9ad 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -436,14 +436,15 @@ int snd_seq_timer_continue(struct snd_seq_timer *tmr) } /* return current 'real' time. use timeofday() to get better granularity. */ -snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) +snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr, + bool adjust_ktime) { snd_seq_real_time_t cur_time; unsigned long flags; spin_lock_irqsave(&tmr->lock, flags); cur_time = tmr->cur_time; - if (tmr->running) { + if (adjust_ktime && tmr->running) { struct timespec64 tm; ktime_get_ts64(&tm); @@ -460,7 +461,13 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) high PPQ values) */ snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr) { - return tmr->tick.cur_tick; + snd_seq_tick_time_t cur_tick; + unsigned long flags; + + spin_lock_irqsave(&tmr->lock, flags); + cur_tick = tmr->tick.cur_tick; + spin_unlock_irqrestore(&tmr->lock, flags); + return cur_tick; } diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 9506b661fe5bfcf056c97799a39e1ba9dec8f029..5d47d559465e6b3f8211fc602b509368546a4d16 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -135,7 +135,8 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer *tmr, int ppq); int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position); int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position); int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base); -snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr); +snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr, + bool adjust_ktime); snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr); extern int seq_default_timer_class; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 8ebbca554e995f47eff787d0ffd36fc244abf7d8..dd958d76ca5de2939433d89866ee9761b813e014 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -95,6 +95,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) continue; snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); + snd_midi_event_reset_decode(vmidi->parser); } else { len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); if (len > 0) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index c0939a0164a6ff4c378ffe0863e5b7e265cf46c4..aeb65d7d4cb30ed54ae079b794c62a184bf5f147 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -933,7 +933,7 @@ static void print_formats(struct snd_dummy *dummy, { int i; - for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { + for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { if (dummy->pcm_hw.formats & (1ULL << i)) snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); } diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index f21633cd9b38ea9a8f6a3c955f9209a8f66ecf2f..acbe61b8db7b26b9fa535fb41f3845b612ac0e19 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -249,7 +249,7 @@ void snd_hdac_print_channel_allocation(int spk_alloc, char *buf, int buflen) for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { if (spk_alloc & (1 << i)) - j += snprintf(buf + j, buflen - j, " %s", + j += scnprintf(buf + j, buflen - j, " %s", cea_speaker_allocation_names[i]); } buf[j] = '\0'; /* necessary when j == 0 */ diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 8894c7c18ad673c8bcebc698f5839e336b68d30d..d92c3c6b6051deb47c1f6958339ebd299fd78e5b 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -875,10 +875,13 @@ static void snd_miro_write(struct snd_miro *chip, unsigned char reg, spin_unlock_irqrestore(&chip->lock, flags); } +static inline void snd_miro_write_mask(struct snd_miro *chip, + unsigned char reg, unsigned char value, unsigned char mask) +{ + unsigned char oldval = snd_miro_read(chip, reg); -#define snd_miro_write_mask(chip, reg, value, mask) \ - snd_miro_write(chip, reg, \ - (snd_miro_read(chip, reg) & ~(mask)) | ((value) & (mask))) + snd_miro_write(chip, reg, (oldval & ~mask) | (value & mask)); +} /* * Proc Interface diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 505cd81e19fa5a40be7d5a9302bb1c0c7a867d00..4ef3caaf4354b5cf62c16b36f9f009d9096b5d0e 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -327,10 +327,13 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, } -#define snd_opti9xx_write_mask(chip, reg, value, mask) \ - snd_opti9xx_write(chip, reg, \ - (snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask))) +static inline void snd_opti9xx_write_mask(struct snd_opti9xx *chip, + unsigned char reg, unsigned char value, unsigned char mask) +{ + unsigned char oldval = snd_opti9xx_read(chip, reg); + snd_opti9xx_write(chip, reg, (oldval & ~mask) | (value & mask)); +} static int snd_opti9xx_configure(struct snd_opti9xx *chip, long port, diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index c397e7da0eacf9808d136ccdb8ef40e583e58b19..7ccfb09535e14acf46193a4423fa38d4f9893976 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -310,8 +310,12 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_beep *beep = codec->beep; + int chs = get_amp_channels(kcontrol); + if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) { - ucontrol->value.integer.value[0] = + if (chs & 1) + ucontrol->value.integer.value[0] = beep->enabled; + if (chs & 2) ucontrol->value.integer.value[1] = beep->enabled; return 0; } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e3f3351da480b2ed64fe08cfe1e40a86593c7e25..7d65fe31c825731279790774aa8692ec51b1866d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -942,6 +942,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); + codec->core.dev.power.power_state = PMSG_ON; snd_hda_codec_proc_new(codec); @@ -4002,7 +4003,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) if (pcm & (AC_SUPPCM_BITS_8 << i)) - j += snprintf(buf + j, buflen - j, " %d", bits[i]); + j += scnprintf(buf + j, buflen - j, " %d", bits[i]); buf[j] = '\0'; /* necessary when j == 0 */ } diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index ba7fe9b6655c1f25279e5489081f34327f215d45..864cc8c9ada0ae6112445d3a6622f337067e778f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -373,7 +373,7 @@ static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) if (pcm & (1 << i)) - j += snprintf(buf + j, buflen - j, " %d", + j += scnprintf(buf + j, buflen - j, " %d", alsa_rates[i]); buf[j] = '\0'; /* necessary when j == 0 */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 890793ad85ca13b627dbfb5529045c6923793d8e..7779f54607156d7c5e36a412fe3752b72cfe1f63 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2034,24 +2034,15 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) { struct snd_card *card = context; struct azx *chip = card->private_data; - struct pci_dev *pci = chip->pci; - - if (!fw) { - dev_err(card->dev, "Cannot load firmware, aborting\n"); - goto error; - } - chip->fw = fw; + if (fw) + chip->fw = fw; + else + dev_err(card->dev, "Cannot load firmware, continue without patching\n"); if (!chip->disabled) { /* continue probing */ - if (azx_probe_continue(chip)) - goto error; + azx_probe_continue(chip); } - return; /* OK */ - - error: - snd_card_free(card); - pci_set_drvdata(pci, NULL); } #endif @@ -2177,6 +2168,17 @@ static const struct hdac_io_ops pci_hda_io_ops = { .dma_free_pages = dma_free_pages, }; +/* Blacklist for skipping the whole probe: + * some HD-audio PCI entries are exposed without any codecs, and such devices + * should be ignored from the beginning. + */ +static const struct pci_device_id driver_blacklist[] = { + { PCI_DEVICE_SUB(0x1022, 0x1487, 0x1043, 0x874f) }, /* ASUS ROG Zenith II / Strix */ + { PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb59) }, /* MSI TRX40 Creator */ + { PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb60) }, /* MSI TRX40 */ + {} +}; + static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .substream_alloc_pages = substream_alloc_pages, @@ -2196,6 +2198,11 @@ static int azx_probe(struct pci_dev *pci, bool schedule_probe; int err; + if (pci_match_id(driver_blacklist, pci)) { + dev_info(&pci->dev, "Skipping the blacklisted device\n"); + return -ENODEV; + } + if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 9b7efece4484a65eda479511dd00d3a02abacf00..2a173de7ca023fd35fbf566aa509ab379d09a0cc 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -221,7 +221,7 @@ static ssize_t init_verbs_show(struct device *dev, mutex_lock(&codec->user_mutex); for (i = 0; i < codec->init_verbs.used; i++) { struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "0x%02x 0x%03x 0x%04x\n", v->nid, v->verb, v->param); } @@ -271,7 +271,7 @@ static ssize_t hints_show(struct device *dev, mutex_lock(&codec->user_mutex); for (i = 0; i < codec->hints.used; i++) { struct hda_hint *hint = snd_array_elem(&codec->hints, i); - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "%s = %s\n", hint->key, hint->val); } mutex_unlock(&codec->user_mutex); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 382b6d2ed80366e2268e97f5602d2aa4e3759eb4..9cc9304ff21a728da62ffdb21567f050053c302d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -969,6 +969,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), + SND_PCI_QUIRK(0x17aa, 0x21d2, "Lenovo T420s", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD), diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index f214055972150d7875c4e01a41a6c79e663a448e..435c0efb9bf29205c240e3d4f807a94376fc4215 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1849,8 +1849,10 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) /* Add sanity check to pass klockwork check. * This should never happen. */ - if (WARN_ON(spdif == NULL)) + if (WARN_ON(spdif == NULL)) { + mutex_unlock(&codec->spdif_mutex); return true; + } non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO); mutex_unlock(&codec->spdif_mutex); return non_pcm; @@ -2574,9 +2576,12 @@ static int alloc_intel_hdmi(struct hda_codec *codec) /* parse and post-process for Intel codecs */ static int parse_intel_hdmi(struct hda_codec *codec) { - int err; + int err, retries = 3; + + do { + err = hdmi_parse_codec(codec); + } while (err < 0 && retries--); - err = hdmi_parse_codec(codec); if (err < 0) { generic_spec_free(codec); return err; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5a7afbeb612d59037e5fe320d1b84122f2ba13c3..b2aec97414fb86c42a45ce924aa96cf8f8c16317 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -333,7 +333,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0215: case 0x10ec0233: case 0x10ec0235: + case 0x10ec0236: + case 0x10ec0245: case 0x10ec0255: + case 0x10ec0256: case 0x10ec0257: case 0x10ec0282: case 0x10ec0283: @@ -345,11 +348,6 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0300: alc_update_coef_idx(codec, 0x10, 1<<9, 0); break; - case 0x10ec0236: - case 0x10ec0256: - alc_write_coef_idx(codec, 0x36, 0x5757); - alc_update_coef_idx(codec, 0x10, 1<<9, 0); - break; case 0x10ec0275: alc_update_coef_idx(codec, 0xe, 0, 1<<0); break; @@ -3122,7 +3120,13 @@ static void alc256_init(struct hda_codec *codec) alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */ alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15); - alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ + /* + * Expose headphone mic (or possibly Line In on some machines) instead + * of PC Beep on 1Ah, and disable 1Ah loopback for all outputs. See + * Documentation/sound/hd-audio/realtek-pc-beep.rst for details of + * this register. + */ + alc_write_coef_idx(codec, 0x36, 0x5757); } static void alc256_shutup(struct hda_codec *codec) @@ -4687,6 +4691,8 @@ static void alc_determine_headset_type(struct hda_codec *codec) is_ctia = (val & 0x1c02) == 0x1c02; break; case 0x10ec0225: + codec->power_save_node = 1; + /* fall through */ case 0x10ec0295: case 0x10ec0299: alc_process_coef_fw(codec, alc225_pre_hsmode); @@ -6584,6 +6590,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS), + SND_PCI_QUIRK(0x17aa, 0x1048, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -7259,6 +7266,7 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; break; case 0x10ec0215: + case 0x10ec0245: case 0x10ec0285: case 0x10ec0289: spec->codec_variant = ALC269_TYPE_ALC215; @@ -8339,6 +8347,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269), HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269), HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269), diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 2697402b5195799243e115fef1996c7293eb773d..41f6450a2539f44734e228a099d843547a1f7280 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -569,7 +569,7 @@ static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); mutex_lock(&ice->gpio_mutex); - ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; + ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; mutex_unlock(&ice->gpio_mutex); return 0; } @@ -583,7 +583,7 @@ static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, mutex_lock(&ice->gpio_mutex); oval = wm_get(ice, WM_ADC_MUX); - nval = (oval & 0xe0) | ucontrol->value.integer.value[0]; + nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0]; if (nval != oval) { wm_put(ice, WM_ADC_MUX, nval); change = 1; diff --git a/sound/sh/aica.c b/sound/sh/aica.c index fdc680ae8aa09c037ac01cc6623e6f6d15797993..d9acf551a8985c58de15ad752b050d959bdb8aa7 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -117,10 +117,10 @@ static void spu_memset(u32 toi, u32 what, int length) } /* spu_memload - write to SPU address space */ -static void spu_memload(u32 toi, void *from, int length) +static void spu_memload(u32 toi, const void *from, int length) { unsigned long flags; - u32 *froml = from; + const u32 *froml = from; u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi); int i; u32 val; diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index 834b2574786f50da6e986ff24eeffe8b3d3178db..6251b5e1b64a2b0594ee0e2095456ba5511d2df6 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -190,7 +190,6 @@ static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, { /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; if (copy_from_user_toio(chip->data_buffer + pos, src, count)) return -EFAULT; @@ -210,7 +209,6 @@ static int snd_sh_dac_pcm_copy_kernel(struct snd_pcm_substream *substream, { /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; memcpy_toio(chip->data_buffer + pos, src, count); chip->buffer_end = chip->data_buffer + pos + count; @@ -229,7 +227,6 @@ static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, { /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; memset_io(chip->data_buffer + pos, 0, count); chip->buffer_end = chip->data_buffer + pos + count; diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 4a56f3dfba5132a01bbb49eb985540d16a944ecf..23887613b5c39325a35a8f1e56713926bfbfbacd 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -25,6 +25,8 @@ config SND_ATMEL_SOC_DMA config SND_ATMEL_SOC_SSC_DMA tristate + select SND_ATMEL_SOC_DMA + select SND_ATMEL_SOC_PDC config SND_ATMEL_SOC_SSC tristate diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1c3626347e12b561549bf8276851f3c6cd399daf..aeeec1144558ef34efacd2fd4047111eae9de115 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -142,14 +142,14 @@ static struct hdac_hdmi_pcm * hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, struct hdac_hdmi_cvt *cvt) { - struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_pcm *pcm; list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) - break; + return pcm; } - return pcm; + return NULL; } static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 68feae262476492ae3a0b30855dbb09e96fa187e..940bdc30753d124625a4bee4621a9461efc0f523 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1438,13 +1438,15 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) } pcm512x->sclk = devm_clk_get(dev, NULL); - if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err; + } if (!IS_ERR(pcm512x->sclk)) { ret = clk_prepare_enable(pcm512x->sclk); if (ret != 0) { dev_err(dev, "Failed to enable SCLK: %d\n", ret); - return ret; + goto err; } } diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index ca8a70ab22a8253f20bf904600eaf03fdeea2f91..d64cb28e8dc5cc8425d992ff8e462ded9bd49bc5 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1563,6 +1563,40 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "Error %d initializing CHIP_CLK_CTRL\n", ret); + /* Mute everything to avoid pop from the following power-up */ + ret = regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_CTRL, + SGTL5000_CHIP_ANA_CTRL_DEFAULT); + if (ret) { + dev_err(&client->dev, + "Error %d muting outputs via CHIP_ANA_CTRL\n", ret); + goto disable_clk; + } + + /* + * If VAG is powered-on (e.g. from previous boot), it would be disabled + * by the write to ANA_POWER in later steps of the probe code. This + * may create a loud pop even with all outputs muted. The proper way + * to circumvent this is disabling the bit first and waiting the proper + * cool-down time. + */ + ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, &value); + if (ret) { + dev_err(&client->dev, "Failed to read ANA_POWER: %d\n", ret); + goto disable_clk; + } + if (value & SGTL5000_VAG_POWERUP) { + ret = regmap_update_bits(sgtl5000->regmap, + SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, + 0); + if (ret) { + dev_err(&client->dev, "Error %d disabling VAG\n", ret); + goto disable_clk; + } + + msleep(SGTL5000_VAG_POWERDOWN_DELAY); + } + /* Follow section 2.2.1.1 of AN3663 */ ana_pwr = SGTL5000_ANA_POWER_DEFAULT; if (sgtl5000->num_supplies <= VDDD) { diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 22f3442af9826ce5868619bf993123bafdb0c82f..9ea41749d0375a20d17991d063303e170938de3c 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -236,6 +236,7 @@ /* * SGTL5000_CHIP_ANA_CTRL */ +#define SGTL5000_CHIP_ANA_CTRL_DEFAULT 0x0133 #define SGTL5000_LINE_OUT_MUTE 0x0100 #define SGTL5000_HP_SEL_MASK 0x0040 #define SGTL5000_HP_SEL_SHIFT 6 diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 0f3604b5594240ed74b6fb1d4661efe36665b147..999eb3ba78672c86fc554db821bc8f07170bac3e 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -974,7 +974,9 @@ static int sst_set_be_modules(struct snd_soc_dapm_widget *w, dev_dbg(c->dev, "Enter: widget=%s\n", w->name); if (SND_SOC_DAPM_EVENT_ON(event)) { + mutex_lock(&drv->lock); ret = sst_send_slot_map(drv); + mutex_unlock(&drv->lock); if (ret) return ret; ret = sst_send_pipe_module_params(w, k); @@ -1341,7 +1343,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dai->capture_widget->name); w = dai->capture_widget; snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connected && !p->connected(w, p->sink)) + if (p->connected && !p->connected(w, p->source)) continue; if (p->connect && p->source->power && diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index 6906ee624cf6f4e16caa6456fdad8e80ed03cd4e..438c7bcd8c4cda40616566f6979dd402d44ab5c6 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -107,7 +107,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram); do_release_regions: pci_release_regions(pci); - return 0; + return ret; } /* diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index 1987f78ea91e49f14188827f081d347662bc4fb1..71c6bbf37b6c8e72e56da771ad0598e4925ef839 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -42,8 +42,8 @@ static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, int i; ssize_t ret = 0; - for (i = 0; i < max_pin; i++) - ret += snprintf(buf + size, MOD_BUF - size, + for (i = 0; i < max_pin; i++) { + ret += scnprintf(buf + size, MOD_BUF - size, "%s %d\n\tModule %d\n\tInstance %d\n\t" "In-used %s\n\tType %s\n" "\tState %d\n\tIndex %d\n", @@ -53,13 +53,15 @@ static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, m_pin[i].in_use ? "Used" : "Unused", m_pin[i].is_dynamic ? "Dynamic" : "Static", m_pin[i].pin_state, i); + size += ret; + } return ret; } static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf, ssize_t size, bool direction) { - return snprintf(buf + size, MOD_BUF - size, + return scnprintf(buf + size, MOD_BUF - size, "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t" "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t" "Sample Type %d\n\tCh Map %#x\n", @@ -81,16 +83,16 @@ static ssize_t module_read(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; - ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n" + ret = scnprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n" "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid, mconfig->id.module_id, mconfig->id.instance_id, mconfig->id.pvt_id); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n", mconfig->mcps, mconfig->ibs, mconfig->obs); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "Module data:\n\tCore %d\n\tIn queue %d\n\t" "Out queue %d\n\tType %s\n", mconfig->core_id, mconfig->max_in_queue, @@ -100,38 +102,38 @@ static ssize_t module_read(struct file *file, char __user *user_buf, ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true); ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "Fixup:\n\tParams %#x\n\tConverter %#x\n", mconfig->params_fixup, mconfig->converter); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n", mconfig->dev_type, mconfig->vbus_id, mconfig->hw_conn_type, mconfig->time_slot); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t" "Pages %#x\n", mconfig->pipe->ppl_id, mconfig->pipe->pipe_priority, mconfig->pipe->conn_type, mconfig->pipe->memory_pages); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n", mconfig->pipe->p_params->host_dma_id, mconfig->pipe->p_params->link_dma_id); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n", mconfig->pipe->p_params->ch, mconfig->pipe->p_params->s_freq, mconfig->pipe->p_params->s_fmt); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "\tLink %#x\n\tStream %#x\n", mconfig->pipe->p_params->linktype, mconfig->pipe->p_params->stream); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "\tState %d\n\tPassthru %s\n", mconfig->pipe->state, mconfig->pipe->passthru ? "true" : "false"); @@ -141,7 +143,7 @@ static ssize_t module_read(struct file *file, char __user *user_buf, ret += skl_print_pins(mconfig->m_out_pin, buf, mconfig->max_out_queue, ret, false); - ret += snprintf(buf + ret, MOD_BUF - ret, + ret += scnprintf(buf + ret, MOD_BUF - ret, "Other:\n\tDomain %d\n\tHomogenous Input %s\n\t" "Homogenous Output %s\n\tIn Queue Mask %d\n\t" "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t" @@ -199,7 +201,7 @@ static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); for (offset = 0; offset < FW_REG_SIZE; offset += 16) { - ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); + ret += scnprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4, tmp + ret, FW_REG_BUF - ret, 0); ret += strlen(tmp + ret); diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 99394c03699819343d351a932ec84799001e7d2d..e099c0505b765210c7f1ff02380dff4dc513da33 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -92,7 +92,7 @@ #define JZ_AIC_I2S_STATUS_BUSY BIT(2) #define JZ_AIC_CLK_DIV_MASK 0xf -#define I2SDIV_DV_SHIFT 8 +#define I2SDIV_DV_SHIFT 0 #define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT) #define I2SDIV_IDV_SHIFT 8 #define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 4d948757d300d04be3bfca3c63f78c68085a8506..5e5ed547547397b609fa10693dda891ca92858b2 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -172,7 +172,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, i; for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { - shift = (i * 4) + 16; + shift = (i * 4) + 20; val = (val & ~(0xF << shift)) | rsnd_mod_id(pos) << shift; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 420dbbe5d2e22a3faab4c6b888c53e5128ae481d..ec1aa2bbc297b8d734069b026fd8bbd593d32613 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -415,7 +415,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, memset(&template, 0, sizeof(template)); template.reg = e->reg; - template.mask = e->mask << e->shift_l; + template.mask = e->mask; template.shift = e->shift_l; template.off_val = snd_soc_enum_item_to_val(e, 0); template.on_val = template.off_val; @@ -541,8 +541,22 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, if (data->value == value) return false; - if (data->widget) - data->widget->on_val = value; + if (data->widget) { + switch (dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->id) { + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + case snd_soc_dapm_mixer_named_ctl: + data->widget->on_val = value & data->widget->mask; + break; + case snd_soc_dapm_demux: + case snd_soc_dapm_mux: + data->widget->on_val = value >> data->widget->shift; + break; + default: + data->widget->on_val = value; + break; + } + } data->value = value; @@ -801,7 +815,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i, val = max - val; p->connect = !!val; } else { - p->connect = 0; + /* since a virtual mixer has no backing registers to + * decide which path to connect, it will try to match + * with initial state. This is to ensure + * that the default mixer choice will be + * correctly powered up during initialization. + */ + p->connect = invert; } } @@ -4500,7 +4520,7 @@ static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) continue; if (w->power) { dapm_seq_insert(w, &down_list, false); - w->power = 0; + w->new_power = 0; powerdown = 1; } } diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 1e317f5e4f1c1c25d071485da4b0eab31573b56e..54e4807a94b841e447c18c76bf243ab6d6aaaed4 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -838,7 +838,7 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, unsigned int regbase = mc->regbase; unsigned int regcount = mc->regcount; unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; - unsigned int regwmask = (1<invert; unsigned long mask = (1UL<nbits)-1; long min = mc->min; @@ -887,7 +887,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, unsigned int regbase = mc->regbase; unsigned int regcount = mc->regcount; unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; - unsigned int regwmask = (1<invert; unsigned long mask = (1UL<nbits)-1; long max = mc->max; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6d15b430a4f2a716518d8d767aa1f9e0336f8ca0..471620a11eeca127cf44c7de831eb8812911899b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2240,7 +2240,8 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) continue; ret = dpcm_do_trigger(dpcm, be_substream, cmd); @@ -2270,7 +2271,8 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; case SNDRV_PCM_TRIGGER_STOP: - if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) + if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) continue; if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) @@ -2315,42 +2317,81 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, } EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); +static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, + int cmd, bool fe_first) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int ret; + + /* call trigger on the frontend before the backend. */ + if (fe_first) { + dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + if (ret < 0) + return ret; + + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + return ret; + } + + /* call trigger on the frontend after the backend. */ + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + if (ret < 0) + return ret; + + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + + return ret; +} + static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *fe = substream->private_data; - int stream = substream->stream, ret; + int stream = substream->stream; + int ret = 0; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; switch (trigger) { case SND_SOC_DPCM_TRIGGER_PRE: - /* call trigger on the frontend before the backend. */ - - dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = dpcm_dai_trigger_fe_be(substream, cmd, true); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, false); + break; + default: + ret = -EINVAL; + break; } - - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); break; case SND_SOC_DPCM_TRIGGER_POST: - /* call trigger on the frontend after the backend. */ - - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = dpcm_dai_trigger_fe_be(substream, cmd, false); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, true); + break; + default: + ret = -EINVAL; + break; } - - dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); break; case SND_SOC_DPCM_TRIGGER_BESPOKE: /* bespoke trigger() - handles both FE and BEs */ @@ -2359,10 +2400,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) fe->dai_link->name, cmd); ret = soc_pcm_bespoke_trigger(substream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; - } break; default: dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, @@ -2371,6 +2408,12 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) goto out; } + if (ret < 0) { + dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", + cmd, ret); + goto out; + } + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -3284,16 +3327,16 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, ssize_t offset = 0; /* FE state */ - offset += snprintf(buf + offset, size - offset, + offset += scnprintf(buf + offset, size - offset, "[%s - %s]\n", fe->dai_link->name, stream ? "Capture" : "Playback"); - offset += snprintf(buf + offset, size - offset, "State: %s\n", + offset += scnprintf(buf + offset, size - offset, "State: %s\n", dpcm_state_string(fe->dpcm[stream].state)); if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) - offset += snprintf(buf + offset, size - offset, + offset += scnprintf(buf + offset, size - offset, "Hardware Params: " "Format = %s, Channels = %d, Rate = %d\n", snd_pcm_format_name(params_format(params)), @@ -3301,10 +3344,10 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, params_rate(params)); /* BEs state */ - offset += snprintf(buf + offset, size - offset, "Backends:\n"); + offset += scnprintf(buf + offset, size - offset, "Backends:\n"); if (list_empty(&fe->dpcm[stream].be_clients)) { - offset += snprintf(buf + offset, size - offset, + offset += scnprintf(buf + offset, size - offset, " No active DSP links\n"); goto out; } @@ -3313,16 +3356,16 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; - offset += snprintf(buf + offset, size - offset, + offset += scnprintf(buf + offset, size - offset, "- %s\n", be->dai_link->name); - offset += snprintf(buf + offset, size - offset, + offset += scnprintf(buf + offset, size - offset, " State: %s\n", dpcm_state_string(be->dpcm[stream].state)); if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) - offset += snprintf(buf + offset, size - offset, + offset += scnprintf(buf + offset, size - offset, " Hardware Params: " "Format = %s, Channels = %d, Rate = %d\n", snd_pcm_format_name(params_format(params)), diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 72301bcad3bddde53465a7b29f06e5ca0ba60813..50aa45525be5a6607986749e83d6a99c9232fde2 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -421,7 +421,7 @@ static int soc_tplg_add_kcontrol(struct soc_tplg *tplg, struct snd_soc_component *comp = tplg->comp; return soc_tplg_add_dcontrol(comp->card->snd_card, - comp->dev, k, NULL, comp, kcontrol); + comp->dev, k, comp->name_prefix, comp, kcontrol); } /* remove a mixer kcontrol */ @@ -1954,7 +1954,9 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, _pcm = pcm; } else { abi_match = false; - pcm_new_ver(tplg, pcm, &_pcm); + ret = pcm_new_ver(tplg, pcm, &_pcm); + if (ret < 0) + return ret; } /* create the FE DAIs and DAI links */ @@ -2177,8 +2179,11 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, } ret = soc_tplg_link_config(tplg, _link); - if (ret < 0) + if (ret < 0) { + if (!abi_match) + kfree(_link); return ret; + } /* offset by version-specific struct size and * real priv data size @@ -2330,7 +2335,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, { struct snd_soc_tplg_manifest *manifest, *_manifest; bool abi_match; - int err; + int ret = 0; if (tplg->pass != SOC_TPLG_PASS_MANIFEST) return 0; @@ -2343,19 +2348,19 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, _manifest = manifest; } else { abi_match = false; - err = manifest_new_ver(tplg, manifest, &_manifest); - if (err < 0) - return err; + ret = manifest_new_ver(tplg, manifest, &_manifest); + if (ret < 0) + return ret; } /* pass control to component driver for optional further init */ if (tplg->comp && tplg->ops && tplg->ops->manifest) - return tplg->ops->manifest(tplg->comp, _manifest); + ret = tplg->ops->manifest(tplg->comp, _manifest); if (!abi_match) /* free the duplicated one */ kfree(_manifest); - return 0; + return ret; } /* validate header magic, size and type */ diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 7a312168f8647acd364e9d0d97c9ef7801f51289..a031f25031b4c84cf0a93c806d01c56a24f5060a 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -71,6 +71,7 @@ #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) +#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) @@ -221,7 +222,7 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - BIT(SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT), + SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK, value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); return 0; diff --git a/sound/usb/format.c b/sound/usb/format.c index eaf2615cb05d46d4f5c4e7d3136fd781f7a051ca..2227b4cea3383ff17c01ec1c6182ca90c1723b1a 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -249,6 +249,52 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof return 0; } +/* + * Many Focusrite devices supports a limited set of sampling rates per + * altsetting. Maximum rate is exposed in the last 4 bytes of Format Type + * descriptor which has a non-standard bLength = 10. + */ +static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip, + struct audioformat *fp, + unsigned int rate) +{ + struct usb_interface *iface; + struct usb_host_interface *alts; + unsigned char *fmt; + unsigned int max_rate; + + iface = usb_ifnum_to_if(chip->dev, fp->iface); + if (!iface) + return true; + + alts = &iface->altsetting[fp->altset_idx]; + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, + NULL, UAC_FORMAT_TYPE); + if (!fmt) + return true; + + if (fmt[0] == 10) { /* bLength */ + max_rate = combine_quad(&fmt[6]); + + /* Validate max rate */ + if (max_rate != 48000 && + max_rate != 96000 && + max_rate != 192000 && + max_rate != 384000) { + + usb_audio_info(chip, + "%u:%d : unexpected max rate: %u\n", + fp->iface, fp->altsetting, max_rate); + + return true; + } + + return rate <= max_rate; + } + + return true; +} + /* * Helper function to walk the array of sample rate triplets reported by * the device. The problem is that we need to parse whole array first to @@ -285,6 +331,11 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, } for (rate = min; rate <= max; rate += res) { + /* Filter out invalid rates on Focusrite devices */ + if (USB_ID_VENDOR(chip->usb_id) == 0x1235 && + !focusrite_valid_sample_rate(chip, fp, rate)) + goto skip_rate; + if (fp->rate_table) fp->rate_table[nr_rates] = rate; if (!fp->rate_min || rate < fp->rate_min) @@ -299,6 +350,7 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, break; } +skip_rate: /* avoid endless loop */ if (res == 0) break; diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index b223de3defc4f4a17059549bf34680acfb161643..bf4eacc53a7d26820fe166e16980f1815d3fbdc5 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -313,7 +313,7 @@ static void line6_data_received(struct urb *urb) line6_midibuf_read(mb, line6->buffer_message, LINE6_MIDI_MESSAGE_MAXLEN); - if (done == 0) + if (done <= 0) break; line6->message_length = done; diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c index 36a610ba342ec190b7b44c4a842fe93251380241..c931d48801ebed6626fdbfd0491d672d29c917b3 100644 --- a/sound/usb/line6/midibuf.c +++ b/sound/usb/line6/midibuf.c @@ -163,7 +163,7 @@ int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, int midi_length_prev = midibuf_message_length(this->command_prev); - if (midi_length_prev > 0) { + if (midi_length_prev > 1) { midi_length = midi_length_prev - 1; repeat = 1; } else diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 14f953679f9fca1981361ad62151610203dcb23a..211c3648a45d18d29e363b74cb79b1439798f8f6 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2625,7 +2625,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) if (map->id == state.chip->usb_id) { state.map = map->map; state.selector_map = map->selector_map; - mixer->ignore_ctl_error = map->ignore_ctl_error; + mixer->ignore_ctl_error |= map->ignore_ctl_error; break; } } diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index eaa03acd4686bdd20e19b69502c23ca465977ade..26ce6838e84299d3bbec04b5745f0376d3619b59 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -363,6 +363,14 @@ static const struct usbmix_name_map dell_alc4020_map[] = { { 0 } }; +/* Some mobos shipped with a dummy HD-audio show the invalid GET_MIN/GET_MAX + * response for Input Gain Pad (id=19, control=12). Skip it. + */ +static const struct usbmix_name_map asus_rog_map[] = { + { 19, NULL, 12 }, /* FU, Input Gain Pad */ + {} +}; + /* * Control map entries */ @@ -482,6 +490,26 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x05a7, 0x1020), .map = bose_companion5_map, }, + { /* Gigabyte TRX40 Aorus Pro WiFi */ + .id = USB_ID(0x0414, 0xa002), + .map = asus_rog_map, + }, + { /* ASUS ROG Zenith II */ + .id = USB_ID(0x0b05, 0x1916), + .map = asus_rog_map, + }, + { /* ASUS ROG Strix */ + .id = USB_ID(0x0b05, 0x1917), + .map = asus_rog_map, + }, + { /* MSI TRX40 Creator */ + .id = USB_ID(0x0db0, 0x0d64), + .map = asus_rog_map, + }, + { /* MSI TRX40 */ + .id = USB_ID(0x0db0, 0x543d), + .map = asus_rog_map, + }, { 0 } /* terminator */ }; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index b54f7dab8372e7f0071b3aa83218cd05df1534f2..b9ea4a42aee4e3cd62cd9a07f913d804c1e80380 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -1520,11 +1520,15 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, /* use known values for that card: interface#1 altsetting#1 */ iface = usb_ifnum_to_if(chip->dev, 1); - if (!iface || iface->num_altsetting < 2) - return -EINVAL; + if (!iface || iface->num_altsetting < 2) { + err = -EINVAL; + goto end; + } alts = &iface->altsetting[1]; - if (get_iface_desc(alts)->bNumEndpoints < 1) - return -EINVAL; + if (get_iface_desc(alts)->bNumEndpoints < 1) { + err = -EINVAL; + goto end; + } ep = get_endpoint(alts, 0)->bEndpointAddress; err = snd_usb_ctl_msg(chip->dev, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 51ee7910e98cf141f4299bedc44142e02c79759b..4872c27f6054398ad06360afef78b675257adbd3 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1151,6 +1151,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ + case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */ return true; } return false; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index f4b3cda412fcc6d887b997d9e4cf8795900daffd..e75271e731b2d4ca15094e35e72720ca2d0654f6 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -131,7 +131,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, info->num_dsps = 2; // 0: Prepad Data, 1: FPGA Code if (us428->chip_status & USX2Y_STAT_CHIP_INIT) info->chip_ready = 1; - info->version = USX2Y_DRIVER_VERSION; + info->version = USX2Y_DRIVER_VERSION; return 0; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index f93b355756e6027e694257c0e2ab829767c7be98..2dfc0abf2e37310e6df192cedced4db0e94494e4 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -689,6 +689,8 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) us->submitted = 2*NOOF_SETRATE_URBS; for (i = 0; i < NOOF_SETRATE_URBS; ++i) { struct urb *urb = us->urb[i]; + if (!urb) + continue; if (urb->status) { if (!err) err = -ENODEV; diff --git a/tools/accounting/getdelays.c b/tools/accounting/getdelays.c index 8cb504d3038447fe4cbb2f033d6002e8b714b252..5ef1c15e88ad2e3d4d4483a6a31c88770b939810 100644 --- a/tools/accounting/getdelays.c +++ b/tools/accounting/getdelays.c @@ -136,7 +136,7 @@ static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid, msg.g.version = 0x1; na = (struct nlattr *) GENLMSG_DATA(&msg); na->nla_type = nla_type; - na->nla_len = nla_len + 1 + NLA_HDRLEN; + na->nla_len = nla_len + NLA_HDRLEN; memcpy(NLA_DATA(na), nla_data, nla_len); msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len); diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 6a73c06e069c9d0eabe52899138a14a06d1a53be..3dbf7e8b07a59887143d66f02812b2bc95f54092 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -35,7 +35,7 @@ $(OUTPUT)include/linux/gpio.h: ../../include/uapi/linux/gpio.h prepare: $(OUTPUT)include/linux/gpio.h -GPIO_UTILS_IN := $(output)gpio-utils-in.o +GPIO_UTILS_IN := $(OUTPUT)gpio-utils-in.o $(GPIO_UTILS_IN): prepare FORCE $(Q)$(MAKE) $(build)=gpio-utils diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index c0d653d36c0f757fd8cfae32cae094a1052c308a..fb02aa4591eb3fb52b374aad54b60c81f04d89a9 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -261,6 +261,7 @@ class ArchX86(Arch): def __init__(self, exit_reasons): self.sc_perf_evt_open = 298 self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reason_field = 'exit_reason' self.exit_reasons = exit_reasons @@ -276,6 +277,7 @@ class ArchPPC(Arch): # numbers depend on the wordsize. char_ptr_size = ctypes.sizeof(ctypes.c_char_p) self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 + self.exit_reason_field = 'exit_nr' self.exit_reasons = {} @@ -283,6 +285,7 @@ class ArchA64(Arch): def __init__(self): self.sc_perf_evt_open = 241 self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reason_field = 'esr_ec' self.exit_reasons = AARCH64_EXIT_REASONS @@ -290,6 +293,7 @@ class ArchS390(Arch): def __init__(self): self.sc_perf_evt_open = 331 self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reason_field = None self.exit_reasons = None ARCH = Arch.get_arch() @@ -513,8 +517,8 @@ class TracepointProvider(Provider): """ filters = {} filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) - if ARCH.exit_reasons: - filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) + if ARCH.exit_reason_field and ARCH.exit_reasons: + filters['kvm_exit'] = (ARCH.exit_reason_field, ARCH.exit_reasons) return filters def get_available_fields(self): diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index b24afc0e6e81c458c5a2a31c98b5121ea917742c..45b50b89009aafd13a84986c5a6ff6ade86853cc 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -210,6 +210,7 @@ static bool fs__env_override(struct fs *fs) size_t name_len = strlen(fs->name); /* name + "_PATH" + '\0' */ char upper_name[name_len + 5 + 1]; + memcpy(upper_name, fs->name, name_len); mem_toupper(upper_name, name_len); strcpy(&upper_name[name_len], "_PATH"); @@ -219,7 +220,8 @@ static bool fs__env_override(struct fs *fs) return false; fs->found = true; - strncpy(fs->path, override_path, sizeof(fs->path)); + strncpy(fs->path, override_path, sizeof(fs->path) - 1); + fs->path[sizeof(fs->path) - 1] = '\0'; return true; } diff --git a/tools/objtool/arch/x86/lib/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt index 0a0e9112f2842e5b40e4e2284b2c061c4d98370a..5cb9f009f2be3f32c2bd8316d0e5f9805f6b4ea5 100644 --- a/tools/objtool/arch/x86/lib/x86-opcode-map.txt +++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt @@ -909,7 +909,7 @@ EndTable GrpTable: Grp3_2 0: TEST Ev,Iz -1: +1: TEST Ev,Iz 2: NOT Ev 3: NEG Ev 4: MUL rAX,Ev diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 5422543faff85fc882c42257142903e0c2a37ca7..04fc04b4ab67e03d798ff945a0dbe6d50b92daf0 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -915,10 +915,7 @@ static struct rela *find_switch_table(struct objtool_file *file, * it. */ for (; - &insn->list != &file->insn_list && - insn->sec == func->sec && - insn->offset >= func->offset; - + &insn->list != &file->insn_list && insn->func && insn->func->pfunc == func; insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) @@ -2065,14 +2062,27 @@ static bool ignore_unreachable_insn(struct instruction *insn) !strcmp(insn->sec->name, ".altinstr_aux")) return true; + if (!insn->func) + return false; + + /* + * CONFIG_UBSAN_TRAP inserts a UD2 when it sees + * __builtin_unreachable(). The BUG() macro has an unreachable() after + * the UD2, which causes GCC's undefined trap logic to emit another UD2 + * (or occasionally a JMP to UD2). + */ + if (list_prev_entry(insn, list)->dead_end && + (insn->type == INSN_BUG || + (insn->type == INSN_JUMP_UNCONDITIONAL && + insn->jump_dest && insn->jump_dest->type == INSN_BUG))) + return true; + /* * Check if this (or a subsequent) instruction is related to * CONFIG_UBSAN or CONFIG_KASAN. * * End the search at 5 instructions to avoid going into the weeds. */ - if (!insn->func) - return false; for (i = 0; i < 5; i++) { if (is_kasan_insn(insn) || is_ubsan_insn(insn)) diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index c3343820916a6dccf0e49bf50cbfbc811b4525fd..7cbbbdd932f1dfb8beaa22fc2f09986b6a5e2291 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -78,7 +78,7 @@ int orc_dump(const char *_objname) char *name; size_t nr_sections; Elf64_Addr orc_ip_addr = 0; - size_t shstrtab_idx; + size_t shstrtab_idx, strtab_idx = 0; Elf *elf; Elf_Scn *scn; GElf_Shdr sh; @@ -139,6 +139,8 @@ int orc_dump(const char *_objname) if (!strcmp(name, ".symtab")) { symtab = data; + } else if (!strcmp(name, ".strtab")) { + strtab_idx = i; } else if (!strcmp(name, ".orc_unwind")) { orc = data->d_buf; orc_size = sh.sh_size; @@ -150,7 +152,7 @@ int orc_dump(const char *_objname) } } - if (!symtab || !orc || !orc_ip) + if (!symtab || !strtab_idx || !orc || !orc_ip) return 0; if (orc_size % sizeof(*orc) != 0) { @@ -171,21 +173,29 @@ int orc_dump(const char *_objname) return -1; } - scn = elf_getscn(elf, sym.st_shndx); - if (!scn) { - WARN_ELF("elf_getscn"); - return -1; - } - - if (!gelf_getshdr(scn, &sh)) { - WARN_ELF("gelf_getshdr"); - return -1; - } - - name = elf_strptr(elf, shstrtab_idx, sh.sh_name); - if (!name || !*name) { - WARN_ELF("elf_strptr"); - return -1; + if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) { + scn = elf_getscn(elf, sym.st_shndx); + if (!scn) { + WARN_ELF("elf_getscn"); + return -1; + } + + if (!gelf_getshdr(scn, &sh)) { + WARN_ELF("gelf_getshdr"); + return -1; + } + + name = elf_strptr(elf, shstrtab_idx, sh.sh_name); + if (!name) { + WARN_ELF("elf_strptr"); + return -1; + } + } else { + name = elf_strptr(elf, strtab_idx, sym.st_name); + if (!name) { + WARN_ELF("elf_strptr"); + return -1; + } } printf("%s+%llx:", name, (unsigned long long)rela.r_addend); diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 7902a5681fc89f6eda64234de379fc8122567529..b8fc7d972be9d1ae667b8bd3de4f389e427a1ab8 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -35,7 +35,7 @@ endif # Only pass canonical directory names as the output directory: # ifneq ($(O),) - FULL_O := $(shell readlink -f $(O) || echo $(O)) + FULL_O := $(shell cd $(PWD); readlink -f $(O) || echo $(O)) endif # diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index b97e31498ff769734e50f9528ade05475687b365..8baaf9797101c34e862e21398178104e81d1d4d9 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -179,8 +179,17 @@ strip-libs = $(filter-out -l%,$(1)) PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) +# Python 3.8 changed the output of `python-config --ldflags` to not include the +# '-lpythonX.Y' flag unless '--embed' is also passed. The feature check for +# libpython fails if that flag is not included in LDFLAGS +ifeq ($(shell $(PYTHON_CONFIG_SQ) --ldflags --embed 2>&1 1>/dev/null; echo $$?), 0) + PYTHON_CONFIG_LDFLAGS := --ldflags --embed +else + PYTHON_CONFIG_LDFLAGS := --ldflags +endif + ifdef PYTHON_CONFIG - PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) + PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) $(PYTHON_CONFIG_LDFLAGS) 2>/dev/null) PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 628ad5f7eddb6a4295ba9370f987e9194dfe6bed..49a87fb64156ef63e265bf8a4cf501d42cd469c5 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3142,6 +3142,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, continue; } + actions->ms.map = map; top = pstack__peek(browser->pstack); if (top == &browser->hists->dso_filter) { /* diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 63db9872c8808df8df2c87bef8d6d5cae925859e..a49f27aa0c95a5b69c90436ebec90ecade5171ee 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -90,7 +90,7 @@ static inline bool replace_android_lib(const char *filename, char *newfilename) return true; } - if (!strncmp(filename, "/system/lib/", 11)) { + if (!strncmp(filename, "/system/lib/", 12)) { char *ndk, *app; const char *arch; size_t ndk_length; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 893193bd28c1788c8b41bb6cdd7010a3b2751e44..ae0feea4e8b5f9bf9d6a5bb116f7312f436e8e1c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -626,14 +626,19 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, return -EINVAL; } - /* Try to get actual symbol name from symtab */ - symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); + if (dwarf_entrypc(sp_die, &eaddr) == 0) { + /* If the DIE has entrypc, use it. */ + symbol = dwarf_diename(sp_die); + } else { + /* Try to get actual symbol name and address from symtab */ + symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); + eaddr = sym.st_value; + } if (!symbol) { pr_warning("Failed to find symbol at 0x%lx\n", (unsigned long)paddr); return -ENOENT; } - eaddr = sym.st_value; tp->offset = (unsigned long)(paddr - eaddr); tp->address = (unsigned long)paddr; diff --git a/tools/power/acpi/Makefile.config b/tools/power/acpi/Makefile.config index f304be71c278ca0c7bc1850f3daf37b41ca19f43..fc116c060b98dccf829268efcff885d96c43450f 100644 --- a/tools/power/acpi/Makefile.config +++ b/tools/power/acpi/Makefile.config @@ -18,7 +18,7 @@ include $(srctree)/../../scripts/Makefile.include OUTPUT=$(srctree)/ ifeq ("$(origin O)", "command line") - OUTPUT := $(O)/power/acpi/ + OUTPUT := $(O)/tools/power/acpi/ endif #$(info Determined 'OUTPUT' to be $(OUTPUT)) diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c index 2116df9ad83254eb0a7a37246b83f959e669b7f5..c097a3748674f80fd2bfc3ad94bce044cadc0931 100644 --- a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c @@ -83,7 +83,7 @@ static struct pci_access *pci_acc; static struct pci_dev *amd_fam14h_pci_dev; static int nbp1_entered; -struct timespec start_time; +static struct timespec start_time; static unsigned long long timediff; #ifdef DEBUG diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index 5b3205f1621749bb6ebc340413ae16d957064cb9..5277df27191f3dad92efbfc471a75654e6fccedc 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c @@ -21,7 +21,7 @@ struct cpuidle_monitor cpuidle_sysfs_monitor; static unsigned long long **previous_count; static unsigned long long **current_count; -struct timespec start_time; +static struct timespec start_time; static unsigned long long timediff; static int cpuidle_get_count_percent(unsigned int id, double *percent, diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index 05f953f0f0a0cf2b3d479ce6a6dcbc9c0d9a8c28..80a21cb67d94f4cd418834c3bc2274ddb6a3af10 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -29,6 +29,8 @@ struct cpuidle_monitor *all_monitors[] = { 0 }; +int cpu_count; + static struct cpuidle_monitor *monitors[MONITORS_MAX]; static unsigned int avail_monitors; diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h index 9e43f3371fbc625eaabaaeb941ae3a14a732ff7f..3558bbae2b5dcf17d78d7e57bc011d5d3751f3b8 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h @@ -18,7 +18,7 @@ #define CSTATE_NAME_LEN 5 #define CSTATE_DESC_LEN 60 -int cpu_count; +extern int cpu_count; /* Hard to define the right names ...: */ enum power_range_e { diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 19e345cf8193e59a4ccc7b0ce8463460d41a6e28..0692f2efc25eff688808d8173501443f1ec7d946 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -4650,9 +4650,9 @@ int add_counter(unsigned int msr_num, char *path, char *name, } msrp->msr_num = msr_num; - strncpy(msrp->name, name, NAME_BYTES); + strncpy(msrp->name, name, NAME_BYTES - 1); if (path) - strncpy(msrp->path, path, PATH_BYTES); + strncpy(msrp->path, path, PATH_BYTES - 1); msrp->width = width; msrp->type = type; msrp->format = format; diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 71dc7efc7efa4fc401db7c47de68b00d9aeb0412..df247f39d7c593f61289f7d95a97b180d0474e21 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 ifneq ($(O),) ifeq ($(origin O), command line) - dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) - ABSOLUTE_O := $(shell cd $(O) ; pwd) + dummy := $(if $(shell cd $(PWD); test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) + ABSOLUTE_O := $(shell cd $(PWD); cd $(O) ; pwd) OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/) COMMAND_O := O=$(ABSOLUTE_O) ifeq ($(objtree),) diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 0c8b61f8398edace8b4d7be42e50b8638679520d..3bdd6a463819d5e55adc21e7b264d018d9cc0270 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1345,7 +1345,7 @@ sub reboot { } else { # Make sure everything has been written to disk - run_ssh("sync"); + run_ssh("sync", 10); if (defined($time)) { start_monitor; diff --git a/tools/testing/selftests/filesystems/incfs/Makefile b/tools/testing/selftests/filesystems/incfs/Makefile index 1f13573d36179148e00b20a1e7aa1f8ec3d0263d..5b2e627ce883c8c39de138b19dd0eeea79c7e73b 100644 --- a/tools/testing/selftests/filesystems/incfs/Makefile +++ b/tools/testing/selftests/filesystems/incfs/Makefile @@ -1,18 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 -CFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -lssl -lcrypto -llz4 -CFLAGS += -I../../../../../usr/include/ -CFLAGS += -I../../../../include/uapi/ -CFLAGS += -I../../../../lib +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall +CFLAGS += -I../.. -I../../../../.. +LDLIBS := -llz4 -lcrypto EXTRA_SOURCES := utils.c -CFLAGS += $(EXTRA_SOURCES) - TEST_GEN_PROGS := incfs_test -include ../../lib.mk - -$(OUTPUT)incfs_test: incfs_test.c $(EXTRA_SOURCES) -all: $(OUTPUT)incfs_test +$(TEST_GEN_PROGS): $(EXTRA_SOURCES) -clean: - rm -rf $(OUTPUT)incfs_test *.o +include ../../lib.mk diff --git a/tools/testing/selftests/filesystems/incfs/config b/tools/testing/selftests/filesystems/incfs/config deleted file mode 100644 index b6749837a31878434de0f4a44e09ae34c55563f6..0000000000000000000000000000000000000000 --- a/tools/testing/selftests/filesystems/incfs/config +++ /dev/null @@ -1 +0,0 @@ -CONFIG_INCREMENTAL_FS=y \ No newline at end of file diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c index dd70e019dc4ce7182ec0f267bf3ef95fd21d50e3..6809399eac97b0f179bd9b827acf383a6f53ab40 100644 --- a/tools/testing/selftests/filesystems/incfs/incfs_test.c +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -2,31 +2,31 @@ /* * Copyright 2018 Google LLC */ -#include -#include -#include +#include #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include + #include -#include +#include +#include #include #include -#include -#include -#include -#include -#include + #include #include -#include "../../kselftest.h" +#include -#include "lz4.h" #include "utils.h" -#define __packed __attribute__((__packed__)) - #define TEST_FAILURE 1 #define TEST_SUCCESS 0 #define INCFS_MAX_MTREE_LEVELS 8 @@ -69,101 +69,6 @@ struct linux_dirent64 { char d_name[0]; } __packed; -/* - * The certificate below and the private key were created by calling: - * openssl req -x509 -newkey rsa:4096 -keyout private.key -out cert.crt - * -days 1000 -sha256 -nodes -outform PEM -subj - * "/C=US/ST=WA/L=Kirkland/O=Example/OU=Org/CN=www.example.com" - */ -char x509_cert[] = -"-----BEGIN CERTIFICATE-----\n" -"MIIFvzCCA6egAwIBAgIUXpwqelEljm6BBllRQGHLrls2MYgwDQYJKoZIhvcNAQEL\n" -"BQAwbzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcM\n" -"CEtpcmtsYW5kMRAwDgYDVQQKDAdFeGFtcGxlMQwwCgYDVQQLDANPcmcxGDAWBgNV\n" -"BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xOTA4MDgyMzA3MDZaFw0yMjA1MDQyMzA3\n" -"MDZaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMREwDwYDVQQH\n" -"DAhLaXJrbGFuZDEQMA4GA1UECgwHRXhhbXBsZTEMMAoGA1UECwwDT3JnMRgwFgYD\n" -"VQQDDA93d3cuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" -"AoICAQC1LuFW/lDV/GflqFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43\n" -"NeeJtqUoVxSLS9wHURjSjD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtA\n" -"uYcY4P9GHQEXYUX+ue82A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt\n" -"4/NXS/Dn+S0/mJlxw34IKfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RAD\n" -"qGewNNCab3ClJDP7/M32BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolV\n" -"gSL1HM2jin5bi4bpFMreY0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBT\n" -"qjjFb3oiSMugJzY+MhISM754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3\n" -"UgC6SyVmZxG2o+AO6m8TRTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiV\n" -"XDmotNb2myXNYHHTjRYNxkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61S\n" -"oxKWi+LGa7B4NaCMjz1LnaOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAb\n" -"uxkq9EYUDg+w9broltiBf4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABo1MwUTAd\n" -"BgNVHQ4EFgQUo6JN3gY2yGbzOTNj8Al7hNB3rw0wHwYDVR0jBBgwFoAUo6JN3gY2\n" -"yGbzOTNj8Al7hNB3rw0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" -"AgEAQb3pJqOzM4whfNVdpEOswd1EApcWNM1ps9iTlEEjDoRv9F7F1PW0uXCIpk3B\n" -"j5JgCmIxAcPnzj42rduRSx421hHMZhbAIWI/JL4ZSF64qlG0YrmJDXlJgSMoyst5\n" -"biUqeWgO7Js5udPt3zhkeA62z3hGM6dE5B3k7gHTaKKtK17+UeR9imZKsOK8GBnM\n" -"rxMPI6XghxxAK2OQ/r09DHDiyf/GxgOE46oknfXfMPx3HaSvDKrZUTZ+UvVbM5c2\n" -"5eXOgH5UO/e4llLknJK7CoP/R6G7pV44iT4t4t9FMnvCYvavAHwfR+6z5vTF3o8a\n" -"wd80fC8z1vfLsIPLROdzBl9rGCvv536fPiEA677CM1AZkjfT0a9DVzrE1NDvuCUF\n" -"0KgEdiNwux+hO6dbTyiS38yPT6TbpoWJptJmFhFkC4hGvUgoX/TI0covSyf74VRH\n" -"k3BHojOBMYiX1K66xoN7fhlGK8cith3L0XXPB8CgSEUPWURvm8RCaGuX2T3FZomF\n" -"BCnNpN+WNnN3Yf4OkjtuvtxxktUU7pfVLsUxrdpo/ph4rWm6U83VT/Zlq92aF4vW\n" -"QJ+7uraQFip7e+Gy9g3UJINm3B7b1C4ch/Z/upCZESOI/23sVGzkfTgOrS+23i6/\n" -"Vi9YW75zySC2FCa1AWMS1NmS5qfDSycJUgD6YvOUg0C54ZI=\n" -"-----END CERTIFICATE-----"; - -char private_key[] = -"-----BEGIN PRIVATE KEY-----\n" -"MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1LuFW/lDV/Gfl\n" -"qFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43NeeJtqUoVxSLS9wHURjS\n" -"jD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtAuYcY4P9GHQEXYUX+ue82\n" -"A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt4/NXS/Dn+S0/mJlxw34I\n" -"KfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RADqGewNNCab3ClJDP7/M32\n" -"BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolVgSL1HM2jin5bi4bpFMre\n" -"Y0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBTqjjFb3oiSMugJzY+MhIS\n" -"M754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3UgC6SyVmZxG2o+AO6m8T\n" -"RTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiVXDmotNb2myXNYHHTjRYN\n" -"xkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61SoxKWi+LGa7B4NaCMjz1L\n" -"naOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAbuxkq9EYUDg+w9broltiB\n" -"f4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABAoICAQCMKul/0J2e/ncub6t2t4dr\n" -"PnTrfCT6xKqPqciny4Ee6hr9So1jR2gvink380bd/mQFMmEdZqGhM3cdpAzLf82f\n" -"hu7BSNxsYIF0er0PB4MZFMJ4sMaXC+zp5/TJnP5MG/zBND0c5k8tQpEyWy8O28Jj\n" -"FKW/0F5P90Q0ncP20EJUS50tXgniOMsU2Prtw/UE6yZDgD0mPxsurMu66ycXSFwM\n" -"WqyfqEeBk7lw/AjR6Sft71W31lTbl+DclG0MN2OIKUPcxiwCRmDFKI36MDgERk1x\n" -"sMPfdrWRLj2ryDFTUuLAWBTOVEGWS0RdRsWWVaJCuHbKd6FLl0TW2xQbOfWDTjYC\n" -"Ps31ejh163qdbk7OGOZIbd83fP3jsyL+4eNzhUpeXMKhfG58mFIv4yhdZIUOpuL6\n" -"aqnoU9z9wEsJKj/SrKr3nw6tuTnmbXgNjun9LfTFmqqDRBYd0Okiprw6jHNM1jgA\n" -"GG0kC/K7r89jKymVDABwGMFCS33ynR1Tb6zG+cqgNMPw19Fy3uQuW21CjqSzCOyP\n" -"aEVCEUZeP+ofql5+7ZKi6Dj+EdTfeKt2ihgheHZZoaYSINb8tsnKbdJhwBfW9PFT\n" -"aT/hu3bnO2FPC8H2NGOqxOEeel9ALU4SFu1pOknEhiL3/mNfOQ+KgrSRDtNRlcL0\n" -"cto05J90u0cmqwWKlshfaQKCAQEA5dcklxs4ezyzt28NcsiyS02oZ+9TkQp6pCXV\n" -"kx7AwhivAmVTlJ+c6BegA5EPd7A1gknM3+EKzGpoBOqmlF45G57phVIAphAp4oCH\n" -"UOVtIQgM8p4EU2gtX+uNOopdYlpBQnWimXaHA2sOD9/yTbZ03j/McRH6D15+iCld\n" -"3880GHdZaYYbQmHoSDg39LRRO1bdS3WC0oKBD2gPi3K0b9RaZSwKzuVrmlvrLURj\n" -"WMZfmkGl4BsITfuoTxbWFVncG3Kb9eYkYUFZy4M2G/s849PS/HjrN7BvgpanjtVp\n" -"1/39APQfAYfUuBPbKYnb6F8dE0pb5cVd4uMZklAeTb3bXjOO9QKCAQEAyc4CxWXr\n" -"bG6Do5dGpWudQ7ucq00MR0T3MHQIu5XTn6BsPHAJ9ZgrQw9C24PXm2VEjjsrMs5T\n" -"rHNF9oeO39s25Za1iyJ+893icqA3h3ivCUOOoVE54BkuJK6REhkXPD5G1ubmxeBz\n" -"MKNehlpd/eSbJJArkzKFZ8sBtLt8i9VFhRnXSpDAbiMpCbjW+bem9MWdLmkenSnu\n" -"OUbnqYcJhFBCvOT7ZCHFCDNUNPfHcaReSY2EYjw0ZqtqAZD0Q+DL+RkLz7l1+/bF\n" -"eEwNjmjFTcwRyawqf38D4miU0H6ca16FkeSlbmM5p3HdwZK2HVYYz3FSwhox6Ebd\n" -"n6in42qfL4Ug6wKCAQAh9IDRWhIkErmyNdPUy1WbzmM8x5ye5t9rdLNywq5TfnYM\n" -"co/AezwhBax8GmgglIWzM9fykzqXLHklkMz/SlRBgl6ZdZ3m6qhlb/uNtfdDU/8l\n" -"sLaO4+sgKpp4tYxKRW8ytFJLPbmAhcZUDg+r73KgiuhXJAK/VoR29TWLJP9bRfaN\n" -"omRQkEpSsQuDOUhu7cxPo5KqKuGKNyNkxJNnmgWowLLwEfCtozrBO0M6EER7c4tf\n" -"6l51tuIMnSEPknD0FSB5WYCyZYcwi7fotlsuhVK8PdjyJzyyHDOw5FJ4uGsyQt55\n" -"yWlhsH1GS7mTQMn42Zlt/pR6OnbCqNdxQMUxy4gpAoIBAFvMbs5E0pb8nr0n72cI\n" -"UP2itl3mKpOw95D+94n9WcrfOt0zShSCKAvVQWCB1O5HXqwklj4CRWXI+iZu+7sx\n" -"CQPfTq3//ygH4x6paxkg+N6J8LPJMz6Rtb/R+QP2je9FlQvk9U1GEKArcLBFI0R/\n" -"XWOAgZHwBWd1nU0NjFY/qeQmIR02Q5LWQ7C8eG4X8MafriSShO6RSGCdtHwVhWq+\n" -"59ztfL3L7skQMFn37K3xS0LCMVpOcLfTeeFEgxjthVvG3OydPOJlGubiEbiaSEZf\n" -"cif/PUXKDYZMdIVzUsw0ryXykJ5qXKuizHFlv5oQtDCJKFBLgjBbLC2YluaIdekz\n" -"8gkCggEBAJWxS7EuB/qL7fOz0o3HRy0plR3qbwZ0pLoCz0Ii7WxraBS1yQwmxif1\n" -"Rgv89GyFqg1yQl3CSrMiw7oC9WxxxuiEZDO18c4KO3NTv9K4itN9OPQVBTHmEhod\n" -"KWcyP4/W/Sfuae77PyclSqUsAARRrKYn2fpLTS5ibaU0QZgHmdPgYDUrPr+6PHKK\n" -"ZfQKU2uBfuo6zoMbMmFi3UYG49j9rv4d6v+44vS1MPHV9JK/LD8YfBhgx8Pg/u6D\n" -"nUgipS48pkGjJr2u2Vu7Mx70vqz0Yf2neyyDbdLtkYauC4w7YKPTD0yzDJyGuAeB\n" -"GyPbW1yZa5vE302a1Cr0Cd7RC4AFAAw=\n" -"-----END PRIVATE KEY-----"; - struct test_files_set get_test_files_set(void) { static struct test_file files[] = { @@ -290,7 +195,7 @@ char *bin2hex(char *dst, const void *src, size_t count) return dst; } -static char *get_index_filename(char *mnt_dir, incfs_uuid_t id) +static char *get_index_filename(const char *mnt_dir, incfs_uuid_t id) { char path[FILENAME_MAX]; char str_id[1 + 2 * sizeof(id)]; @@ -301,15 +206,43 @@ static char *get_index_filename(char *mnt_dir, incfs_uuid_t id) return strdup(path); } -int open_file_by_id(char *mnt_dir, incfs_uuid_t id) +int open_file_by_id(const char *mnt_dir, incfs_uuid_t id, bool use_ioctl) { char *path = get_index_filename(mnt_dir, id); - int fd = open(path, O_RDWR); + int cmd_fd = open_commands_file(mnt_dir); + int fd = open(path, O_RDWR | O_CLOEXEC); + struct incfs_permit_fill permit_fill = { + .file_descriptor = fd, + }; + int error = 0; - free(path); if (fd < 0) { print_error("Can't open file by id."); + error = -errno; + goto out; + } + + if (use_ioctl && ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) { + print_error("Failed to call PERMIT_FILL"); + error = -errno; + goto out; + } + + if (ioctl(fd, INCFS_IOC_PERMIT_FILL, &permit_fill) != -1 || + errno != EPERM) { + print_error( + "Successfully called PERMIT_FILL on non pending_read file"); return -errno; + goto out; + } + +out: + free(path); + close(cmd_fd); + + if (error) { + close(fd); + return error; } return fd; @@ -343,20 +276,18 @@ static int emit_test_blocks(char *mnt_dir, struct test_file *file, uint8_t *data_buf = malloc(data_buf_size); uint8_t *current_data = data_buf; uint8_t *data_end = data_buf + data_buf_size; - struct incfs_new_data_block *block_buf = - calloc(block_count, sizeof(*block_buf)); + struct incfs_fill_block *block_buf = + calloc(block_count, sizeof(struct incfs_fill_block)); + struct incfs_fill_blocks fill_blocks = { + .count = block_count, + .fill_blocks = ptr_to_u64(block_buf), + }; ssize_t write_res = 0; - int fd; + int fd = -1; int error = 0; int i = 0; int blocks_written = 0; - fd = open_file_by_id(mnt_dir, file->id); - if (fd <= 0) { - error = -errno; - goto out; - } - for (i = 0; i < block_count; i++) { int block_index = blocks[i]; bool compress = (file->index + block_index) % 2 == 0; @@ -404,17 +335,33 @@ static int emit_test_blocks(char *mnt_dir, struct test_file *file, block_buf[i].block_index = block_index; block_buf[i].data_len = block_size; block_buf[i].data = ptr_to_u64(current_data); - block_buf[i].compression = - compress ? COMPRESSION_LZ4 : COMPRESSION_NONE; current_data += block_size; } if (!error) { - write_res = write(fd, block_buf, sizeof(*block_buf) * i); + fd = open_file_by_id(mnt_dir, file->id, false); + if (fd < 0) { + error = -errno; + goto out; + } + write_res = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks); + if (write_res >= 0) { + ksft_print_msg("Wrote to file via normal fd error\n"); + error = -EPERM; + goto out; + } + + close(fd); + fd = open_file_by_id(mnt_dir, file->id, true); + if (fd < 0) { + error = -errno; + goto out; + } + write_res = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks); if (write_res < 0) error = -errno; else - blocks_written = write_res / sizeof(*block_buf); + blocks_written = write_res; } if (error) { ksft_print_msg( @@ -499,7 +446,7 @@ static loff_t read_whole_file(char *filename) loff_t bytes_read = 0; uint8_t buff[16 * 1024]; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_CLOEXEC); if (fd <= 0) return fd; @@ -531,7 +478,7 @@ static int read_test_file(uint8_t *buf, size_t len, char *filename, size_t bytes_to_read = len; off_t offset = ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_CLOEXEC); if (fd <= 0) return fd; @@ -720,8 +667,6 @@ static int build_mtree(struct test_file *file) int tree_lvl_index[INCFS_MAX_MTREE_LEVELS] = {}; int tree_lvl_count[INCFS_MAX_MTREE_LEVELS] = {}; int levels_count = 0; - char data_to_sign[256] = {}; - int sig_data_size; int i, level; if (file->size == 0) @@ -748,8 +693,9 @@ static int build_mtree(struct test_file *file) if (block_count == 1) { int seed = get_file_block_seed(file->index, 0); + memset(data, 0, INCFS_DATA_FILE_BLOCK_SIZE); rnd_buf((uint8_t *)data, file->size, seed); - sha256(data, file->size, file->root_hash); + sha256(data, INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash); return 0; } @@ -764,11 +710,13 @@ static int build_mtree(struct test_file *file) int seed = get_file_block_seed(file->index, i); char *hash_ptr = file->mtree[block_index].data + block_off; - if (file->size - offset < block_size) + if (file->size - offset < block_size) { block_size = file->size - offset; + memset(data, 0, INCFS_DATA_FILE_BLOCK_SIZE); + } rnd_buf((uint8_t *)data, block_size, seed); - sha256(data, block_size, hash_ptr); + sha256(data, INCFS_DATA_FILE_BLOCK_SIZE, hash_ptr); } /* Build higher levels of hash tree. */ @@ -792,19 +740,6 @@ static int build_mtree(struct test_file *file) sha256(file->mtree[0].data, INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash); - /* Calculating digital signature */ - snprintf(file->sig.add_data, sizeof(file->sig.add_data), "%ld", - file->size); - memcpy(data_to_sign, file->root_hash, SHA256_DIGEST_SIZE); - memcpy(data_to_sign + SHA256_DIGEST_SIZE, file->sig.add_data, - strlen(file->sig.add_data)); - sig_data_size = SHA256_DIGEST_SIZE + strlen(file->sig.add_data); - if (!sign_pkcs7(data_to_sign, sig_data_size, private_key, x509_cert, - &file->sig.data, &file->sig.size)) { - ksft_print_msg("Signing failed.\n"); - return -EINVAL; - } - return 0; } @@ -813,21 +748,21 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file) int err; int i; int fd; + struct incfs_fill_blocks fill_blocks = { + .count = file->mtree_block_count, + }; + struct incfs_fill_block *fill_block_array = + calloc(fill_blocks.count, sizeof(struct incfs_fill_block)); - size_t blocks_size = - file->mtree_block_count * sizeof(struct incfs_new_data_block); - struct incfs_new_data_block *blocks = NULL; - char *file_path; - - if (blocks_size == 0) + if (fill_blocks.count == 0) return 0; - blocks = malloc(blocks_size); - if (!blocks) + if (!fill_block_array) return -ENOMEM; + fill_blocks.fill_blocks = ptr_to_u64(fill_block_array); - for (i = 0; i < file->mtree_block_count; i++) { - blocks[i] = (struct incfs_new_data_block){ + for (i = 0; i < fill_blocks.count; i++) { + fill_block_array[i] = (struct incfs_fill_block){ .block_index = i, .data_len = INCFS_DATA_FILE_BLOCK_SIZE, .data = ptr_to_u64(file->mtree[i].data), @@ -835,18 +770,28 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file) }; } - file_path = concat_file_name(mount_dir, file->name); - fd = open(file_path, O_RDWR); - free(file_path); + fd = open_file_by_id(mount_dir, file->id, false); if (fd < 0) { err = errno; goto failure; } - err = write(fd, blocks, blocks_size); + err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks); close(fd); + if (err >= 0) { + err = -EPERM; + goto failure; + } + + fd = open_file_by_id(mount_dir, file->id, true); + if (fd < 0) { + err = errno; + goto failure; + } - if (err < blocks_size) + err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks); + close(fd); + if (err < fill_blocks.count) err = errno; else { err = 0; @@ -854,7 +799,7 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file) } failure: - free(blocks); + free(fill_block_array); return err; } @@ -966,7 +911,7 @@ static bool iterate_directory(char *dir_to_iterate, bool root, int file_count) int i; /* Test directory iteration */ - int fd = open(dir_to_iterate, O_RDONLY | O_DIRECTORY); + int fd = open(dir_to_iterate, O_RDONLY | O_DIRECTORY | O_CLOEXEC); if (fd < 0) { print_error("Can't open directory\n"); @@ -1167,7 +1112,7 @@ static int basic_file_ops_test(char *mount_dir) char *path = concat_file_name(mount_dir, file->name); int fd; - fd = open(path, O_RDWR); + fd = open(path, O_RDWR | O_CLOEXEC); free(path); if (fd <= 0) { print_error("Can't open file"); @@ -1274,13 +1219,6 @@ static int dynamic_files_and_data_test(char *mount_dir) if (i == missing_file_idx) continue; - res = load_hash_tree(mount_dir, file); - if (res) { - ksft_print_msg("Can't load hashes for %s. error: %s\n", - file->name, strerror(-res)); - goto failure; - } - res = emit_test_file_data(mount_dir, file); if (res) { ksft_print_msg("Error %s emiting data for %s.\n", @@ -1479,7 +1417,6 @@ static int work_after_remount_test(char *mount_dir) /* Write first half of the data into the command file. (stage 1) */ for (i = 0; i < file_num_stage1; i++) { struct test_file *file = &test.files[i]; - int res; build_mtree(file); if (emit_file(cmd_fd, NULL, file->name, &file->id, @@ -1488,14 +1425,7 @@ static int work_after_remount_test(char *mount_dir) if (emit_test_file_data(mount_dir, file)) goto failure; - - res = load_hash_tree(mount_dir, file); - if (res) { - ksft_print_msg("Can't load hashes for %s. error: %s\n", - file->name, strerror(-res)); - goto failure; - } -} + } /* Unmount and mount again, to see that data is persistent. */ close(cmd_fd); @@ -1882,162 +1812,6 @@ static int multiple_providers_test(char *mount_dir) return TEST_FAILURE; } -static int signature_test(char *mount_dir) -{ - struct test_files_set test = get_test_files_set(); - const int file_num = test.files_count; - int i = 0; - unsigned char sig_buf[INCFS_MAX_SIGNATURE_SIZE]; - char *backing_dir; - int cmd_fd = -1; - - backing_dir = create_backing_dir(mount_dir); - if (!backing_dir) - goto failure; - - /* Mount FS and release the backing file. (10s wait time) */ - if (mount_fs(mount_dir, backing_dir, 10000) != 0) - goto failure; - - cmd_fd = open_commands_file(mount_dir); - if (cmd_fd < 0) - goto failure; - - /* Write hashes and data. */ - for (i = 0; i < file_num; i++) { - struct test_file *file = &test.files[i]; - int res; - - build_mtree(file); - - res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id, - file->size, file->root_hash, - file->sig.data, file->sig.size, file->sig.add_data); - - if (res) { - ksft_print_msg("Emit failed for %s. error: %s\n", - file->name, strerror(-res)); - goto failure; - } - - if (emit_test_file_data(mount_dir, file)) - goto failure; - - res = load_hash_tree(mount_dir, file); - if (res) { - ksft_print_msg("Can't load hashes for %s. error: %s\n", - file->name, strerror(-res)); - goto failure; - } - } - - /* Validate data */ - for (i = 0; i < file_num; i++) { - struct test_file *file = &test.files[i]; - int sig_len; - char *path; - int fd; - - if (validate_test_file_content(mount_dir, file) < 0) - goto failure; - - path = concat_file_name(mount_dir, file->name); - fd = open(path, O_RDWR); - free(path); - if (fd < 0) { - print_error("Can't open file"); - goto failure; - } - - sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf)); - - if (close(fd)) { - print_error("Can't close file"); - goto failure; - } - - if (sig_len < 0) { - ksft_print_msg("Can't load signature %s. error: %s\n", - file->name, strerror(-sig_len)); - goto failure; - } - - if (sig_len != file->sig.size || - memcmp(sig_buf, file->sig.data, sig_len)) { - ksft_print_msg("Signature mismatch %s.\n", - file->name); - goto failure; - } - } - - /* Unmount and mount again, to make sure the signature is persistent. */ - close(cmd_fd); - cmd_fd = -1; - if (umount(mount_dir) != 0) { - print_error("Can't unmout FS"); - goto failure; - } - if (mount_fs(mount_dir, backing_dir, 50) != 0) - goto failure; - - cmd_fd = open_commands_file(mount_dir); - if (cmd_fd < 0) - goto failure; - - /* Validate data again */ - for (i = 0; i < file_num; i++) { - struct test_file *file = &test.files[i]; - int sig_len; - char *path; - int fd; - - if (validate_test_file_content(mount_dir, file) < 0) - goto failure; - - path = concat_file_name(mount_dir, file->name); - fd = open(path, O_RDWR); - free(path); - if (fd < 0) { - print_error("Can't open file"); - goto failure; - } - - sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf)); - - if (close(fd)) { - print_error("Can't close file"); - goto failure; - } - - if (sig_len < 0) { - ksft_print_msg("Can't load signature %s. error: %s\n", - file->name, strerror(-sig_len)); - goto failure; - } - if (sig_len != file->sig.size || - memcmp(sig_buf, file->sig.data, sig_len)) { - ksft_print_msg("Signature mismatch %s.\n", - file->name); - goto failure; - } - } - - /* Final unmount */ - close(cmd_fd); - cmd_fd = -1; - if (umount(mount_dir) != 0) { - print_error("Can't unmout FS"); - goto failure; - } - return TEST_SUCCESS; - -failure: - close(cmd_fd); - free(backing_dir); - umount(mount_dir); - return TEST_FAILURE; -} - static int hash_tree_test(char *mount_dir) { char *backing_dir; @@ -2066,8 +1840,8 @@ static int hash_tree_test(char *mount_dir) build_mtree(file); res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id, - file->size, file->root_hash, - file->sig.data, file->sig.size, file->sig.add_data); + file->size, file->root_hash, + file->sig.add_data); if (i == corrupted_file_idx) { /* Corrupt third blocks hash */ @@ -2158,48 +1932,88 @@ static int hash_tree_test(char *mount_dir) return TEST_FAILURE; } -static int validate_logs(char *mount_dir, int log_fd, struct test_file *file) +enum expected_log { FULL_LOG, NO_LOG, PARTIAL_LOG }; + +static int validate_logs(char *mount_dir, int log_fd, struct test_file *file, + enum expected_log expected_log) { uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; - struct incfs_pending_read_info prs[100] = {}; + struct incfs_pending_read_info prs[2048] = {}; int prs_size = ARRAY_SIZE(prs); int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int expected_read_block_cnt; int res; int read_count; - int i; + int i, j; char *filename = concat_file_name(mount_dir, file->name); int fd; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_CLOEXEC); free(filename); if (fd <= 0) return TEST_FAILURE; if (block_cnt > prs_size) block_cnt = prs_size; + expected_read_block_cnt = block_cnt; for (i = 0; i < block_cnt; i++) { res = pread(fd, data, sizeof(data), INCFS_DATA_FILE_BLOCK_SIZE * i); + + /* Make some read logs of type SAME_FILE_NEXT_BLOCK */ + if (i % 10 == 0) + usleep(20000); + + /* Skip some blocks to make logs of type SAME_FILE */ + if (i % 10 == 5) { + ++i; + --expected_read_block_cnt; + } + if (res <= 0) goto failure; } - read_count = wait_for_pending_reads(log_fd, 0, prs, prs_size); + read_count = wait_for_pending_reads( + log_fd, expected_log == NO_LOG ? 10 : 0, prs, prs_size); + if (expected_log == NO_LOG) { + if (read_count == 0) + goto success; + if (read_count < 0) + ksft_print_msg("Error reading logged reads %s.\n", + strerror(-read_count)); + else + ksft_print_msg("Somehow read empty logs.\n"); + goto failure; + } + if (read_count < 0) { ksft_print_msg("Error reading logged reads %s.\n", strerror(-read_count)); goto failure; } - if (read_count != block_cnt) { + i = 0; + if (expected_log == PARTIAL_LOG) { + if (read_count == 0) { + ksft_print_msg("No logs %s.\n", file->name); + goto failure; + } + + for (i = 0, j = 0; j < expected_read_block_cnt - read_count; + i++, j++) + if (i % 10 == 5) + ++i; + + } else if (read_count != expected_read_block_cnt) { ksft_print_msg("Bad log read count %s %d %d.\n", file->name, - read_count, block_cnt); + read_count, expected_read_block_cnt); goto failure; } - for (i = 0; i < read_count; i++) { - struct incfs_pending_read_info *read = &prs[i]; + for (j = 0; j < read_count; i++, j++) { + struct incfs_pending_read_info *read = &prs[j]; if (!same_id(&read->file_id, &file->id)) { ksft_print_msg("Bad log read ino %s\n", file->name); @@ -2212,8 +2026,8 @@ static int validate_logs(char *mount_dir, int log_fd, struct test_file *file) goto failure; } - if (i != 0) { - unsigned long psn = prs[i - 1].serial_number; + if (j != 0) { + unsigned long psn = prs[j - 1].serial_number; if (read->serial_number != psn + 1) { ksft_print_msg("Bad log read sn %s %d %d.\n", @@ -2228,7 +2042,12 @@ static int validate_logs(char *mount_dir, int log_fd, struct test_file *file) file->name); goto failure; } + + if (i % 10 == 5) + ++i; } + +success: close(fd); return TEST_SUCCESS; @@ -2242,14 +2061,14 @@ static int read_log_test(char *mount_dir) struct test_files_set test = get_test_files_set(); const int file_num = test.files_count; int i = 0; - int cmd_fd = -1, log_fd = -1; + int cmd_fd = -1, log_fd = -1, drop_caches = -1; char *backing_dir; backing_dir = create_backing_dir(mount_dir); if (!backing_dir) goto failure; - if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0) + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0) goto failure; cmd_fd = open_commands_file(mount_dir); @@ -2257,7 +2076,7 @@ static int read_log_test(char *mount_dir) goto failure; log_fd = open_log_file(mount_dir); - if (cmd_fd < 0) + if (log_fd < 0) ksft_print_msg("Can't open log file.\n"); /* Write data. */ @@ -2276,7 +2095,7 @@ static int read_log_test(char *mount_dir) for (i = 0; i < file_num; i++) { struct test_file *file = &test.files[i]; - if (validate_logs(mount_dir, log_fd, file)) + if (validate_logs(mount_dir, log_fd, file, FULL_LOG)) goto failure; } @@ -2289,7 +2108,7 @@ static int read_log_test(char *mount_dir) goto failure; } - if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0) + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0) goto failure; cmd_fd = open_commands_file(mount_dir); @@ -2297,40 +2116,562 @@ static int read_log_test(char *mount_dir) goto failure; log_fd = open_log_file(mount_dir); - if (cmd_fd < 0) + if (log_fd < 0) ksft_print_msg("Can't open log file.\n"); /* Validate data again */ for (i = 0; i < file_num; i++) { struct test_file *file = &test.files[i]; - if (validate_logs(mount_dir, log_fd, file)) + if (validate_logs(mount_dir, log_fd, file, FULL_LOG)) goto failure; } - /* Final unmount */ + /* + * Unmount and mount again with no read log to make sure poll + * doesn't crash + */ close(cmd_fd); close(log_fd); - free(backing_dir); if (umount(mount_dir) != 0) { print_error("Can't unmout FS"); goto failure; } - return TEST_SUCCESS; + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0,rlog_pages=0", + false) != 0) + goto failure; -failure: - close(cmd_fd); - close(log_fd); - free(backing_dir); - umount(mount_dir); - return TEST_FAILURE; -} + log_fd = open_log_file(mount_dir); + if (log_fd < 0) + ksft_print_msg("Can't open log file.\n"); -static char *setup_mount_dir() -{ - struct stat st; - char *current_dir = getcwd(NULL, 0); + /* Validate data again - note should fail this time */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file, NO_LOG)) + goto failure; + } + + /* + * Remount and check that logs start working again + */ + drop_caches = open("/proc/sys/vm/drop_caches", O_WRONLY | O_CLOEXEC); + if (drop_caches == -1) + goto failure; + i = write(drop_caches, "3", 1); + close(drop_caches); + if (i != 1) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0,rlog_pages=1", + true) != 0) + goto failure; + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file, PARTIAL_LOG)) + goto failure; + } + + /* + * Remount and check that logs start working again + */ + drop_caches = open("/proc/sys/vm/drop_caches", O_WRONLY | O_CLOEXEC); + if (drop_caches == -1) + goto failure; + i = write(drop_caches, "3", 1); + close(drop_caches); + if (i != 1) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0,rlog_pages=4", + true) != 0) + goto failure; + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file, FULL_LOG)) + goto failure; + } + + /* Final unmount */ + close(log_fd); + free(backing_dir); + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + close(log_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int emit_partial_test_file_data(char *mount_dir, struct test_file *file) +{ + int i, j; + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int *block_indexes = NULL; + int result = 0; + int blocks_written = 0; + + if (file->size == 0) + return 0; + + /* Emit 2 blocks, skip 2 blocks etc*/ + block_indexes = calloc(block_cnt, sizeof(*block_indexes)); + for (i = 0, j = 0; i < block_cnt; ++i) + if ((i & 2) == 0) { + block_indexes[j] = i; + ++j; + } + + for (i = 0; i < j; i += blocks_written) { + blocks_written = emit_test_blocks(mount_dir, file, + block_indexes + i, j - i); + if (blocks_written < 0) { + result = blocks_written; + goto out; + } + if (blocks_written == 0) { + result = -EIO; + goto out; + } + } +out: + free(block_indexes); + return result; +} + +static int validate_ranges(const char *mount_dir, struct test_file *file) +{ + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + char *filename = concat_file_name(mount_dir, file->name); + int fd; + struct incfs_filled_range ranges[128]; + struct incfs_get_filled_blocks_args fba = { + .range_buffer = ptr_to_u64(ranges), + .range_buffer_size = sizeof(ranges), + }; + int error = TEST_SUCCESS; + int i; + int range_cnt; + int cmd_fd = -1; + struct incfs_permit_fill permit_fill; + + fd = open(filename, O_RDONLY | O_CLOEXEC); + free(filename); + if (fd <= 0) + return TEST_FAILURE; + + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error != -1 || errno != EPERM) { + ksft_print_msg("INCFS_IOC_GET_FILLED_BLOCKS not blocked\n"); + error = -EPERM; + goto out; + } + + cmd_fd = open_commands_file(mount_dir); + permit_fill.file_descriptor = fd; + if (ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) { + print_error("INCFS_IOC_PERMIT_FILL failed"); + return -EPERM; + goto out; + } + + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error && errno != ERANGE) + goto out; + + if (error && errno == ERANGE && block_cnt < 509) + goto out; + + if (!error && block_cnt >= 509) { + error = -ERANGE; + goto out; + } + + if (fba.total_blocks_out != block_cnt) { + error = -EINVAL; + goto out; + } + + if (fba.data_blocks_out != block_cnt) { + error = -EINVAL; + goto out; + } + + range_cnt = (block_cnt + 3) / 4; + if (range_cnt > 128) + range_cnt = 128; + if (range_cnt != fba.range_buffer_size_out / sizeof(*ranges)) { + error = -ERANGE; + goto out; + } + + error = TEST_SUCCESS; + for (i = 0; i < fba.range_buffer_size_out / sizeof(*ranges) - 1; ++i) + if (ranges[i].begin != i * 4 || ranges[i].end != i * 4 + 2) { + error = -EINVAL; + goto out; + } + + if (ranges[i].begin != i * 4 || + (ranges[i].end != i * 4 + 1 && ranges[i].end != i * 4 + 2)) { + error = -EINVAL; + goto out; + } + + for (i = 0; i < 64; ++i) { + fba.start_index = i * 2; + fba.end_index = i * 2 + 2; + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error) + goto out; + + if (fba.total_blocks_out != block_cnt) { + error = -EINVAL; + goto out; + } + + if (fba.start_index >= block_cnt) { + if (fba.index_out != fba.start_index) { + error = -EINVAL; + goto out; + } + + break; + } + + if (i % 2) { + if (fba.range_buffer_size_out != 0) { + error = -EINVAL; + goto out; + } + } else { + if (fba.range_buffer_size_out != sizeof(*ranges)) { + error = -EINVAL; + goto out; + } + + if (ranges[0].begin != i * 2) { + error = -EINVAL; + goto out; + } + + if (ranges[0].end != i * 2 + 1 && + ranges[0].end != i * 2 + 2) { + error = -EINVAL; + goto out; + } + } + } + +out: + close(fd); + close(cmd_fd); + return error; +} + +static int get_blocks_test(char *mount_dir) +{ + char *backing_dir; + int cmd_fd = -1; + int i; + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_file(cmd_fd, NULL, file->name, &file->id, file->size, + NULL)) + goto failure; + + if (emit_partial_test_file_data(mount_dir, file)) + goto failure; + } + + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_ranges(mount_dir, file)) + goto failure; + + /* + * The smallest files are filled completely, so this checks that + * the fast get_filled_blocks path is not causing issues + */ + if (validate_ranges(mount_dir, file)) + goto failure; + } + + close(cmd_fd); + umount(mount_dir); + free(backing_dir); + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + free(backing_dir); + return TEST_FAILURE; +} + +static int emit_partial_test_file_hash(char *mount_dir, struct test_file *file) +{ + int err; + int fd; + struct incfs_fill_blocks fill_blocks = { + .count = 1, + }; + struct incfs_fill_block *fill_block_array = + calloc(fill_blocks.count, sizeof(struct incfs_fill_block)); + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + + if (file->size <= 4096 / 32 * 4096) + return 0; + + if (fill_blocks.count == 0) + return 0; + + if (!fill_block_array) + return -ENOMEM; + fill_blocks.fill_blocks = ptr_to_u64(fill_block_array); + + rnd_buf(data, sizeof(data), 0); + + fill_block_array[0] = + (struct incfs_fill_block){ .block_index = 1, + .data_len = + INCFS_DATA_FILE_BLOCK_SIZE, + .data = ptr_to_u64(data), + .flags = INCFS_BLOCK_FLAGS_HASH }; + + fd = open_file_by_id(mount_dir, file->id, true); + if (fd < 0) { + err = errno; + goto failure; + } + + err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks); + close(fd); + if (err < fill_blocks.count) + err = errno; + else + err = 0; + +failure: + free(fill_block_array); + return err; +} + +static int validate_hash_ranges(const char *mount_dir, struct test_file *file) +{ + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + char *filename = concat_file_name(mount_dir, file->name); + int fd; + struct incfs_filled_range ranges[128]; + struct incfs_get_filled_blocks_args fba = { + .range_buffer = ptr_to_u64(ranges), + .range_buffer_size = sizeof(ranges), + }; + int error = TEST_SUCCESS; + int file_blocks = (file->size + INCFS_DATA_FILE_BLOCK_SIZE - 1) / + INCFS_DATA_FILE_BLOCK_SIZE; + int cmd_fd = -1; + struct incfs_permit_fill permit_fill; + + if (file->size <= 4096 / 32 * 4096) + return 0; + + fd = open(filename, O_RDONLY | O_CLOEXEC); + free(filename); + if (fd <= 0) + return TEST_FAILURE; + + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error != -1 || errno != EPERM) { + ksft_print_msg("INCFS_IOC_GET_FILLED_BLOCKS not blocked\n"); + error = -EPERM; + goto out; + } + + cmd_fd = open_commands_file(mount_dir); + permit_fill.file_descriptor = fd; + if (ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) { + print_error("INCFS_IOC_PERMIT_FILL failed"); + return -EPERM; + goto out; + } + + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error) + goto out; + + if (fba.total_blocks_out <= block_cnt) { + error = -EINVAL; + goto out; + } + + if (fba.data_blocks_out != block_cnt) { + error = -EINVAL; + goto out; + } + + if (fba.range_buffer_size_out != sizeof(struct incfs_filled_range)) { + error = -EINVAL; + goto out; + } + + if (ranges[0].begin != file_blocks + 1 || + ranges[0].end != file_blocks + 2) { + error = -EINVAL; + goto out; + } + +out: + close(cmd_fd); + close(fd); + return error; +} + +static int get_hash_blocks_test(char *mount_dir) +{ + char *backing_dir; + int cmd_fd = -1; + int i; + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (crypto_emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, file->root_hash, + file->sig.add_data)) + goto failure; + + if (emit_partial_test_file_hash(mount_dir, file)) + goto failure; + } + + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_hash_ranges(mount_dir, file)) + goto failure; + } + + close(cmd_fd); + umount(mount_dir); + free(backing_dir); + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + free(backing_dir); + return TEST_FAILURE; +} + +static int large_file(char *mount_dir) +{ + char *backing_dir; + int cmd_fd = -1; + int i; + int result = TEST_FAILURE; + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {}; + int block_count = 3LL * 1024 * 1024 * 1024 / INCFS_DATA_FILE_BLOCK_SIZE; + struct incfs_fill_block *block_buf = + calloc(block_count, sizeof(struct incfs_fill_block)); + struct incfs_fill_blocks fill_blocks = { + .count = block_count, + .fill_blocks = ptr_to_u64(block_buf), + }; + incfs_uuid_t id; + int fd; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + if (emit_file(cmd_fd, NULL, "very_large_file", &id, + (uint64_t)block_count * INCFS_DATA_FILE_BLOCK_SIZE, + NULL) < 0) + goto failure; + + for (i = 0; i < block_count; i++) { + block_buf[i].compression = COMPRESSION_NONE; + block_buf[i].block_index = i; + block_buf[i].data_len = INCFS_DATA_FILE_BLOCK_SIZE; + block_buf[i].data = ptr_to_u64(data); + } + + fd = open_file_by_id(mount_dir, id, true); + if (fd < 0) + goto failure; + + if (ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks) != block_count) + goto failure; + + if (emit_file(cmd_fd, NULL, "very_very_large_file", &id, 1LL << 40, + NULL) < 0) + goto failure; + + result = TEST_SUCCESS; + +failure: + close(fd); + close(cmd_fd); + return result; +} + +static char *setup_mount_dir() +{ + struct stat st; + char *current_dir = getcwd(NULL, 0); char *mount_dir = concat_file_name(current_dir, "incfs-mount-dir"); free(current_dir); @@ -2361,7 +2702,7 @@ int main(int argc, char *argv[]) // NOTE - this abuses the concept of randomness - do *not* ever do this // on a machine for production use - the device will think it has good // randomness when it does not. - fd = open("/dev/urandom", O_WRONLY); + fd = open("/dev/urandom", O_WRONLY | O_CLOEXEC); count = 4096; for (int i = 0; i < 128; ++i) ioctl(fd, RNDADDTOENTCNT, &count); @@ -2392,9 +2733,11 @@ int main(int argc, char *argv[]) MAKE_TEST(work_after_remount_test), MAKE_TEST(child_procs_waiting_for_data_test), MAKE_TEST(multiple_providers_test), - MAKE_TEST(signature_test), MAKE_TEST(hash_tree_test), MAKE_TEST(read_log_test), + MAKE_TEST(get_blocks_test), + MAKE_TEST(get_hash_blocks_test), + MAKE_TEST(large_file), }; #undef MAKE_TEST @@ -2415,7 +2758,7 @@ int main(int argc, char *argv[]) rmdir(mount_dir); if (fails > 0) - ksft_exit_pass(); + ksft_exit_fail(); else ksft_exit_pass(); return 0; diff --git a/tools/testing/selftests/filesystems/incfs/utils.c b/tools/testing/selftests/filesystems/incfs/utils.c index 08b8452ad0bcdbbe5982d1780b6f1dd71ef68396..e194f63ba92224d14a42285b46ff4e4ccac43261 100644 --- a/tools/testing/selftests/filesystems/incfs/utils.c +++ b/tools/testing/selftests/filesystems/incfs/utils.c @@ -2,28 +2,31 @@ /* * Copyright 2018 Google LLC */ -#include -#include #include -#include -#include +#include #include +#include +#include +#include +#include #include + #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include + #include #include #include "utils.h" -int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms) +#ifndef __S_IFREG +#define __S_IFREG S_IFREG +#endif + +int mount_fs(const char *mount_dir, const char *backing_dir, + int read_timeout_ms) { static const char fs_name[] = INCFS_NAME; char mount_options[512]; @@ -39,190 +42,107 @@ int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms) return result; } -int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt) +int mount_fs_opt(const char *mount_dir, const char *backing_dir, + const char *opt, bool remount) { static const char fs_name[] = INCFS_NAME; int result; - result = mount(backing_dir, mount_dir, fs_name, 0, opt); + result = mount(backing_dir, mount_dir, fs_name, + remount ? MS_REMOUNT : 0, opt); if (result != 0) perror("Error mounting fs."); return result; } -int unlink_node(int fd, int parent_ino, char *filename) +struct hash_section { + uint32_t algorithm; + uint8_t log2_blocksize; + uint32_t salt_size; + /* no salt */ + uint32_t hash_size; + uint8_t hash[SHA256_DIGEST_SIZE]; +} __packed; + +struct signature_blob { + uint32_t version; + uint32_t hash_section_size; + struct hash_section hash_section; + uint32_t signing_section_size; + uint8_t signing_section[]; +} __packed; + +size_t format_signature(void **buf, const char *root_hash, const char *add_data) { - return 0; -} - - -static EVP_PKEY *deserialize_private_key(const char *pem_key) -{ - BIO *bio = NULL; - EVP_PKEY *pkey = NULL; - int len = strlen(pem_key); - - bio = BIO_new_mem_buf(pem_key, len); - if (!bio) - return NULL; - - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - BIO_free(bio); - return pkey; -} - -static X509 *deserialize_cert(const char *pem_cert) -{ - BIO *bio = NULL; - X509 *cert = NULL; - int len = strlen(pem_cert); - - bio = BIO_new_mem_buf(pem_cert, len); - if (!bio) - return NULL; - - cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); - BIO_free(bio); - return cert; -} - -bool sign_pkcs7(const void *data_to_sign, size_t data_size, - char *pkey_pem, char *cert_pem, - void **sig_ret, size_t *sig_size_ret) -{ - /* - * PKCS#7 signing flags: - * - * - PKCS7_BINARY signing binary data, so skip MIME translation - * - * - PKCS7_NOATTR omit extra authenticated attributes, such as - * SMIMECapabilities - * - * - PKCS7_PARTIAL PKCS7_sign() creates a handle only, then - * PKCS7_sign_add_signer() can add a signer later. - * This is necessary to change the message digest - * algorithm from the default of SHA-1. Requires - * OpenSSL 1.0.0 or later. - */ - int pkcs7_flags = PKCS7_BINARY | PKCS7_NOATTR | PKCS7_PARTIAL; - void *sig; - size_t sig_size; - BIO *bio = NULL; - PKCS7 *p7 = NULL; - EVP_PKEY *pkey = NULL; - X509 *cert = NULL; - bool ok = false; - - const EVP_MD *md = EVP_sha256(); - - pkey = deserialize_private_key(pkey_pem); - if (!pkey) { - printf("deserialize_private_key failed\n"); - goto out; - } - - cert = deserialize_cert(cert_pem); - if (!cert) { - printf("deserialize_cert failed\n"); - goto out; - } - - bio = BIO_new_mem_buf(data_to_sign, data_size); - if (!bio) - goto out; - - p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags); - if (!p7) { - printf("failed to initialize PKCS#7 signature object\n"); - goto out; - } - - if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) { - printf("failed to add signer to PKCS#7 signature object\n"); - goto out; - } - - if (PKCS7_final(p7, bio, pkcs7_flags) != 1) { - printf("failed to finalize PKCS#7 signature\n"); - goto out; - } - - BIO_free(bio); - bio = BIO_new(BIO_s_mem()); - if (!bio) { - printf("out of memory\n"); - goto out; - } - - if (i2d_PKCS7_bio(bio, p7) != 1) { - printf("failed to DER-encode PKCS#7 signature object\n"); - goto out; - } + size_t size = sizeof(struct signature_blob) + strlen(add_data) + 1; + struct signature_blob *sb = malloc(size); + + *sb = (struct signature_blob){ + .version = INCFS_SIGNATURE_VERSION, + .hash_section_size = sizeof(struct hash_section), + .hash_section = + (struct hash_section){ + .algorithm = INCFS_HASH_TREE_SHA256, + .log2_blocksize = 12, + .salt_size = 0, + .hash_size = SHA256_DIGEST_SIZE, + }, + .signing_section_size = sizeof(uint32_t) + strlen(add_data) + 1, + }; - sig_size = BIO_get_mem_data(bio, &sig); - *sig_ret = malloc(sig_size); - memcpy(*sig_ret, sig, sig_size); - *sig_size_ret = sig_size; - ok = true; -out: - PKCS7_free(p7); - BIO_free(bio); - return ok; + memcpy(sb->hash_section.hash, root_hash, SHA256_DIGEST_SIZE); + memcpy((char *)sb->signing_section, add_data, strlen(add_data) + 1); + *buf = sb; + return size; } -int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, - size_t size, const char *root_hash, char *sig, size_t sig_size, - char *add_data) +int crypto_emit_file(int fd, const char *dir, const char *filename, + incfs_uuid_t *id_out, size_t size, const char *root_hash, + const char *add_data) { int mode = __S_IFREG | 0555; - struct incfs_file_signature_info sig_info = { - .hash_tree_alg = root_hash - ? INCFS_HASH_TREE_SHA256 - : 0, - .root_hash = ptr_to_u64(root_hash), - .additional_data = ptr_to_u64(add_data), - .additional_data_size = strlen(add_data), - .signature = ptr_to_u64(sig), - .signature_size = sig_size, - }; + void *signature; + int error = 0; struct incfs_new_file_args args = { .size = size, .mode = mode, .file_name = ptr_to_u64(filename), .directory_path = ptr_to_u64(dir), - .signature_info = ptr_to_u64(&sig_info), .file_attr = 0, .file_attr_len = 0 }; + args.signature_size = format_signature(&signature, root_hash, add_data); + args.signature_info = ptr_to_u64(signature); + md5(filename, strlen(filename), (char *)args.file_id.bytes); - if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) - return -errno; + if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) { + error = -errno; + goto out; + } *id_out = args.file_id; - return 0; -} +out: + free(signature); + return error; +} -int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, - size_t size, char *attr) +int emit_file(int fd, const char *dir, const char *filename, + incfs_uuid_t *id_out, size_t size, const char *attr) { int mode = __S_IFREG | 0555; - struct incfs_file_signature_info sig_info = { - .hash_tree_alg = 0, - .root_hash = ptr_to_u64(NULL) - }; - struct incfs_new_file_args args = { - .size = size, - .mode = mode, - .file_name = ptr_to_u64(filename), - .directory_path = ptr_to_u64(dir), - .signature_info = ptr_to_u64(&sig_info), - .file_attr = ptr_to_u64(attr), - .file_attr_len = attr ? strlen(attr) : 0 - }; + struct incfs_new_file_args args = { .size = size, + .mode = mode, + .file_name = ptr_to_u64(filename), + .directory_path = ptr_to_u64(dir), + .signature_info = ptr_to_u64(NULL), + .signature_size = 0, + .file_attr = ptr_to_u64(attr), + .file_attr_len = + attr ? strlen(attr) : 0 }; md5(filename, strlen(filename), (char *)args.file_id.bytes); @@ -250,7 +170,7 @@ int get_file_signature(int fd, unsigned char *buf, int buf_size) return -errno; } -loff_t get_file_size(char *name) +loff_t get_file_size(const char *name) { struct stat st; @@ -259,27 +179,27 @@ loff_t get_file_size(char *name) return -ENOENT; } -int open_commands_file(char *mount_dir) +int open_commands_file(const char *mount_dir) { char cmd_file[255]; int cmd_fd; snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME); - cmd_fd = open(cmd_file, O_RDONLY); + cmd_fd = open(cmd_file, O_RDONLY | O_CLOEXEC); if (cmd_fd < 0) perror("Can't open commands file"); return cmd_fd; } -int open_log_file(char *mount_dir) +int open_log_file(const char *mount_dir) { char cmd_file[255]; int cmd_fd; snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/.log", mount_dir); - cmd_fd = open(cmd_file, O_RDWR); + cmd_fd = open(cmd_file, O_RDWR | O_CLOEXEC); if (cmd_fd < 0) perror("Can't open log file"); return cmd_fd; @@ -358,7 +278,7 @@ int delete_dir_tree(const char *dir_path) return result; } -void sha256(char *data, size_t dsize, char *hash) +void sha256(const char *data, size_t dsize, char *hash) { SHA256_CTX ctx; @@ -367,7 +287,7 @@ void sha256(char *data, size_t dsize, char *hash) SHA256_Final((unsigned char *)hash, &ctx); } -void md5(char *data, size_t dsize, char *hash) +void md5(const char *data, size_t dsize, char *hash) { MD5_CTX ctx; diff --git a/tools/testing/selftests/filesystems/incfs/utils.h b/tools/testing/selftests/filesystems/incfs/utils.h index 9c9ba3c5f70a54b69cfffebba7692d34395e9d1f..9af63e4e922c5f2866ac424eec647356f2fd3e9a 100644 --- a/tools/testing/selftests/filesystems/incfs/utils.h +++ b/tools/testing/selftests/filesystems/incfs/utils.h @@ -5,10 +5,12 @@ #include #include -#include "../../include/uapi/linux/incrementalfs.h" +#include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#define __packed __attribute__((__packed__)) + #ifdef __LP64__ #define ptr_to_u64(p) ((__u64)p) #else @@ -17,9 +19,11 @@ #define SHA256_DIGEST_SIZE 32 -int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms); +int mount_fs(const char *mount_dir, const char *backing_dir, + int read_timeout_ms); -int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt); +int mount_fs_opt(const char *mount_dir, const char *backing_dir, + const char *opt, bool remount); int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size); @@ -28,32 +32,26 @@ int get_file_signature(int fd, unsigned char *buf, int buf_size); int emit_node(int fd, char *filename, int *ino_out, int parent_ino, size_t size, mode_t mode, char *attr); -int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, - size_t size, char *attr); - -int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, - size_t size, const char *root_hash, char *sig, size_t sig_size, - char *add_data); +int emit_file(int fd, const char *dir, const char *filename, + incfs_uuid_t *id_out, size_t size, const char *attr); -int unlink_node(int fd, int parent_ino, char *filename); +int crypto_emit_file(int fd, const char *dir, const char *filename, + incfs_uuid_t *id_out, size_t size, const char *root_hash, + const char *add_data); -loff_t get_file_size(char *name); +loff_t get_file_size(const char *name); -int open_commands_file(char *mount_dir); +int open_commands_file(const char *mount_dir); -int open_log_file(char *mount_dir); +int open_log_file(const char *mount_dir); int wait_for_pending_reads(int fd, int timeout_ms, struct incfs_pending_read_info *prs, int prs_count); char *concat_file_name(const char *dir, char *file); -void sha256(char *data, size_t dsize, char *hash); - -void md5(char *data, size_t dsize, char *hash); +void sha256(const char *data, size_t dsize, char *hash); -bool sign_pkcs7(const void *data_to_sign, size_t data_size, - char *pkey_pem, char *cert_pem, - void **sig_ret, size_t *sig_size_ret); +void md5(const char *data, size_t dsize, char *hash); int delete_dir_tree(const char *path); diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c index c5587844fbb8c6e2e5254ea050f6167c834186ad..ad723a5d0f831779d5db43625169935627b30486 100644 --- a/tools/testing/selftests/ipc/msgque.c +++ b/tools/testing/selftests/ipc/msgque.c @@ -137,7 +137,7 @@ int dump_queue(struct msgque_data *msgque) for (kern_id = 0; kern_id < 256; kern_id++) { ret = msgctl(kern_id, MSG_STAT, &ds); if (ret < 0) { - if (errno == -EINVAL) + if (errno == EINVAL) continue; printf("Failed to get stats for IPC queue with id %d\n", kern_id); diff --git a/tools/testing/selftests/kmod/kmod.sh b/tools/testing/selftests/kmod/kmod.sh index 7956ea3be6675ff865e6671a2b47eba87fc30b06..eed5d5b81226b2ccee702ac4298dfb702f363d81 100755 --- a/tools/testing/selftests/kmod/kmod.sh +++ b/tools/testing/selftests/kmod/kmod.sh @@ -502,18 +502,23 @@ function test_num() fi } -function get_test_count() +function get_test_data() { test_num $1 - TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + local field_num=$(echo $1 | sed 's/^0*//') + echo $ALL_TESTS | awk '{print $'$field_num'}' +} + +function get_test_count() +{ + TEST_DATA=$(get_test_data $1) LAST_TWO=${TEST_DATA#*:*} echo ${LAST_TWO%:*} } function get_test_enabled() { - test_num $1 - TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + TEST_DATA=$(get_test_data $1) echo ${TEST_DATA#*:*:} } diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index 5bef05d6ba3935c4c288faec8c8efc83ed4a3849..c9be64dc681d2fe6289a0658f64e1f77aeac7aa2 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -54,17 +54,20 @@ else $(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS)) endif +define INSTALL_SINGLE_RULE + $(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH)) + $(if $(INSTALL_LIST),@echo rsync -a $(INSTALL_LIST) $(INSTALL_PATH)/) + $(if $(INSTALL_LIST),@rsync -a $(INSTALL_LIST) $(INSTALL_PATH)/) +endef + define INSTALL_RULE - @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \ - mkdir -p ${INSTALL_PATH}; \ - echo "rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/"; \ - rsync -a $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(INSTALL_PATH)/; \ - fi - @if [ "X$(TEST_GEN_PROGS)$(TEST_CUSTOM_PROGS)$(TEST_GEN_PROGS_EXTENDED)$(TEST_GEN_FILES)" != "X" ]; then \ - mkdir -p ${INSTALL_PATH}; \ - echo "rsync -a $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/"; \ - rsync -a $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(INSTALL_PATH)/; \ - fi + $(eval INSTALL_LIST = $(TEST_PROGS)) $(INSTALL_SINGLE_RULE) + $(eval INSTALL_LIST = $(TEST_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE) + $(eval INSTALL_LIST = $(TEST_FILES)) $(INSTALL_SINGLE_RULE) + $(eval INSTALL_LIST = $(TEST_GEN_PROGS)) $(INSTALL_SINGLE_RULE) + $(eval INSTALL_LIST = $(TEST_CUSTOM_PROGS)) $(INSTALL_SINGLE_RULE) + $(eval INSTALL_LIST = $(TEST_GEN_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE) + $(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE) endef install: all diff --git a/tools/testing/selftests/size/get_size.c b/tools/testing/selftests/size/get_size.c index d4b59ab979a0939f71684c4fcbfa09d8be7c907e..f55943b6d1e2ab9796c844438e2e964c8bd6724a 100644 --- a/tools/testing/selftests/size/get_size.c +++ b/tools/testing/selftests/size/get_size.c @@ -12,23 +12,35 @@ * own execution. It also attempts to have as few dependencies * on kernel features as possible. * - * It should be statically linked, with startup libs avoided. - * It uses no library calls, and only the following 3 syscalls: + * It should be statically linked, with startup libs avoided. It uses + * no library calls except the syscall() function for the following 3 + * syscalls: * sysinfo(), write(), and _exit() * * For output, it avoids printf (which in some C libraries * has large external dependencies) by implementing it's own * number output and print routines, and using __builtin_strlen() + * + * The test may crash if any of the above syscalls fails because in some + * libc implementations (e.g. the GNU C Library) errno is saved in + * thread-local storage, which does not get initialized due to avoiding + * startup libs. */ #include #include +#include #define STDOUT_FILENO 1 static int print(const char *s) { - return write(STDOUT_FILENO, s, __builtin_strlen(s)); + size_t len = 0; + + while (s[len] != '\0') + len++; + + return syscall(SYS_write, STDOUT_FILENO, s, len); } static inline char *num_to_str(unsigned long num, char *buf, int len) @@ -80,12 +92,12 @@ void _start(void) print("TAP version 13\n"); print("# Testing system size.\n"); - ccode = sysinfo(&info); + ccode = syscall(SYS_sysinfo, &info); if (ccode < 0) { print("not ok 1"); print(test_name); print(" ---\n reason: \"could not get sysinfo\"\n ...\n"); - _exit(ccode); + syscall(SYS_exit, ccode); } print("ok 1"); print(test_name); @@ -101,5 +113,5 @@ void _start(void) print(" ...\n"); print("1..1\n"); - _exit(0); + syscall(SYS_exit, 0); } diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c index 6f22238f32173db4ef4d710666807cb5397f7dc0..12aaa063196e7406a08188a64570d46ce407ec91 100644 --- a/tools/testing/selftests/x86/ptrace_syscall.c +++ b/tools/testing/selftests/x86/ptrace_syscall.c @@ -414,8 +414,12 @@ int main() #if defined(__i386__) && (!defined(__GLIBC__) || __GLIBC__ > 2 || __GLIBC_MINOR__ >= 16) vsyscall32 = (void *)getauxval(AT_SYSINFO); - printf("[RUN]\tCheck AT_SYSINFO return regs\n"); - test_sys32_regs(do_full_vsyscall32); + if (vsyscall32) { + printf("[RUN]\tCheck AT_SYSINFO return regs\n"); + test_sys32_regs(do_full_vsyscall32); + } else { + printf("[SKIP]\tAT_SYSINFO is not available\n"); + } #endif test_ptrace_syscall_restart(); diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c index b4c37e76a6e08f7973bcf324dd87a612d621546d..187dfaa67d0a2d8e9b6f1b804eff87dc0de7b321 100644 --- a/tools/usb/usbip/src/usbip_network.c +++ b/tools/usb/usbip/src/usbip_network.c @@ -62,39 +62,39 @@ void usbip_setup_port_number(char *arg) info("using port %d (\"%s\")", usbip_port, usbip_port_string); } -void usbip_net_pack_uint32_t(int pack, uint32_t *num) +uint32_t usbip_net_pack_uint32_t(int pack, uint32_t num) { uint32_t i; if (pack) - i = htonl(*num); + i = htonl(num); else - i = ntohl(*num); + i = ntohl(num); - *num = i; + return i; } -void usbip_net_pack_uint16_t(int pack, uint16_t *num) +uint16_t usbip_net_pack_uint16_t(int pack, uint16_t num) { uint16_t i; if (pack) - i = htons(*num); + i = htons(num); else - i = ntohs(*num); + i = ntohs(num); - *num = i; + return i; } void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) { - usbip_net_pack_uint32_t(pack, &udev->busnum); - usbip_net_pack_uint32_t(pack, &udev->devnum); - usbip_net_pack_uint32_t(pack, &udev->speed); + udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum); + udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum); + udev->speed = usbip_net_pack_uint32_t(pack, udev->speed); - usbip_net_pack_uint16_t(pack, &udev->idVendor); - usbip_net_pack_uint16_t(pack, &udev->idProduct); - usbip_net_pack_uint16_t(pack, &udev->bcdDevice); + udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor); + udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct); + udev->bcdDevice = usbip_net_pack_uint16_t(pack, udev->bcdDevice); } void usbip_net_pack_usb_interface(int pack __attribute__((unused)), @@ -141,6 +141,14 @@ ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) return usbip_net_xmit(sockfd, buff, bufflen, 1); } +static inline void usbip_net_pack_op_common(int pack, + struct op_common *op_common) +{ + op_common->version = usbip_net_pack_uint16_t(pack, op_common->version); + op_common->code = usbip_net_pack_uint16_t(pack, op_common->code); + op_common->status = usbip_net_pack_uint32_t(pack, op_common->status); +} + int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) { struct op_common op_common; @@ -152,7 +160,7 @@ int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) op_common.code = code; op_common.status = status; - PACK_OP_COMMON(1, &op_common); + usbip_net_pack_op_common(1, &op_common); rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); if (rc < 0) { @@ -176,7 +184,7 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code) goto err; } - PACK_OP_COMMON(0, &op_common); + usbip_net_pack_op_common(0, &op_common); if (op_common.version != USBIP_VERSION) { dbg("version mismatch: %d %d", op_common.version, diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h index 7032687621d3b503edb38f6ad69926631633c7b4..8e8330c0f1c9c07dd054fe43fbb61af92d734450 100644 --- a/tools/usb/usbip/src/usbip_network.h +++ b/tools/usb/usbip/src/usbip_network.h @@ -34,12 +34,6 @@ struct op_common { } __attribute__((packed)); -#define PACK_OP_COMMON(pack, op_common) do {\ - usbip_net_pack_uint16_t(pack, &(op_common)->version);\ - usbip_net_pack_uint16_t(pack, &(op_common)->code);\ - usbip_net_pack_uint32_t(pack, &(op_common)->status);\ -} while (0) - /* ---------------------------------------------------------------------- */ /* Dummy Code */ #define OP_UNSPEC 0x00 @@ -165,11 +159,11 @@ struct op_devlist_reply_extra { } while (0) #define PACK_OP_DEVLIST_REPLY(pack, reply) do {\ - usbip_net_pack_uint32_t(pack, &(reply)->ndev);\ + (reply)->ndev = usbip_net_pack_uint32_t(pack, (reply)->ndev);\ } while (0) -void usbip_net_pack_uint32_t(int pack, uint32_t *num); -void usbip_net_pack_uint16_t(int pack, uint16_t *num); +uint32_t usbip_net_pack_uint32_t(int pack, uint32_t num); +uint16_t usbip_net_pack_uint16_t(int pack, uint16_t num); void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev); void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf); diff --git a/tools/vm/Makefile b/tools/vm/Makefile index 20f6cf04377f0c257aeb4bacb3133b6a35e9e9b6..9860622cbb151126571ef0962cdab5735c59c5dd 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for vm tools # +include ../scripts/Makefile.include + TARGETS=page-types slabinfo page_owner_sort LIB_DIR = ../lib/api diff --git a/usr/Kconfig b/usr/Kconfig index 43658b8a975e57a8d8b98ce0c1fd78e7e810afe3..8b4826de1189f9cdb1f73b412aec078829974138 100644 --- a/usr/Kconfig +++ b/usr/Kconfig @@ -131,17 +131,6 @@ choice If in doubt, select 'None' -config INITRAMFS_COMPRESSION_NONE - bool "None" - help - Do not compress the built-in initramfs at all. This may sound wasteful - in space, but, you should be aware that the built-in initramfs will be - compressed at a later stage anyways along with the rest of the kernel, - on those architectures that support this. However, not compressing the - initramfs may lead to slightly higher memory consumption during a - short time at boot, while both the cpio image and the unpacked - filesystem image will be present in memory simultaneously - config INITRAMFS_COMPRESSION_GZIP bool "Gzip" depends on RD_GZIP @@ -214,6 +203,17 @@ config INITRAMFS_COMPRESSION_LZ4 If you choose this, keep in mind that most distros don't provide lz4 by default which could cause a build failure. +config INITRAMFS_COMPRESSION_NONE + bool "None" + help + Do not compress the built-in initramfs at all. This may sound wasteful + in space, but, you should be aware that the built-in initramfs will be + compressed at a later stage anyways along with the rest of the kernel, + on those architectures that support this. However, not compressing the + initramfs may lead to slightly higher memory consumption during a + short time at boot, while both the cpio image and the unpacked + filesystem image will be present in memory simultaneously + endchoice config INITRAMFS_COMPRESSION diff --git a/virt/kvm/arm/mmio.c b/virt/kvm/arm/mmio.c index 3caee91bca08907ad7aa18a822e1cb40525ae279..878e0edb2e1b7fe84ba11c33568e7a61e6f259ad 100644 --- a/virt/kvm/arm/mmio.c +++ b/virt/kvm/arm/mmio.c @@ -117,6 +117,9 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) data = (data ^ mask) - mask; } + if (!vcpu->arch.mmio_decode.sixty_four) + data = data & 0xffffffff; + trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, &data); data = vcpu_data_host_to_guest(vcpu, data, len); @@ -137,6 +140,7 @@ static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len) unsigned long rt; int access_size; bool sign_extend; + bool sixty_four; if (kvm_vcpu_dabt_iss1tw(vcpu)) { /* page table accesses IO mem: tell guest to fix its TTBR */ @@ -150,11 +154,13 @@ static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len) *is_write = kvm_vcpu_dabt_iswrite(vcpu); sign_extend = kvm_vcpu_dabt_issext(vcpu); + sixty_four = kvm_vcpu_dabt_issf(vcpu); rt = kvm_vcpu_dabt_get_rd(vcpu); *len = access_size; vcpu->arch.mmio_decode.sign_extend = sign_extend; vcpu->arch.mmio_decode.rt = rt; + vcpu->arch.mmio_decode.sixty_four = sixty_four; return 0; } diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 9f69202d8e49b4fcc22ee3445d1598e1f93b2e08..3814cdad643a544081c034507395d5fd8d336aa6 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1736,7 +1736,8 @@ int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) if (!kvm->arch.pgd) return 0; trace_kvm_test_age_hva(hva); - return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL); + return handle_hva_to_gpa(kvm, hva, hva + PAGE_SIZE, + kvm_test_age_hva_handler, NULL); } void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 526d808ecbbd9d0f15a1f8514daabc3e11bb46f3..8354ec4ef912e54bd1ab2e234983f0f8a60e2b13 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -2210,7 +2210,8 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz) target_addr = (u32)(val >> KVM_ITS_CTE_RDBASE_SHIFT); coll_id = val & KVM_ITS_CTE_ICID_MASK; - if (target_addr >= atomic_read(&kvm->online_vcpus)) + if (target_addr != COLLECTION_NOT_MAPPED && + target_addr >= atomic_read(&kvm->online_vcpus)) return -EINVAL; collection = find_collection(its, coll_id); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index deff4b3eb972269559f866ec3dc5abf181e6941b..71f77ae6c2a6618b498264376f4207b2ce5dc868 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1277,14 +1277,14 @@ bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) } EXPORT_SYMBOL_GPL(kvm_is_visible_gfn); -unsigned long kvm_host_page_size(struct kvm *kvm, gfn_t gfn) +unsigned long kvm_host_page_size(struct kvm_vcpu *vcpu, gfn_t gfn) { struct vm_area_struct *vma; unsigned long addr, size; size = PAGE_SIZE; - addr = gfn_to_hva(kvm, gfn); + addr = kvm_vcpu_gfn_to_hva_prot(vcpu, gfn, NULL); if (kvm_is_error_hva(addr)) return PAGE_SIZE; @@ -2027,12 +2027,12 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, if (slots->generation != ghc->generation) __kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len); - if (unlikely(!ghc->memslot)) - return kvm_write_guest(kvm, gpa, data, len); - if (kvm_is_error_hva(ghc->hva)) return -EFAULT; + if (unlikely(!ghc->memslot)) + return kvm_write_guest(kvm, gpa, data, len); + r = __copy_to_user((void __user *)ghc->hva + offset, data, len); if (r) return -EFAULT; @@ -2060,12 +2060,12 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, if (slots->generation != ghc->generation) __kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len); - if (unlikely(!ghc->memslot)) - return kvm_read_guest(kvm, ghc->gpa, data, len); - if (kvm_is_error_hva(ghc->hva)) return -EFAULT; + if (unlikely(!ghc->memslot)) + return kvm_read_guest(kvm, ghc->gpa, data, len); + r = __copy_from_user(data, (void __user *)ghc->hva, len); if (r) return -EFAULT;