mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 12:58:12 -04:00
Merge remote-tracking branch 'aosp/android-5.4' into android-5.4-stable
Final merge of android-5.4 before KMI freeze Change-Id: Icedf0ccbd2fd7c7d087da026565743771f360b46 Signed-off-by: Todd Kjos <tkjos@google.com>
This commit is contained in:
commit
9489b78a0f
113 changed files with 39743 additions and 37931 deletions
|
|
@ -189,7 +189,8 @@ Description:
|
|||
Access: Read
|
||||
Valid values: "Unknown", "Good", "Overheat", "Dead",
|
||||
"Over voltage", "Unspecified failure", "Cold",
|
||||
"Watchdog timer expire", "Safety timer expire"
|
||||
"Watchdog timer expire", "Safety timer expire",
|
||||
"Over current", "Warm", "Cool", "Hot"
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/precharge_current
|
||||
Date: June 2017
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 30
|
||||
SUBLEVEL = 31
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
|
|
@ -880,7 +880,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_LDS_MODULE += scripts/module-lto.lds
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
|
|
|
|||
78899
abi_gki_aarch64.xml
78899
abi_gki_aarch64.xml
File diff suppressed because it is too large
Load diff
|
|
@ -98,6 +98,7 @@
|
|||
devm_free_irq
|
||||
devm_gpiochip_add_data
|
||||
devm_gpiod_get
|
||||
devm_gpio_free
|
||||
devm_gpio_request
|
||||
devm_hwspin_lock_request_specific
|
||||
__devm_iio_device_register
|
||||
|
|
@ -189,6 +190,7 @@
|
|||
gpiod_direction_output_raw
|
||||
gpiod_get_raw_value
|
||||
gpiod_set_raw_value
|
||||
gpiod_set_raw_value_cansleep
|
||||
gpiod_to_chip
|
||||
gpiod_to_irq
|
||||
gpio_free
|
||||
|
|
@ -199,6 +201,7 @@
|
|||
handle_level_irq
|
||||
i2c_del_driver
|
||||
i2c_register_driver
|
||||
i2c_transfer_buffer_flags
|
||||
i2c_smbus_read_byte_data
|
||||
i2c_smbus_write_byte_data
|
||||
ida_alloc_range
|
||||
|
|
@ -220,6 +223,33 @@
|
|||
input_register_device
|
||||
__ioremap
|
||||
iounmap
|
||||
iommu_alloc_resv_region
|
||||
iommu_attach_device
|
||||
iommu_detach_device
|
||||
iommu_device_register
|
||||
iommu_device_unregister
|
||||
iommu_dma_get_resv_regions
|
||||
iommu_domain_alloc
|
||||
iommu_domain_free
|
||||
iommu_domain_get_attr
|
||||
iommu_domain_set_attr
|
||||
iommu_fwspec_add_ids
|
||||
iommu_fwspec_free
|
||||
iommu_get_dma_cookie
|
||||
iommu_get_domain_for_dev
|
||||
iommu_group_get
|
||||
iommu_group_get_for_dev
|
||||
iommu_group_get_iommudata
|
||||
iommu_group_put
|
||||
iommu_group_ref_get
|
||||
iommu_group_remove_device
|
||||
iommu_group_set_iommudata
|
||||
iommu_map
|
||||
iommu_map_sg
|
||||
iommu_present
|
||||
iommu_put_dma_cookie
|
||||
iommu_set_fault_handler
|
||||
iommu_unmap
|
||||
ip_route_output_flow
|
||||
irq_find_mapping
|
||||
irq_get_irq_data
|
||||
|
|
@ -263,6 +293,8 @@
|
|||
ktime_get_real_seconds
|
||||
ktime_get_real_ts64
|
||||
kzfree
|
||||
__list_add_valid
|
||||
__list_del_entry_valid
|
||||
memcpy
|
||||
memset
|
||||
misc_deregister
|
||||
|
|
@ -435,6 +467,7 @@
|
|||
seq_putc
|
||||
seq_puts
|
||||
seq_read
|
||||
set_normalized_timespec64
|
||||
set_user_nice
|
||||
sg_init_table
|
||||
sg_miter_next
|
||||
|
|
@ -460,6 +493,7 @@
|
|||
snd_pcm_hw_constraint_minmax
|
||||
snd_pcm_lib_ioctl
|
||||
snd_pcm_period_elapsed
|
||||
snd_soc_add_component_controls
|
||||
snd_soc_dapm_disable_pin
|
||||
snd_soc_dapm_enable_pin
|
||||
snd_soc_dapm_ignore_suspend
|
||||
|
|
@ -826,6 +860,9 @@
|
|||
# required by microarray_fp.ko
|
||||
cdev_alloc
|
||||
|
||||
# required by mmc_hsq.ko
|
||||
mmc_cqe_request_done
|
||||
|
||||
# required by musb_hdrc.ko
|
||||
device_wakeup_enable
|
||||
dev_printk
|
||||
|
|
@ -947,6 +984,8 @@
|
|||
memcmp
|
||||
mutex_is_locked
|
||||
of_devfreq_cooling_register_power
|
||||
of_hwspin_lock_get_id_byname
|
||||
of_modalias_node
|
||||
on_each_cpu
|
||||
prepare_to_wait
|
||||
put_unused_fd
|
||||
|
|
@ -1134,6 +1173,7 @@
|
|||
mmc_of_parse
|
||||
mmc_regulator_set_vqmmc
|
||||
mmc_remove_host
|
||||
mmc_request_done
|
||||
__sdhci_add_host
|
||||
sdhci_cleanup_host
|
||||
sdhci_enable_clk
|
||||
|
|
@ -1225,6 +1265,14 @@
|
|||
|
||||
# required by sipc_core.ko
|
||||
gen_pool_destroy
|
||||
mbox_chan_received_data
|
||||
mbox_chan_txdone
|
||||
mbox_client_txdone
|
||||
mbox_controller_register
|
||||
mbox_controller_unregister
|
||||
mbox_free_channel
|
||||
mbox_request_channel
|
||||
mbox_send_message
|
||||
register_syscore_ops
|
||||
|
||||
# required by sipx.ko
|
||||
|
|
@ -1233,6 +1281,15 @@
|
|||
hrtimer_start_range_ns
|
||||
hrtimer_try_to_cancel
|
||||
|
||||
# required by snd-soc-aw881xx.ko
|
||||
i2c_smbus_write_byte
|
||||
|
||||
# required by snd-soc-akm4377.ko
|
||||
regcache_mark_dirty
|
||||
regcache_sync
|
||||
snd_soc_get_volsw
|
||||
snd_soc_put_volsw
|
||||
|
||||
# required by snd-soc-sprd-audio-dma.ko
|
||||
dmam_alloc_attrs
|
||||
dmam_free_coherent
|
||||
|
|
@ -1302,6 +1359,16 @@
|
|||
snd_ctl_boolean_mono_info
|
||||
snd_pcm_hw_constraint_list
|
||||
|
||||
# required by snd-soc-tfa98xx.ko
|
||||
crc32_le
|
||||
device_create_bin_file
|
||||
device_remove_bin_file
|
||||
msleep_interruptible
|
||||
snd_pcm_format_width
|
||||
snd_pcm_hw_constraint_mask64
|
||||
snd_soc_dapm_add_routes
|
||||
snd_soc_dapm_new_controls
|
||||
|
||||
# required by sprd-cpufreq-common.ko
|
||||
dev_pm_opp_remove
|
||||
|
||||
|
|
@ -1328,6 +1395,7 @@
|
|||
dma_get_sgtable_attrs
|
||||
dma_mmap_attrs
|
||||
dma_set_coherent_mask
|
||||
drm_add_edid_modes
|
||||
drm_atomic_helper_async_commit
|
||||
drm_atomic_helper_check
|
||||
drm_atomic_helper_cleanup_planes
|
||||
|
|
@ -1350,17 +1418,33 @@
|
|||
__drm_atomic_helper_plane_destroy_state
|
||||
__drm_atomic_helper_plane_duplicate_state
|
||||
drm_atomic_helper_prepare_planes
|
||||
drm_atomic_helper_resume
|
||||
drm_atomic_helper_set_config
|
||||
drm_atomic_helper_shutdown
|
||||
drm_atomic_helper_suspend
|
||||
drm_atomic_helper_swap_state
|
||||
drm_atomic_helper_update_legacy_modeset_state
|
||||
drm_atomic_helper_update_plane
|
||||
drm_atomic_helper_wait_for_dependencies
|
||||
drm_atomic_helper_wait_for_fences
|
||||
drm_atomic_helper_wait_for_vblanks
|
||||
drm_atomic_private_obj_fini
|
||||
drm_atomic_private_obj_init
|
||||
drm_atomic_set_crtc_for_connector
|
||||
drm_atomic_set_fence_for_plane
|
||||
drm_atomic_set_mode_for_crtc
|
||||
drm_atomic_state_alloc
|
||||
drm_atomic_state_clear
|
||||
drm_atomic_state_default_clear
|
||||
drm_atomic_state_default_release
|
||||
__drm_atomic_state_free
|
||||
drm_bridge_attach
|
||||
drm_connector_attach_content_protection_property
|
||||
drm_connector_attach_encoder
|
||||
drm_connector_cleanup
|
||||
drm_connector_init
|
||||
drm_connector_unregister
|
||||
drm_connector_update_edid_property
|
||||
drm_crtc_cleanup
|
||||
__drm_crtc_commit_free
|
||||
drm_crtc_handle_vblank
|
||||
|
|
@ -1370,9 +1454,21 @@
|
|||
drm_crtc_vblank_on
|
||||
drm_display_mode_from_videomode
|
||||
drm_display_mode_to_videomode
|
||||
drm_dp_aux_register
|
||||
drm_dp_aux_unregister
|
||||
drm_dp_calc_pbn_mode
|
||||
drm_dp_channel_eq_ok
|
||||
drm_dp_clock_recovery_ok
|
||||
drm_dp_dpcd_read
|
||||
drm_dp_dpcd_read_link_status
|
||||
drm_dp_dpcd_write
|
||||
drm_encoder_cleanup
|
||||
drm_encoder_init
|
||||
drm_format_info
|
||||
drm_gem_cma_prime_get_sg_table
|
||||
drm_gem_cma_prime_mmap
|
||||
drm_gem_cma_prime_vmap
|
||||
drm_gem_cma_prime_vunmap
|
||||
drm_gem_cma_vm_ops
|
||||
drm_gem_create_mmap_offset
|
||||
drm_gem_fb_create
|
||||
|
|
@ -1383,12 +1479,19 @@
|
|||
drm_gem_object_init
|
||||
drm_gem_object_put_unlocked
|
||||
drm_gem_object_release
|
||||
drm_gem_prime_export
|
||||
drm_gem_prime_fd_to_handle
|
||||
drm_gem_prime_handle_to_fd
|
||||
drm_gem_prime_import
|
||||
drm_gem_vm_close
|
||||
drm_get_edid
|
||||
drm_hdcp_check_ksvs_revoked
|
||||
drm_hdcp_update_content_protection
|
||||
drm_helper_hpd_irq_event
|
||||
drm_helper_probe_single_connector_modes
|
||||
drm_kms_helper_poll_fini
|
||||
drm_kms_helper_poll_init
|
||||
drm_match_cea_mode
|
||||
drm_mode_config_reset
|
||||
drm_mode_create
|
||||
drm_mode_crtc_set_gamma_size
|
||||
|
|
@ -1628,7 +1731,22 @@
|
|||
free_percpu_irq
|
||||
irq_create_of_mapping
|
||||
panic_notifier_list
|
||||
register_virtio_device
|
||||
register_virtio_driver
|
||||
__request_percpu_irq
|
||||
unregister_virtio_device
|
||||
unregister_virtio_driver
|
||||
virtqueue_add_inbuf
|
||||
virtqueue_add_outbuf
|
||||
virtqueue_detach_unused_buf
|
||||
virtqueue_get_buf
|
||||
virtqueue_get_vring_size
|
||||
virtqueue_kick
|
||||
virtqueue_kick_prepare
|
||||
virtqueue_notify
|
||||
vring_del_virtqueue
|
||||
vring_interrupt
|
||||
vring_new_virtqueue
|
||||
wait_woken
|
||||
woken_wake_function
|
||||
|
||||
|
|
@ -1757,3 +1875,4 @@
|
|||
of_usb_host_tpl_support
|
||||
pci_bus_type
|
||||
__usb_create_hcd
|
||||
usb_hcd_platform_shutdown
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ CONFIG_IKCONFIG=y
|
|||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_IKHEADERS=y
|
||||
CONFIG_UCLAMP_TASK=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_MEMCG=y
|
||||
CONFIG_MEMCG_SWAP=y
|
||||
CONFIG_BLK_CGROUP=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_UCLAMP_TASK_GROUP=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CPUSETS=y
|
||||
|
|
@ -22,7 +24,6 @@ CONFIG_CGROUP_BPF=y
|
|||
CONFIG_NAMESPACES=y
|
||||
# CONFIG_UTS_NS is not set
|
||||
# CONFIG_PID_NS is not set
|
||||
CONFIG_SCHED_AUTOGROUP=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_RD_BZIP2 is not set
|
||||
# CONFIG_RD_LZMA is not set
|
||||
|
|
@ -61,6 +62,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0
|
|||
CONFIG_ENERGY_MODEL=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_ARM_CPUIDLE=y
|
||||
CONFIG_ARM_PSCI_CPUIDLE=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_TIMES=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
|
||||
|
|
@ -206,8 +208,6 @@ CONFIG_CFG80211=y
|
|||
CONFIG_MAC80211=y
|
||||
CONFIG_RFKILL=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
# CONFIG_PCIEAER is not set
|
||||
CONFIG_PCI_HOST_GENERIC=y
|
||||
CONFIG_PCIE_QCOM=y
|
||||
CONFIG_PCIE_KIRIN=y
|
||||
|
|
@ -501,9 +501,10 @@ CONFIG_DEBUG_STACK_USAGE=y
|
|||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_SOFTLOCKUP_DETECTOR=y
|
||||
# CONFIG_DETECT_HUNG_TASK is not set
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_PANIC_ON_OOPS=y
|
||||
CONFIG_PANIC_TIMEOUT=-1
|
||||
CONFIG_SCHEDSTATS=y
|
||||
# CONFIG_DEBUG_PREEMPT is not set
|
||||
CONFIG_DEBUG_LIST=y
|
||||
CONFIG_BUG_ON_DATA_CORRUPTION=y
|
||||
CONFIG_CORESIGHT=y
|
||||
CONFIG_CORESIGHT_STM=y
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@ CONFIG_IKCONFIG=y
|
|||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_IKHEADERS=y
|
||||
CONFIG_UCLAMP_TASK=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_MEMCG=y
|
||||
CONFIG_MEMCG_SWAP=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_UCLAMP_TASK_GROUP=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CPUSETS=y
|
||||
|
|
@ -22,7 +24,6 @@ CONFIG_CGROUP_BPF=y
|
|||
CONFIG_NAMESPACES=y
|
||||
# CONFIG_UTS_NS is not set
|
||||
# CONFIG_PID_NS is not set
|
||||
CONFIG_SCHED_AUTOGROUP=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_RD_BZIP2 is not set
|
||||
# CONFIG_RD_LZMA is not set
|
||||
|
|
@ -437,6 +438,7 @@ CONFIG_DEBUG_STACK_USAGE=y
|
|||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_SOFTLOCKUP_DETECTOR=y
|
||||
# CONFIG_DETECT_HUNG_TASK is not set
|
||||
CONFIG_PANIC_ON_OOPS=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_DEBUG_LIST=y
|
||||
CONFIG_BUG_ON_DATA_CORRUPTION=y
|
||||
|
|
|
|||
|
|
@ -488,21 +488,13 @@ out:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_crypto_start_using_mode() - Start using a crypto algorithm on a device
|
||||
* @mode_num: the blk_crypto_mode we want to allocate ciphers for.
|
||||
* @data_unit_size: the data unit size that will be used
|
||||
* @q: the request queue for the device
|
||||
*
|
||||
* Upper layers must call this function to ensure that a the crypto API fallback
|
||||
* has transforms for this algorithm, if they become necessary.
|
||||
*
|
||||
* Return: 0 on success and -err on error.
|
||||
/*
|
||||
* Prepare blk-crypto-fallback for the specified crypto mode.
|
||||
* Returns -ENOPKG if the needed crypto API support is missing.
|
||||
*/
|
||||
int blk_crypto_start_using_mode(enum blk_crypto_mode_num mode_num,
|
||||
unsigned int data_unit_size,
|
||||
struct request_queue *q)
|
||||
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;
|
||||
|
|
@ -515,25 +507,20 @@ int blk_crypto_start_using_mode(enum blk_crypto_mode_num mode_num,
|
|||
if (likely(smp_load_acquire(&tfms_inited[mode_num])))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the keyslot manager of the request queue supports this
|
||||
* crypto mode, then we don't need to allocate this mode.
|
||||
*/
|
||||
if (keyslot_manager_crypto_mode_supported(q->ksm, mode_num,
|
||||
data_unit_size))
|
||||
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(
|
||||
blk_crypto_modes[mode_num].cipher_str,
|
||||
0, 0);
|
||||
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;
|
||||
}
|
||||
|
|
@ -559,7 +546,6 @@ out:
|
|||
mutex_unlock(&tfms_init_lock);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_crypto_start_using_mode);
|
||||
|
||||
int blk_crypto_fallback_evict_key(const struct blk_crypto_key *key)
|
||||
{
|
||||
|
|
@ -615,9 +601,11 @@ int __init blk_crypto_fallback_init(void)
|
|||
crypto_mode_supported[i] = 0xFFFFFFFF;
|
||||
crypto_mode_supported[BLK_ENCRYPTION_MODE_INVALID] = 0;
|
||||
|
||||
blk_crypto_ksm = keyslot_manager_create(NULL, blk_crypto_num_keyslots,
|
||||
&blk_crypto_ksm_ll_ops,
|
||||
crypto_mode_supported, NULL);
|
||||
blk_crypto_ksm = keyslot_manager_create(
|
||||
NULL, blk_crypto_num_keyslots,
|
||||
&blk_crypto_ksm_ll_ops,
|
||||
BLK_CRYPTO_FEATURE_STANDARD_KEYS,
|
||||
crypto_mode_supported, NULL);
|
||||
if (!blk_crypto_ksm)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ 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);
|
||||
|
|
@ -29,6 +31,13 @@ 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;
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@ int blk_crypto_submit_bio(struct bio **bio_ptr)
|
|||
/* Get device keyslot if supported */
|
||||
if (keyslot_manager_crypto_mode_supported(q->ksm,
|
||||
bc->bc_key->crypto_mode,
|
||||
bc->bc_key->data_unit_size)) {
|
||||
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;
|
||||
|
|
@ -232,6 +233,38 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
|
|||
}
|
||||
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
|
||||
* @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 data_unit_size,
|
||||
bool is_hw_wrapped_key,
|
||||
struct request_queue *q)
|
||||
{
|
||||
if (keyslot_manager_crypto_mode_supported(q->ksm, crypto_mode,
|
||||
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
|
||||
|
|
@ -252,7 +285,8 @@ int blk_crypto_evict_key(struct request_queue *q,
|
|||
{
|
||||
if (q->ksm &&
|
||||
keyslot_manager_crypto_mode_supported(q->ksm, key->crypto_mode,
|
||||
key->data_unit_size))
|
||||
key->data_unit_size,
|
||||
key->is_hw_wrapped))
|
||||
return keyslot_manager_evict_key(q->ksm, key);
|
||||
|
||||
return blk_crypto_fallback_evict_key(key);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct keyslot {
|
|||
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];
|
||||
void *ll_priv_data;
|
||||
|
||||
|
|
@ -135,6 +136,8 @@ static inline void keyslot_manager_hw_exit(struct keyslot_manager *ksm)
|
|||
* @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
|
||||
|
|
@ -154,6 +157,7 @@ struct keyslot_manager *keyslot_manager_create(
|
|||
struct device *dev,
|
||||
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)
|
||||
{
|
||||
|
|
@ -175,6 +179,7 @@ struct keyslot_manager *keyslot_manager_create(
|
|||
|
||||
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->ll_priv_data = ll_priv_data;
|
||||
|
|
@ -381,23 +386,24 @@ void keyslot_manager_put_slot(struct keyslot_manager *ksm, unsigned int slot)
|
|||
}
|
||||
|
||||
/**
|
||||
* keyslot_manager_crypto_mode_supported() - Find out if a crypto_mode/data
|
||||
* unit size combination is supported
|
||||
* by a ksm.
|
||||
* 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.
|
||||
* @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_mode/
|
||||
* data_unit_size combo.
|
||||
* 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 data_unit_size)
|
||||
unsigned int data_unit_size,
|
||||
bool is_hw_wrapped_key)
|
||||
{
|
||||
if (!ksm)
|
||||
return false;
|
||||
|
|
@ -405,6 +411,13 @@ bool keyslot_manager_crypto_mode_supported(struct keyslot_manager *ksm,
|
|||
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;
|
||||
}
|
||||
return ksm->crypto_mode_supported[crypto_mode] & data_unit_size;
|
||||
}
|
||||
|
||||
|
|
@ -520,6 +533,7 @@ EXPORT_SYMBOL_GPL(keyslot_manager_destroy);
|
|||
* keyslot_manager_create_passthrough() - Create a passthrough keyslot manager
|
||||
* @dev: Device for runtime power management (NULL if none)
|
||||
* @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.
|
||||
*
|
||||
|
|
@ -537,6 +551,7 @@ EXPORT_SYMBOL_GPL(keyslot_manager_destroy);
|
|||
struct keyslot_manager *keyslot_manager_create_passthrough(
|
||||
struct device *dev,
|
||||
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)
|
||||
{
|
||||
|
|
@ -547,6 +562,7 @@ struct keyslot_manager *keyslot_manager_create_passthrough(
|
|||
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->ll_priv_data = ll_priv_data;
|
||||
|
|
@ -575,11 +591,13 @@ void keyslot_manager_intersect_modes(struct keyslot_manager *parent,
|
|||
if (child) {
|
||||
unsigned int i;
|
||||
|
||||
parent->features &= child->features;
|
||||
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;
|
||||
memset(parent->crypto_mode_supported, 0,
|
||||
sizeof(parent->crypto_mode_supported));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1342,6 +1342,8 @@ Run:
|
|||
error = dpm_run_callback(callback, dev, state, info);
|
||||
if (error) {
|
||||
async_error = error;
|
||||
log_suspend_abort_reason("Callback failed on %s in %pS returned %d",
|
||||
dev_name(dev), callback, error);
|
||||
goto Complete;
|
||||
}
|
||||
|
||||
|
|
@ -1549,6 +1551,8 @@ Run:
|
|||
error = dpm_run_callback(callback, dev, state, info);
|
||||
if (error) {
|
||||
async_error = error;
|
||||
log_suspend_abort_reason("Callback failed on %s in %pS returned %d",
|
||||
dev_name(dev), callback, error);
|
||||
goto Complete;
|
||||
}
|
||||
dpm_propagate_wakeup_to_parent(dev);
|
||||
|
|
@ -1716,7 +1720,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);
|
||||
|
|
@ -1740,9 +1743,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|||
|
||||
if (pm_wakeup_pending()) {
|
||||
dev->power.direct_complete = false;
|
||||
pm_get_active_wakeup_sources(suspend_abort,
|
||||
MAX_SUSPEND_ABORT_LEN);
|
||||
log_suspend_abort_reason(suspend_abort);
|
||||
async_error = -EBUSY;
|
||||
goto Complete;
|
||||
}
|
||||
|
|
@ -1819,6 +1819,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|||
|
||||
dpm_propagate_wakeup_to_parent(dev);
|
||||
dpm_clear_superiors_direct_complete(dev);
|
||||
} else {
|
||||
log_suspend_abort_reason("Callback failed on %s in %pS returned %d",
|
||||
dev_name(dev), callback, error);
|
||||
}
|
||||
|
||||
device_unlock(dev);
|
||||
|
|
@ -2028,6 +2031,8 @@ int dpm_prepare(pm_message_t state)
|
|||
}
|
||||
pr_info("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;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "power.h"
|
||||
|
|
@ -883,6 +885,7 @@ bool pm_wakeup_pending(void)
|
|||
{
|
||||
unsigned long flags;
|
||||
bool ret = false;
|
||||
char suspend_abort[MAX_SUSPEND_ABORT_LEN];
|
||||
|
||||
raw_spin_lock_irqsave(&events_lock, flags);
|
||||
if (events_check_enabled) {
|
||||
|
|
@ -897,6 +900,10 @@ bool pm_wakeup_pending(void)
|
|||
if (ret) {
|
||||
pm_pr_dbg("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;
|
||||
|
|
@ -924,6 +931,18 @@ void pm_wakeup_clear(bool reset)
|
|||
void pm_system_irq_wakeup(unsigned int irq_number)
|
||||
{
|
||||
if (pm_wakeup_irq == 0) {
|
||||
struct irq_desc *desc;
|
||||
const char *name = "null";
|
||||
|
||||
desc = irq_to_desc(irq_number);
|
||||
if (desc == NULL)
|
||||
name = "stray irq";
|
||||
else if (desc->action && desc->action->name)
|
||||
name = desc->action->name;
|
||||
|
||||
log_irq_wakeup_reason(irq_number);
|
||||
pr_warn("%s: %d triggered %s\n", __func__, irq_number, name);
|
||||
|
||||
pm_wakeup_irq = irq_number;
|
||||
pm_system_wakeup();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,7 +214,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) {
|
||||
blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, lo->lo_queue);
|
||||
|
|
@ -223,7 +224,8 @@ static void __loop_update_dio(struct loop_device *lo, bool dio)
|
|||
blk_queue_flag_set(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
|
||||
|
|
@ -1536,16 +1538,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,
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ bool have_governor_per_policy(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(have_governor_per_policy);
|
||||
|
||||
static struct kobject *cpufreq_global_kobject;
|
||||
|
||||
struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (have_governor_per_policy())
|
||||
|
|
@ -2764,9 +2766,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
|
||||
|
||||
struct kobject *cpufreq_global_kobject;
|
||||
EXPORT_SYMBOL(cpufreq_global_kobject);
|
||||
|
||||
static int __init cpufreq_core_init(void)
|
||||
{
|
||||
if (cpufreq_disabled())
|
||||
|
|
|
|||
|
|
@ -486,6 +486,28 @@ static int sprd_dma_set_2stage_config(struct sprd_dma_chn *schan)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_dma_set_pending(struct sprd_dma_chn *schan, bool enable)
|
||||
{
|
||||
struct sprd_dma_dev *sdev = to_sprd_dma_dev(&schan->vc.chan);
|
||||
u32 reg, val, req_id;
|
||||
|
||||
if (schan->dev_id == SPRD_DMA_SOFTWARE_UID)
|
||||
return;
|
||||
|
||||
/* The DMA request id always starts from 0. */
|
||||
req_id = schan->dev_id - 1;
|
||||
|
||||
if (req_id < 32) {
|
||||
reg = SPRD_DMA_GLB_REQ_PEND0_EN;
|
||||
val = BIT(req_id);
|
||||
} else {
|
||||
reg = SPRD_DMA_GLB_REQ_PEND1_EN;
|
||||
val = BIT(req_id - 32);
|
||||
}
|
||||
|
||||
sprd_dma_glb_update(sdev, reg, val, enable ? val : 0);
|
||||
}
|
||||
|
||||
static void sprd_dma_set_chn_config(struct sprd_dma_chn *schan,
|
||||
struct sprd_dma_desc *sdesc)
|
||||
{
|
||||
|
|
@ -532,6 +554,7 @@ static void sprd_dma_start(struct sprd_dma_chn *schan)
|
|||
*/
|
||||
sprd_dma_set_chn_config(schan, schan->cur_desc);
|
||||
sprd_dma_set_uid(schan);
|
||||
sprd_dma_set_pending(schan, true);
|
||||
sprd_dma_enable_chn(schan);
|
||||
|
||||
if (schan->dev_id == SPRD_DMA_SOFTWARE_UID &&
|
||||
|
|
@ -543,6 +566,7 @@ static void sprd_dma_start(struct sprd_dma_chn *schan)
|
|||
static void sprd_dma_stop(struct sprd_dma_chn *schan)
|
||||
{
|
||||
sprd_dma_stop_and_disable(schan);
|
||||
sprd_dma_set_pending(schan, false);
|
||||
sprd_dma_unset_uid(schan);
|
||||
sprd_dma_clear_int(schan);
|
||||
schan->cur_desc = NULL;
|
||||
|
|
|
|||
|
|
@ -423,9 +423,40 @@ static int axp288_extcon_probe(struct platform_device *pdev)
|
|||
/* Start charger cable type detection */
|
||||
axp288_extcon_enable(info);
|
||||
|
||||
device_init_wakeup(dev, true);
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused axp288_extcon_suspend(struct device *dev)
|
||||
{
|
||||
struct axp288_extcon_info *info = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(info->irq[VBUS_RISING_IRQ]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused axp288_extcon_resume(struct device *dev)
|
||||
{
|
||||
struct axp288_extcon_info *info = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* Wakeup when a charger is connected to do charger-type
|
||||
* connection and generate an extcon event which makes the
|
||||
* axp288 charger driver set the input current limit.
|
||||
*/
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(info->irq[VBUS_RISING_IRQ]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(axp288_extcon_pm_ops, axp288_extcon_suspend,
|
||||
axp288_extcon_resume);
|
||||
|
||||
static const struct platform_device_id axp288_extcon_table[] = {
|
||||
{ .name = "axp288_extcon" },
|
||||
{},
|
||||
|
|
@ -437,6 +468,7 @@ static struct platform_driver axp288_extcon_driver = {
|
|||
.id_table = axp288_extcon_table,
|
||||
.driver = {
|
||||
.name = "axp288_extcon",
|
||||
.pm = &axp288_extcon_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -569,6 +569,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
|
|||
const struct sprd_eic_variant_data *pdata;
|
||||
struct gpio_irq_chip *irq;
|
||||
struct sprd_eic *sprd_eic;
|
||||
struct resource *res;
|
||||
int ret, i;
|
||||
|
||||
pdata = of_device_get_match_data(&pdev->dev);
|
||||
|
|
@ -595,9 +596,13 @@ static int sprd_eic_probe(struct platform_device *pdev)
|
|||
* have one bank EIC, thus base[1] and base[2] can be
|
||||
* optional.
|
||||
*/
|
||||
sprd_eic->base[i] = devm_platform_ioremap_resource(pdev, i);
|
||||
if (IS_ERR(sprd_eic->base[i]))
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(sprd_eic->base[i]))
|
||||
return PTR_ERR(sprd_eic->base[i]);
|
||||
}
|
||||
|
||||
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
|
||||
|
|
|
|||
|
|
@ -1375,7 +1375,7 @@ static int vcn_v1_0_set_clockgating_state(void *handle,
|
|||
|
||||
if (enable) {
|
||||
/* wait for STATUS to clear */
|
||||
if (vcn_v1_0_is_idle(handle))
|
||||
if (!vcn_v1_0_is_idle(handle))
|
||||
return -EBUSY;
|
||||
vcn_v1_0_enable_clock_gating(adev);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2879,6 +2879,17 @@ static bool retrieve_link_cap(struct dc_link *link)
|
|||
sink_id.ieee_device_id,
|
||||
sizeof(sink_id.ieee_device_id));
|
||||
|
||||
/* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */
|
||||
{
|
||||
uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 };
|
||||
|
||||
if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
|
||||
!memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017,
|
||||
sizeof(str_mbp_2017))) {
|
||||
link->reported_link_cap.link_rate = 0x0c;
|
||||
}
|
||||
}
|
||||
|
||||
core_link_read_dpcd(
|
||||
link,
|
||||
DP_SINK_HW_REVISION_START,
|
||||
|
|
|
|||
|
|
@ -156,10 +156,8 @@ int bochs_hw_init(struct drm_device *dev)
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -129,11 +129,6 @@
|
|||
#define TCOBASE 0x050
|
||||
#define TCOCTL 0x054
|
||||
|
||||
#define ACPIBASE 0x040
|
||||
#define ACPIBASE_SMI_OFF 0x030
|
||||
#define ACPICTRL 0x044
|
||||
#define ACPICTRL_EN 0x080
|
||||
|
||||
#define SBREG_BAR 0x10
|
||||
#define SBREG_SMBCTRL 0xc6000c
|
||||
#define SBREG_SMBCTRL_DNV 0xcf000c
|
||||
|
|
@ -1544,7 +1539,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
|
|||
pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
|
||||
spin_unlock(&p2sb_spinlock);
|
||||
|
||||
res = &tco_res[ICH_RES_MEM_OFF];
|
||||
res = &tco_res[1];
|
||||
if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
|
||||
res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV;
|
||||
else
|
||||
|
|
@ -1554,7 +1549,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
|
|||
res->flags = IORESOURCE_MEM;
|
||||
|
||||
return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
|
||||
tco_res, 3, &spt_tco_platform_data,
|
||||
tco_res, 2, &spt_tco_platform_data,
|
||||
sizeof(spt_tco_platform_data));
|
||||
}
|
||||
|
||||
|
|
@ -1567,17 +1562,16 @@ static struct platform_device *
|
|||
i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev,
|
||||
struct resource *tco_res)
|
||||
{
|
||||
return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
|
||||
tco_res, 2, &cnl_tco_platform_data,
|
||||
sizeof(cnl_tco_platform_data));
|
||||
return platform_device_register_resndata(&pci_dev->dev,
|
||||
"iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data,
|
||||
sizeof(cnl_tco_platform_data));
|
||||
}
|
||||
|
||||
static void i801_add_tco(struct i801_priv *priv)
|
||||
{
|
||||
u32 base_addr, tco_base, tco_ctl, ctrl_val;
|
||||
struct pci_dev *pci_dev = priv->pci_dev;
|
||||
struct resource tco_res[3], *res;
|
||||
unsigned int devfn;
|
||||
struct resource tco_res[2], *res;
|
||||
u32 tco_base, tco_ctl;
|
||||
|
||||
/* If we have ACPI based watchdog use that instead */
|
||||
if (acpi_has_watchdog())
|
||||
|
|
@ -1592,30 +1586,15 @@ static void i801_add_tco(struct i801_priv *priv)
|
|||
return;
|
||||
|
||||
memset(tco_res, 0, sizeof(tco_res));
|
||||
|
||||
res = &tco_res[ICH_RES_IO_TCO];
|
||||
/*
|
||||
* Always populate the main iTCO IO resource here. The second entry
|
||||
* for NO_REBOOT MMIO is filled by the SPT specific function.
|
||||
*/
|
||||
res = &tco_res[0];
|
||||
res->start = tco_base & ~1;
|
||||
res->end = res->start + 32 - 1;
|
||||
res->flags = IORESOURCE_IO;
|
||||
|
||||
/*
|
||||
* Power Management registers.
|
||||
*/
|
||||
devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2);
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr);
|
||||
|
||||
res = &tco_res[ICH_RES_IO_SMI];
|
||||
res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF;
|
||||
res->end = res->start + 3;
|
||||
res->flags = IORESOURCE_IO;
|
||||
|
||||
/*
|
||||
* Enable the ACPI I/O space.
|
||||
*/
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val);
|
||||
ctrl_val |= ACPICTRL_EN;
|
||||
pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val);
|
||||
|
||||
if (priv->features & FEATURE_TCO_CNL)
|
||||
priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ static int defer_packet_queue(
|
|||
*/
|
||||
xchg(&pq->state, SDMA_PKT_Q_DEFERRED);
|
||||
if (list_empty(&pq->busy.list)) {
|
||||
pq->busy.lock = &sde->waitlock;
|
||||
iowait_get_priority(&pq->busy);
|
||||
iowait_queue(pkts_sent, &pq->busy, &sde->dmawait);
|
||||
}
|
||||
|
|
@ -155,6 +156,7 @@ static void activate_packet_queue(struct iowait *wait, int reason)
|
|||
{
|
||||
struct hfi1_user_sdma_pkt_q *pq =
|
||||
container_of(wait, struct hfi1_user_sdma_pkt_q, busy);
|
||||
pq->busy.lock = NULL;
|
||||
xchg(&pq->state, SDMA_PKT_Q_ACTIVE);
|
||||
wake_up(&wait->wait_dma);
|
||||
};
|
||||
|
|
@ -256,6 +258,21 @@ pq_reqs_nomem:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void flush_pq_iowait(struct hfi1_user_sdma_pkt_q *pq)
|
||||
{
|
||||
unsigned long flags;
|
||||
seqlock_t *lock = pq->busy.lock;
|
||||
|
||||
if (!lock)
|
||||
return;
|
||||
write_seqlock_irqsave(lock, flags);
|
||||
if (!list_empty(&pq->busy.list)) {
|
||||
list_del_init(&pq->busy.list);
|
||||
pq->busy.lock = NULL;
|
||||
}
|
||||
write_sequnlock_irqrestore(lock, flags);
|
||||
}
|
||||
|
||||
int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
|
||||
struct hfi1_ctxtdata *uctxt)
|
||||
{
|
||||
|
|
@ -281,6 +298,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
|
|||
kfree(pq->reqs);
|
||||
kfree(pq->req_in_use);
|
||||
kmem_cache_destroy(pq->txreq_cache);
|
||||
flush_pq_iowait(pq);
|
||||
kfree(pq);
|
||||
} else {
|
||||
spin_unlock(&fd->pq_rcu_lock);
|
||||
|
|
@ -587,11 +605,12 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
|
|||
if (ret < 0) {
|
||||
if (ret != -EBUSY)
|
||||
goto free_req;
|
||||
wait_event_interruptible_timeout(
|
||||
if (wait_event_interruptible_timeout(
|
||||
pq->busy.wait_dma,
|
||||
(pq->state == SDMA_PKT_Q_ACTIVE),
|
||||
pq->state == SDMA_PKT_Q_ACTIVE,
|
||||
msecs_to_jiffies(
|
||||
SDMA_IOWAIT_TIMEOUT));
|
||||
SDMA_IOWAIT_TIMEOUT)) <= 0)
|
||||
flush_pq_iowait(pq);
|
||||
}
|
||||
}
|
||||
*count += idx;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/percpu.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
|
||||
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/arm-gic-common.h>
|
||||
|
|
@ -648,6 +650,9 @@ 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);
|
||||
|
||||
gic_deactivate_unhandled(irqnr);
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|||
}
|
||||
|
||||
err = blk_crypto_start_using_mode(cipher->mode_num, dkc->sector_size,
|
||||
dkc->is_hw_wrapped,
|
||||
dkc->dev->bdev->bd_queue);
|
||||
if (err) {
|
||||
ti->error = "Error starting to use blk-crypto";
|
||||
|
|
|
|||
|
|
@ -1741,8 +1741,9 @@ static blk_qc_t dm_process_bio(struct mapped_device *md,
|
|||
* won't be imposed.
|
||||
*/
|
||||
if (current->bio_list) {
|
||||
blk_queue_split(md->queue, &bio);
|
||||
if (!is_abnormal_io(bio))
|
||||
if (is_abnormal_io(bio))
|
||||
blk_queue_split(md->queue, &bio);
|
||||
else
|
||||
dm_queue_split(md, ti, &bio);
|
||||
}
|
||||
|
||||
|
|
@ -2370,16 +2371,21 @@ static struct keyslot_mgmt_ll_ops dm_ksm_ll_ops = {
|
|||
|
||||
static int dm_init_inline_encryption(struct mapped_device *md)
|
||||
{
|
||||
unsigned int features;
|
||||
unsigned int mode_masks[BLK_ENCRYPTION_MODE_MAX];
|
||||
|
||||
/*
|
||||
* Start out with all crypto mode support bits set. Any unsupported
|
||||
* bits will be cleared later when calculating the device restrictions.
|
||||
* 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(NULL,
|
||||
&dm_ksm_ll_ops,
|
||||
features,
|
||||
mode_masks, md);
|
||||
if (!md->queue->ksm)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <uapi/linux/usb/charger.h>
|
||||
|
||||
#define SPRD_PMIC_INT_MASK_STATUS 0x0
|
||||
#define SPRD_PMIC_INT_RAW_STATUS 0x4
|
||||
|
|
@ -17,6 +18,16 @@
|
|||
|
||||
#define SPRD_SC2731_IRQ_BASE 0x140
|
||||
#define SPRD_SC2731_IRQ_NUMS 16
|
||||
#define SPRD_SC2731_CHG_DET 0xedc
|
||||
|
||||
/* PMIC charger detection definition */
|
||||
#define SPRD_PMIC_CHG_DET_DELAY_US 200000
|
||||
#define SPRD_PMIC_CHG_DET_TIMEOUT 2000000
|
||||
#define SPRD_PMIC_CHG_DET_DONE BIT(11)
|
||||
#define SPRD_PMIC_SDP_TYPE BIT(7)
|
||||
#define SPRD_PMIC_DCP_TYPE BIT(6)
|
||||
#define SPRD_PMIC_CDP_TYPE BIT(5)
|
||||
#define SPRD_PMIC_CHG_TYPE_MASK GENMASK(7, 5)
|
||||
|
||||
struct sprd_pmic {
|
||||
struct regmap *regmap;
|
||||
|
|
@ -24,12 +35,14 @@ struct sprd_pmic {
|
|||
struct regmap_irq *irqs;
|
||||
struct regmap_irq_chip irq_chip;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
const struct sprd_pmic_data *pdata;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct sprd_pmic_data {
|
||||
u32 irq_base;
|
||||
u32 num_irqs;
|
||||
u32 charger_det;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -40,8 +53,46 @@ struct sprd_pmic_data {
|
|||
static const struct sprd_pmic_data sc2731_data = {
|
||||
.irq_base = SPRD_SC2731_IRQ_BASE,
|
||||
.num_irqs = SPRD_SC2731_IRQ_NUMS,
|
||||
.charger_det = SPRD_SC2731_CHG_DET,
|
||||
};
|
||||
|
||||
enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct sprd_pmic *ddata = spi_get_drvdata(spi);
|
||||
const struct sprd_pmic_data *pdata = ddata->pdata;
|
||||
enum usb_charger_type type;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(ddata->regmap, pdata->charger_det, val,
|
||||
(val & SPRD_PMIC_CHG_DET_DONE),
|
||||
SPRD_PMIC_CHG_DET_DELAY_US,
|
||||
SPRD_PMIC_CHG_DET_TIMEOUT);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to detect charger type\n");
|
||||
return UNKNOWN_TYPE;
|
||||
}
|
||||
|
||||
switch (val & SPRD_PMIC_CHG_TYPE_MASK) {
|
||||
case SPRD_PMIC_CDP_TYPE:
|
||||
type = CDP_TYPE;
|
||||
break;
|
||||
case SPRD_PMIC_DCP_TYPE:
|
||||
type = DCP_TYPE;
|
||||
break;
|
||||
case SPRD_PMIC_SDP_TYPE:
|
||||
type = SDP_TYPE;
|
||||
break;
|
||||
default:
|
||||
type = UNKNOWN_TYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sprd_pmic_detect_charger_type);
|
||||
|
||||
static const struct mfd_cell sprd_pmic_devs[] = {
|
||||
{
|
||||
.name = "sc27xx-wdt",
|
||||
|
|
@ -181,6 +232,7 @@ static int sprd_pmic_probe(struct spi_device *spi)
|
|||
spi_set_drvdata(spi, ddata);
|
||||
ddata->dev = &spi->dev;
|
||||
ddata->irq = spi->irq;
|
||||
ddata->pdata = pdata;
|
||||
|
||||
ddata->irq_chip.name = dev_name(&spi->dev);
|
||||
ddata->irq_chip.status_base =
|
||||
|
|
|
|||
|
|
@ -394,6 +394,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->tx_initial_phase = SET_CLOCK_PHASE(20, 20, 11);
|
||||
pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@
|
|||
#define MEI_DEV_ID_CMP_H 0x06e0 /* Comet Lake H */
|
||||
#define MEI_DEV_ID_CMP_H_3 0x06e4 /* Comet Lake H 3 (iTouch) */
|
||||
|
||||
#define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */
|
||||
|
||||
#define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
|
||||
|
||||
#define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
|
|||
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH12_CFG)},
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
|
||||
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CDF, MEI_ME_PCH8_CFG)},
|
||||
|
||||
/* required last entry */
|
||||
{0, }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ struct pci_endpoint_test {
|
|||
struct completion irq_raised;
|
||||
int last_irq;
|
||||
int num_irqs;
|
||||
int irq_type;
|
||||
/* mutex to protect the ioctls */
|
||||
struct mutex mutex;
|
||||
struct miscdevice miscdev;
|
||||
|
|
@ -157,6 +158,7 @@ static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
|
|||
struct pci_dev *pdev = test->pdev;
|
||||
|
||||
pci_free_irq_vectors(pdev);
|
||||
test->irq_type = IRQ_TYPE_UNDEFINED;
|
||||
}
|
||||
|
||||
static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
|
||||
|
|
@ -191,6 +193,8 @@ static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
|
|||
irq = 0;
|
||||
res = false;
|
||||
}
|
||||
|
||||
test->irq_type = type;
|
||||
test->num_irqs = irq;
|
||||
|
||||
return res;
|
||||
|
|
@ -330,6 +334,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
|
|||
dma_addr_t orig_dst_phys_addr;
|
||||
size_t offset;
|
||||
size_t alignment = test->alignment;
|
||||
int irq_type = test->irq_type;
|
||||
u32 src_crc32;
|
||||
u32 dst_crc32;
|
||||
|
||||
|
|
@ -426,6 +431,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
|
|||
dma_addr_t orig_phys_addr;
|
||||
size_t offset;
|
||||
size_t alignment = test->alignment;
|
||||
int irq_type = test->irq_type;
|
||||
u32 crc32;
|
||||
|
||||
if (size > SIZE_MAX - alignment)
|
||||
|
|
@ -494,6 +500,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
|
|||
dma_addr_t orig_phys_addr;
|
||||
size_t offset;
|
||||
size_t alignment = test->alignment;
|
||||
int irq_type = test->irq_type;
|
||||
u32 crc32;
|
||||
|
||||
if (size > SIZE_MAX - alignment)
|
||||
|
|
@ -555,7 +562,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (irq_type == req_irq_type)
|
||||
if (test->irq_type == req_irq_type)
|
||||
return true;
|
||||
|
||||
pci_endpoint_test_release_irq(test);
|
||||
|
|
@ -567,12 +574,10 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
|
|||
if (!pci_endpoint_test_request_irq(test))
|
||||
goto err;
|
||||
|
||||
irq_type = req_irq_type;
|
||||
return true;
|
||||
|
||||
err:
|
||||
pci_endpoint_test_free_irq_vectors(test);
|
||||
irq_type = IRQ_TYPE_UNDEFINED;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -633,7 +638,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
|||
{
|
||||
int err;
|
||||
int id;
|
||||
char name[20];
|
||||
char name[24];
|
||||
enum pci_barno bar;
|
||||
void __iomem *base;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -652,6 +657,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
|||
test->test_reg_bar = 0;
|
||||
test->alignment = 0;
|
||||
test->pdev = pdev;
|
||||
test->irq_type = IRQ_TYPE_UNDEFINED;
|
||||
|
||||
if (no_msi)
|
||||
irq_type = IRQ_TYPE_LEGACY;
|
||||
|
|
|
|||
|
|
@ -168,6 +168,11 @@ MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
|
|||
|
||||
static inline int mmc_blk_part_switch(struct mmc_card *card,
|
||||
unsigned int part_type);
|
||||
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
struct mmc_card *card,
|
||||
int disable_multi,
|
||||
struct mmc_queue *mq);
|
||||
static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
|
||||
|
||||
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
|
||||
{
|
||||
|
|
@ -1532,9 +1537,30 @@ static int mmc_blk_cqe_issue_flush(struct mmc_queue *mq, struct request *req)
|
|||
return mmc_blk_cqe_start_req(mq->card->host, mrq);
|
||||
}
|
||||
|
||||
static int mmc_blk_hsq_issue_rw_rq(struct mmc_queue *mq, struct request *req)
|
||||
{
|
||||
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
|
||||
struct mmc_host *host = mq->card->host;
|
||||
int err;
|
||||
|
||||
mmc_blk_rw_rq_prep(mqrq, mq->card, 0, mq);
|
||||
mqrq->brq.mrq.done = mmc_blk_hsq_req_done;
|
||||
mmc_pre_req(host, &mqrq->brq.mrq);
|
||||
|
||||
err = mmc_cqe_start_req(host, &mqrq->brq.mrq);
|
||||
if (err)
|
||||
mmc_post_req(host, &mqrq->brq.mrq, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mmc_blk_cqe_issue_rw_rq(struct mmc_queue *mq, struct request *req)
|
||||
{
|
||||
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
|
||||
struct mmc_host *host = mq->card->host;
|
||||
|
||||
if (host->hsq_enabled)
|
||||
return mmc_blk_hsq_issue_rw_rq(mq, req);
|
||||
|
||||
mmc_blk_data_prep(mq, mqrq, 0, NULL, NULL);
|
||||
|
||||
|
|
@ -1920,6 +1946,41 @@ static void mmc_blk_urgent_bkops(struct mmc_queue *mq,
|
|||
mmc_run_bkops(mq->card);
|
||||
}
|
||||
|
||||
static void mmc_blk_hsq_req_done(struct mmc_request *mrq)
|
||||
{
|
||||
struct mmc_queue_req *mqrq =
|
||||
container_of(mrq, struct mmc_queue_req, brq.mrq);
|
||||
struct request *req = mmc_queue_req_to_req(mqrq);
|
||||
struct request_queue *q = req->q;
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
struct mmc_host *host = mq->card->host;
|
||||
unsigned long flags;
|
||||
|
||||
if (mmc_blk_rq_error(&mqrq->brq) ||
|
||||
mmc_blk_urgent_bkops_needed(mq, mqrq)) {
|
||||
spin_lock_irqsave(&mq->lock, flags);
|
||||
mq->recovery_needed = true;
|
||||
mq->recovery_req = req;
|
||||
spin_unlock_irqrestore(&mq->lock, flags);
|
||||
|
||||
host->cqe_ops->cqe_recovery_start(host);
|
||||
|
||||
schedule_work(&mq->recovery_work);
|
||||
return;
|
||||
}
|
||||
|
||||
mmc_blk_rw_reset_success(mq, req);
|
||||
|
||||
/*
|
||||
* Block layer timeouts race with completions which means the normal
|
||||
* completion path cannot be used during recovery.
|
||||
*/
|
||||
if (mq->in_recovery)
|
||||
mmc_blk_cqe_complete_rq(mq, req);
|
||||
else
|
||||
blk_mq_complete_request(req);
|
||||
}
|
||||
|
||||
void mmc_blk_mq_complete(struct request *req)
|
||||
{
|
||||
struct mmc_queue *mq = req->q->queuedata;
|
||||
|
|
|
|||
|
|
@ -1852,15 +1852,19 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|||
*/
|
||||
card->reenable_cmdq = card->ext_csd.cmdq_en;
|
||||
|
||||
if (card->ext_csd.cmdq_en && !host->cqe_enabled) {
|
||||
if (host->cqe_ops && !host->cqe_enabled) {
|
||||
err = host->cqe_ops->cqe_enable(host, card);
|
||||
if (err) {
|
||||
pr_err("%s: Failed to enable CQE, error %d\n",
|
||||
mmc_hostname(host), err);
|
||||
} else {
|
||||
if (!err) {
|
||||
host->cqe_enabled = true;
|
||||
pr_info("%s: Command Queue Engine enabled\n",
|
||||
mmc_hostname(host));
|
||||
|
||||
if (card->ext_csd.cmdq_en) {
|
||||
pr_info("%s: Command Queue Engine enabled\n",
|
||||
mmc_hostname(host));
|
||||
} else {
|
||||
host->hsq_enabled = true;
|
||||
pr_info("%s: Host Software Queue enabled\n",
|
||||
mmc_hostname(host));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ enum mmc_issue_type mmc_issue_type(struct mmc_queue *mq, struct request *req)
|
|||
{
|
||||
struct mmc_host *host = mq->card->host;
|
||||
|
||||
if (mq->use_cqe)
|
||||
if (mq->use_cqe && !host->hsq_enabled)
|
||||
return mmc_cqe_issue_type(host, req);
|
||||
|
||||
if (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_WRITE)
|
||||
|
|
@ -124,12 +124,14 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req,
|
|||
{
|
||||
struct request_queue *q = req->q;
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
struct mmc_card *card = mq->card;
|
||||
struct mmc_host *host = card->host;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&mq->lock, flags);
|
||||
|
||||
if (mq->recovery_needed || !mq->use_cqe)
|
||||
if (mq->recovery_needed || !mq->use_cqe || host->hsq_enabled)
|
||||
ret = BLK_EH_RESET_TIMER;
|
||||
else
|
||||
ret = mmc_cqe_timed_out(req);
|
||||
|
|
@ -144,12 +146,13 @@ static void mmc_mq_recovery_handler(struct work_struct *work)
|
|||
struct mmc_queue *mq = container_of(work, struct mmc_queue,
|
||||
recovery_work);
|
||||
struct request_queue *q = mq->queue;
|
||||
struct mmc_host *host = mq->card->host;
|
||||
|
||||
mmc_get_card(mq->card, &mq->ctx);
|
||||
|
||||
mq->in_recovery = true;
|
||||
|
||||
if (mq->use_cqe)
|
||||
if (mq->use_cqe && !host->hsq_enabled)
|
||||
mmc_blk_cqe_recovery(mq);
|
||||
else
|
||||
mmc_blk_mq_recovery(mq);
|
||||
|
|
@ -160,6 +163,9 @@ static void mmc_mq_recovery_handler(struct work_struct *work)
|
|||
mq->recovery_needed = false;
|
||||
spin_unlock_irq(&mq->lock);
|
||||
|
||||
if (host->hsq_enabled)
|
||||
host->cqe_ops->cqe_recovery_finish(host);
|
||||
|
||||
mmc_put_card(mq->card, &mq->ctx);
|
||||
|
||||
blk_mq_run_hw_queues(q, true);
|
||||
|
|
@ -279,6 +285,14 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
}
|
||||
break;
|
||||
case MMC_ISSUE_ASYNC:
|
||||
/*
|
||||
* For MMC host software queue, we only allow 2 requests in
|
||||
* flight to avoid a long latency.
|
||||
*/
|
||||
if (host->hsq_enabled && mq->in_flight[issue_type] > 2) {
|
||||
spin_unlock_irq(&mq->lock);
|
||||
return BLK_STS_RESOURCE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
|
|
@ -430,7 +444,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
|
|||
* The queue depth for CQE must match the hardware because the request
|
||||
* tag is used to index the hardware queue.
|
||||
*/
|
||||
if (mq->use_cqe)
|
||||
if (mq->use_cqe && !host->hsq_enabled)
|
||||
mq->tag_set.queue_depth =
|
||||
min_t(int, card->ext_csd.cmdq_depth, host->cqe_qdepth);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1082,6 +1082,16 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
if (host->cqe_ops && !host->cqe_enabled) {
|
||||
err = host->cqe_ops->cqe_enable(host, card);
|
||||
if (!err) {
|
||||
host->cqe_enabled = true;
|
||||
host->hsq_enabled = true;
|
||||
pr_info("%s: Host Software Queue enabled\n",
|
||||
mmc_hostname(host));
|
||||
}
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
|
|
|
|||
|
|
@ -632,6 +632,7 @@ config MMC_SDHCI_SPRD
|
|||
depends on ARCH_SPRD
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
select MMC_SDHCI_IO_ACCESSORS
|
||||
select MMC_HSQ
|
||||
help
|
||||
This selects the SDIO Host Controller in Spreadtrum
|
||||
SoCs, this driver supports R11(IP version: R11P0).
|
||||
|
|
@ -936,6 +937,17 @@ config MMC_CQHCI
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_HSQ
|
||||
tristate "MMC Host Software Queue support"
|
||||
help
|
||||
This selects the MMC Host Software Queue support. This may increase
|
||||
performance, if the host controller and its driver supports it.
|
||||
|
||||
If you have a controller/driver supporting this interface, say Y or M
|
||||
here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_TOSHIBA_PCI
|
||||
tristate "Toshiba Type A SD/MMC Card Interface Driver"
|
||||
depends on PCI
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
|
|||
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
|
||||
obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o
|
||||
obj-$(CONFIG_MMC_CQHCI) += cqhci.o
|
||||
obj-$(CONFIG_MMC_HSQ) += mmc_hsq.o
|
||||
|
||||
ifeq ($(CONFIG_CB710_DEBUG),y)
|
||||
CFLAGS-cb710-mmc += -DDEBUG
|
||||
|
|
|
|||
|
|
@ -321,14 +321,20 @@ static int cqhci_enable(struct mmc_host *mmc, struct mmc_card *card)
|
|||
struct cqhci_host *cq_host = mmc->cqe_private;
|
||||
int err;
|
||||
|
||||
if (!card->ext_csd.cmdq_en)
|
||||
return -EINVAL;
|
||||
|
||||
if (cq_host->enabled)
|
||||
return 0;
|
||||
|
||||
cq_host->rca = card->rca;
|
||||
|
||||
err = cqhci_host_alloc_tdl(cq_host);
|
||||
if (err)
|
||||
if (err) {
|
||||
pr_err("%s: Failed to enable CQE, error %d\n",
|
||||
mmc_hostname(mmc), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
__cqhci_enable(cq_host);
|
||||
|
||||
|
|
|
|||
348
drivers/mmc/host/mmc_hsq.c
Normal file
348
drivers/mmc/host/mmc_hsq.c
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
*
|
||||
* MMC software queue support based on command queue interfaces
|
||||
*
|
||||
* Copyright (C) 2019 Linaro, Inc.
|
||||
* Author: Baolin Wang <baolin.wang@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "mmc_hsq.h"
|
||||
|
||||
#define HSQ_NUM_SLOTS 64
|
||||
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
|
||||
|
||||
static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
|
||||
{
|
||||
struct mmc_host *mmc = hsq->mmc;
|
||||
struct hsq_slot *slot;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hsq->lock, flags);
|
||||
|
||||
/* Make sure we are not already running a request now */
|
||||
if (hsq->mrq) {
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure there are remain requests need to pump */
|
||||
if (!hsq->qcnt || !hsq->enabled) {
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
slot = &hsq->slot[hsq->next_tag];
|
||||
hsq->mrq = slot->mrq;
|
||||
hsq->qcnt--;
|
||||
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
|
||||
mmc->ops->request(mmc, hsq->mrq);
|
||||
}
|
||||
|
||||
static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
|
||||
{
|
||||
struct hsq_slot *slot;
|
||||
int tag;
|
||||
|
||||
/*
|
||||
* If there are no remain requests in software queue, then set a invalid
|
||||
* tag.
|
||||
*/
|
||||
if (!remains) {
|
||||
hsq->next_tag = HSQ_INVALID_TAG;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increasing the next tag and check if the corresponding request is
|
||||
* available, if yes, then we found a candidate request.
|
||||
*/
|
||||
if (++hsq->next_tag != HSQ_INVALID_TAG) {
|
||||
slot = &hsq->slot[hsq->next_tag];
|
||||
if (slot->mrq)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Othersie we should iterate all slots to find a available tag. */
|
||||
for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
|
||||
slot = &hsq->slot[tag];
|
||||
if (slot->mrq)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag == HSQ_NUM_SLOTS)
|
||||
tag = HSQ_INVALID_TAG;
|
||||
|
||||
hsq->next_tag = tag;
|
||||
}
|
||||
|
||||
static void mmc_hsq_post_request(struct mmc_hsq *hsq)
|
||||
{
|
||||
unsigned long flags;
|
||||
int remains;
|
||||
|
||||
spin_lock_irqsave(&hsq->lock, flags);
|
||||
|
||||
remains = hsq->qcnt;
|
||||
hsq->mrq = NULL;
|
||||
|
||||
/* Update the next available tag to be queued. */
|
||||
mmc_hsq_update_next_tag(hsq, remains);
|
||||
|
||||
if (hsq->waiting_for_idle && !remains) {
|
||||
hsq->waiting_for_idle = false;
|
||||
wake_up(&hsq->wait_queue);
|
||||
}
|
||||
|
||||
/* Do not pump new request in recovery mode. */
|
||||
if (hsq->recovery_halt) {
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
|
||||
/*
|
||||
* Try to pump new request to host controller as fast as possible,
|
||||
* after completing previous request.
|
||||
*/
|
||||
if (remains > 0)
|
||||
mmc_hsq_pump_requests(hsq);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_hsq_finalize_request - finalize one request if the request is done
|
||||
* @mmc: the host controller
|
||||
* @mrq: the request need to be finalized
|
||||
*
|
||||
* Return true if we finalized the corresponding request in software queue,
|
||||
* otherwise return false.
|
||||
*/
|
||||
bool mmc_hsq_finalize_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hsq->lock, flags);
|
||||
|
||||
if (!hsq->enabled || !hsq->mrq || hsq->mrq != mrq) {
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear current completed slot request to make a room for new request.
|
||||
*/
|
||||
hsq->slot[hsq->next_tag].mrq = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
|
||||
mmc_cqe_request_done(mmc, hsq->mrq);
|
||||
|
||||
mmc_hsq_post_request(hsq);
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_hsq_finalize_request);
|
||||
|
||||
static void mmc_hsq_recovery_start(struct mmc_host *mmc)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hsq->lock, flags);
|
||||
|
||||
hsq->recovery_halt = true;
|
||||
|
||||
spin_unlock_irqrestore(&hsq->lock, flags);
|
||||
}
|
||||
|
||||
static void mmc_hsq_recovery_finish(struct mmc_host *mmc)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
int remains;
|
||||
|
||||
spin_lock_irq(&hsq->lock);
|
||||
|
||||
hsq->recovery_halt = false;
|
||||
remains = hsq->qcnt;
|
||||
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
|
||||
/*
|
||||
* Try to pump new request if there are request pending in software
|
||||
* queue after finishing recovery.
|
||||
*/
|
||||
if (remains > 0)
|
||||
mmc_hsq_pump_requests(hsq);
|
||||
}
|
||||
|
||||
static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
int tag = mrq->tag;
|
||||
|
||||
spin_lock_irq(&hsq->lock);
|
||||
|
||||
if (!hsq->enabled) {
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
/* Do not queue any new requests in recovery mode. */
|
||||
if (hsq->recovery_halt) {
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
hsq->slot[tag].mrq = mrq;
|
||||
|
||||
/*
|
||||
* Set the next tag as current request tag if no available
|
||||
* next tag.
|
||||
*/
|
||||
if (hsq->next_tag == HSQ_INVALID_TAG)
|
||||
hsq->next_tag = tag;
|
||||
|
||||
hsq->qcnt++;
|
||||
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
|
||||
mmc_hsq_pump_requests(hsq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmc_hsq_post_req(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
if (mmc->ops->post_req)
|
||||
mmc->ops->post_req(mmc, mrq, 0);
|
||||
}
|
||||
|
||||
static bool mmc_hsq_queue_is_idle(struct mmc_hsq *hsq, int *ret)
|
||||
{
|
||||
bool is_idle;
|
||||
|
||||
spin_lock_irq(&hsq->lock);
|
||||
|
||||
is_idle = (!hsq->mrq && !hsq->qcnt) ||
|
||||
hsq->recovery_halt;
|
||||
|
||||
*ret = hsq->recovery_halt ? -EBUSY : 0;
|
||||
hsq->waiting_for_idle = !is_idle;
|
||||
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
|
||||
return is_idle;
|
||||
}
|
||||
|
||||
static int mmc_hsq_wait_for_idle(struct mmc_host *mmc)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
int ret;
|
||||
|
||||
wait_event(hsq->wait_queue,
|
||||
mmc_hsq_queue_is_idle(hsq, &ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mmc_hsq_disable(struct mmc_host *mmc)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
u32 timeout = 500;
|
||||
int ret;
|
||||
|
||||
spin_lock_irq(&hsq->lock);
|
||||
|
||||
if (!hsq->enabled) {
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
|
||||
ret = wait_event_timeout(hsq->wait_queue,
|
||||
mmc_hsq_queue_is_idle(hsq, &ret),
|
||||
msecs_to_jiffies(timeout));
|
||||
if (ret == 0) {
|
||||
pr_warn("could not stop mmc software queue\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irq(&hsq->lock);
|
||||
|
||||
hsq->enabled = false;
|
||||
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
}
|
||||
|
||||
static int mmc_hsq_enable(struct mmc_host *mmc, struct mmc_card *card)
|
||||
{
|
||||
struct mmc_hsq *hsq = mmc->cqe_private;
|
||||
|
||||
spin_lock_irq(&hsq->lock);
|
||||
|
||||
if (hsq->enabled) {
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
hsq->enabled = true;
|
||||
|
||||
spin_unlock_irq(&hsq->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mmc_cqe_ops mmc_hsq_ops = {
|
||||
.cqe_enable = mmc_hsq_enable,
|
||||
.cqe_disable = mmc_hsq_disable,
|
||||
.cqe_request = mmc_hsq_request,
|
||||
.cqe_post_req = mmc_hsq_post_req,
|
||||
.cqe_wait_for_idle = mmc_hsq_wait_for_idle,
|
||||
.cqe_recovery_start = mmc_hsq_recovery_start,
|
||||
.cqe_recovery_finish = mmc_hsq_recovery_finish,
|
||||
};
|
||||
|
||||
int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
|
||||
{
|
||||
hsq->num_slots = HSQ_NUM_SLOTS;
|
||||
hsq->next_tag = HSQ_INVALID_TAG;
|
||||
|
||||
hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots,
|
||||
sizeof(struct hsq_slot), GFP_KERNEL);
|
||||
if (!hsq->slot)
|
||||
return -ENOMEM;
|
||||
|
||||
hsq->mmc = mmc;
|
||||
hsq->mmc->cqe_private = hsq;
|
||||
mmc->cqe_ops = &mmc_hsq_ops;
|
||||
|
||||
spin_lock_init(&hsq->lock);
|
||||
init_waitqueue_head(&hsq->wait_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_hsq_init);
|
||||
|
||||
void mmc_hsq_suspend(struct mmc_host *mmc)
|
||||
{
|
||||
mmc_hsq_disable(mmc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_hsq_suspend);
|
||||
|
||||
int mmc_hsq_resume(struct mmc_host *mmc)
|
||||
{
|
||||
return mmc_hsq_enable(mmc, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_hsq_resume);
|
||||
|
||||
MODULE_DESCRIPTION("MMC Host Software Queue support");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
30
drivers/mmc/host/mmc_hsq.h
Normal file
30
drivers/mmc/host/mmc_hsq.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef LINUX_MMC_HSQ_H
|
||||
#define LINUX_MMC_HSQ_H
|
||||
|
||||
struct hsq_slot {
|
||||
struct mmc_request *mrq;
|
||||
};
|
||||
|
||||
struct mmc_hsq {
|
||||
struct mmc_host *mmc;
|
||||
struct mmc_request *mrq;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct hsq_slot *slot;
|
||||
spinlock_t lock;
|
||||
|
||||
int next_tag;
|
||||
int num_slots;
|
||||
int qcnt;
|
||||
|
||||
bool enabled;
|
||||
bool waiting_for_idle;
|
||||
bool recovery_halt;
|
||||
};
|
||||
|
||||
int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc);
|
||||
void mmc_hsq_suspend(struct mmc_host *mmc);
|
||||
int mmc_hsq_resume(struct mmc_host *mmc);
|
||||
bool mmc_hsq_finalize_request(struct mmc_host *mmc, struct mmc_request *mrq);
|
||||
|
||||
#endif
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "mmc_hsq.h"
|
||||
|
||||
/* SDHCI_ARGUMENT2 register high 16bit */
|
||||
#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
|
||||
|
|
@ -379,6 +380,16 @@ static unsigned int sdhci_sprd_get_ro(struct sdhci_host *host)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sdhci_sprd_request_done(struct sdhci_host *host,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
/* Validate if the request was from software queue firstly. */
|
||||
if (mmc_hsq_finalize_request(host->mmc, mrq))
|
||||
return;
|
||||
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
}
|
||||
|
||||
static struct sdhci_ops sdhci_sprd_ops = {
|
||||
.read_l = sdhci_sprd_readl,
|
||||
.write_l = sdhci_sprd_writel,
|
||||
|
|
@ -392,6 +403,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
|
|||
.hw_reset = sdhci_sprd_hw_reset,
|
||||
.get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
|
||||
.get_ro = sdhci_sprd_get_ro,
|
||||
.request_done = sdhci_sprd_request_done,
|
||||
};
|
||||
|
||||
static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
|
|
@ -521,6 +533,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct sdhci_host *host;
|
||||
struct sdhci_sprd_host *sprd_host;
|
||||
struct mmc_hsq *hsq;
|
||||
struct clk *clk;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -543,7 +556,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||
sdhci_sprd_voltage_switch;
|
||||
|
||||
host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
|
||||
MMC_CAP_ERASE | MMC_CAP_CMD23;
|
||||
MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY;
|
||||
ret = mmc_of_parse(host->mmc);
|
||||
if (ret)
|
||||
goto pltfm_free;
|
||||
|
|
@ -631,6 +644,18 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
|
|||
|
||||
sprd_host->flags = host->flags;
|
||||
|
||||
hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
|
||||
if (!hsq) {
|
||||
ret = -ENOMEM;
|
||||
goto err_cleanup_host;
|
||||
}
|
||||
|
||||
ret = mmc_hsq_init(hsq, host->mmc);
|
||||
if (ret)
|
||||
goto err_cleanup_host;
|
||||
|
||||
host->always_defer_done = true;
|
||||
|
||||
ret = __sdhci_add_host(host);
|
||||
if (ret)
|
||||
goto err_cleanup_host;
|
||||
|
|
@ -689,6 +714,7 @@ static int sdhci_sprd_runtime_suspend(struct device *dev)
|
|||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
|
||||
|
||||
mmc_hsq_suspend(host->mmc);
|
||||
sdhci_runtime_suspend_host(host);
|
||||
|
||||
clk_disable_unprepare(sprd_host->clk_sdio);
|
||||
|
|
@ -717,6 +743,8 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
|
|||
goto clk_disable;
|
||||
|
||||
sdhci_runtime_resume_host(host, 1);
|
||||
mmc_hsq_resume(host->mmc);
|
||||
|
||||
return 0;
|
||||
|
||||
clk_disable:
|
||||
|
|
|
|||
|
|
@ -2727,7 +2727,10 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
|||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
if (host->ops->request_done)
|
||||
host->ops->request_done(host, mrq);
|
||||
else
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3030,7 +3033,7 @@ static inline bool sdhci_defer_done(struct sdhci_host *host,
|
|||
{
|
||||
struct mmc_data *data = mrq->data;
|
||||
|
||||
return host->pending_reset ||
|
||||
return host->pending_reset || host->always_defer_done ||
|
||||
((host->flags & SDHCI_REQ_USE_DMA) && data &&
|
||||
data->host_cookie == COOKIE_MAPPED);
|
||||
}
|
||||
|
|
@ -3155,7 +3158,12 @@ out:
|
|||
|
||||
/* Process mrqs ready for immediate completion */
|
||||
for (i = 0; i < SDHCI_MAX_MRQS; i++) {
|
||||
if (mrqs_done[i])
|
||||
if (!mrqs_done[i])
|
||||
continue;
|
||||
|
||||
if (host->ops->request_done)
|
||||
host->ops->request_done(host, mrqs_done[i]);
|
||||
else
|
||||
mmc_request_done(host->mmc, mrqs_done[i]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -535,6 +535,7 @@ struct sdhci_host {
|
|||
bool pending_reset; /* Cmd/data reset is pending */
|
||||
bool irq_wake_enabled; /* IRQ wakeup is enabled */
|
||||
bool v4_mode; /* Host Version 4 Enable */
|
||||
bool always_defer_done; /* Always defer to complete requests */
|
||||
|
||||
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
|
||||
struct mmc_command *cmd; /* Current command */
|
||||
|
|
@ -646,6 +647,8 @@ struct sdhci_ops {
|
|||
void (*voltage_switch)(struct sdhci_host *host);
|
||||
void (*adma_write_desc)(struct sdhci_host *host, void **desc,
|
||||
dma_addr_t addr, int len, unsigned int cmd);
|
||||
void (*request_done)(struct sdhci_host *host,
|
||||
struct mmc_request *mrq);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ enum {
|
|||
|
||||
enum {
|
||||
MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START = 0,
|
||||
MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 1,
|
||||
MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING = 2,
|
||||
MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING = 1,
|
||||
MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 2,
|
||||
};
|
||||
|
||||
struct mlx5e_ktls_offload_context_tx {
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ tx_sync_info_get(struct mlx5e_ktls_offload_context_tx *priv_tx,
|
|||
* this packet was already acknowledged and its record info
|
||||
* was released.
|
||||
*/
|
||||
ends_before = before(tcp_seq + datalen, tls_record_start_seq(record));
|
||||
ends_before = before(tcp_seq + datalen - 1, tls_record_start_seq(record));
|
||||
|
||||
if (unlikely(tls_record_is_start_marker(record))) {
|
||||
ret = ends_before ? MLX5E_KTLS_SYNC_SKIP_NO_DATA : MLX5E_KTLS_SYNC_FAIL;
|
||||
|
|
|
|||
|
|
@ -1934,6 +1934,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
|
|||
if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
|
||||
BRCMF_SDIO_FT_NORMAL)) {
|
||||
rd->len = 0;
|
||||
brcmf_sdio_rxfail(bus, true, true);
|
||||
sdio_release_host(bus->sdiodev->func1);
|
||||
brcmu_pkt_buf_free_skb(pkt);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation
|
||||
* Copyright(c) 2018 - 2020 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation
|
||||
* Copyright(c) 2018 - 2020 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -1373,11 +1373,7 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* region register have absolute value so apply rxf offset after
|
||||
* reading the registers
|
||||
*/
|
||||
offs += rxf_data.offset;
|
||||
offs = rxf_data.offset;
|
||||
|
||||
/* Lock fence */
|
||||
iwl_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1);
|
||||
|
|
@ -2315,10 +2311,7 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (iwl_fw_dbg_stop_restart_recording(fwrt, ¶ms, true)) {
|
||||
IWL_ERR(fwrt, "Failed to stop DBGC recording, aborting dump\n");
|
||||
goto out;
|
||||
}
|
||||
iwl_fw_dbg_stop_restart_recording(fwrt, ¶ms, true);
|
||||
|
||||
IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection start\n");
|
||||
if (iwl_trans_dbg_ini_valid(fwrt->trans))
|
||||
|
|
@ -2484,14 +2477,14 @@ static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_params *params,
|
||||
bool stop)
|
||||
void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_params *params,
|
||||
bool stop)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP))
|
||||
|
|
@ -2508,7 +2501,5 @@ int iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
|
|||
iwl_fw_set_dbg_rec_on(fwrt);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_restart_recording);
|
||||
|
|
|
|||
|
|
@ -263,9 +263,9 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
|
|||
_iwl_fw_dbg_trigger_simple_stop((fwrt), (wdev), \
|
||||
iwl_fw_dbg_get_trigger((fwrt)->fw,\
|
||||
(trig)))
|
||||
int iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_params *params,
|
||||
bool stop);
|
||||
void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_params *params,
|
||||
bool stop);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
|
||||
|
|
|
|||
|
|
@ -147,7 +147,11 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
|
|||
(vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
|
||||
|
||||
/* consider our LDPC support in case of HE */
|
||||
/* consider LDPC support in case of HE */
|
||||
if (he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[1] &
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
|
||||
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
|
||||
|
||||
if (sband->iftype_data && sband->iftype_data->he_cap.has_he &&
|
||||
!(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
|
||||
|
|
|
|||
|
|
@ -850,9 +850,11 @@ out_free_tagset:
|
|||
if (new)
|
||||
blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
|
||||
out_free_async_qe:
|
||||
nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
|
||||
sizeof(struct nvme_command), DMA_TO_DEVICE);
|
||||
ctrl->async_event_sqe.data = NULL;
|
||||
if (ctrl->async_event_sqe.data) {
|
||||
nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
|
||||
sizeof(struct nvme_command), DMA_TO_DEVICE);
|
||||
ctrl->async_event_sqe.data = NULL;
|
||||
}
|
||||
out_free_queue:
|
||||
nvme_rdma_free_queue(&ctrl->queues[0]);
|
||||
return error;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
|
|||
|
||||
count = round_down(count, nvmem->word_size);
|
||||
|
||||
if (!nvmem->reg_read)
|
||||
return -EPERM;
|
||||
|
||||
rc = nvmem->reg_read(nvmem->priv, pos, buf, count);
|
||||
|
||||
if (rc)
|
||||
|
|
@ -90,6 +93,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
|
|||
|
||||
count = round_down(count, nvmem->word_size);
|
||||
|
||||
if (!nvmem->reg_write)
|
||||
return -EPERM;
|
||||
|
||||
rc = nvmem->reg_write(nvmem->priv, pos, buf, count);
|
||||
|
||||
if (rc)
|
||||
|
|
|
|||
|
|
@ -217,12 +217,14 @@ static int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub,
|
|||
* Enable the auto-check function to validate if the programming is
|
||||
* successful.
|
||||
*/
|
||||
sprd_efuse_set_auto_check(efuse, true);
|
||||
if (lock)
|
||||
sprd_efuse_set_auto_check(efuse, true);
|
||||
|
||||
writel(*data, efuse->base + SPRD_EFUSE_MEM(blk));
|
||||
|
||||
/* Disable auto-check and data double after programming */
|
||||
sprd_efuse_set_auto_check(efuse, false);
|
||||
if (lock)
|
||||
sprd_efuse_set_auto_check(efuse, false);
|
||||
sprd_efuse_set_data_double(efuse, false);
|
||||
|
||||
/*
|
||||
|
|
@ -237,9 +239,9 @@ static int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub,
|
|||
writel(SPRD_EFUSE_ERR_CLR_MASK,
|
||||
efuse->base + SPRD_EFUSE_ERR_CLR);
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
} else if (lock) {
|
||||
sprd_efuse_set_prog_lock(efuse, lock);
|
||||
writel(*data, efuse->base + SPRD_EFUSE_MEM(blk));
|
||||
writel(0, efuse->base + SPRD_EFUSE_MEM(blk));
|
||||
sprd_efuse_set_prog_lock(efuse, false);
|
||||
}
|
||||
|
||||
|
|
@ -322,6 +324,8 @@ unlock:
|
|||
static int sprd_efuse_write(void *context, u32 offset, void *val, size_t bytes)
|
||||
{
|
||||
struct sprd_efuse *efuse = context;
|
||||
bool blk_double = efuse->data->blk_double;
|
||||
bool lock;
|
||||
int ret;
|
||||
|
||||
ret = sprd_efuse_lock(efuse);
|
||||
|
|
@ -332,7 +336,20 @@ static int sprd_efuse_write(void *context, u32 offset, void *val, size_t bytes)
|
|||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
ret = sprd_efuse_raw_prog(efuse, offset, false, false, val);
|
||||
/*
|
||||
* If the writing bytes are equal with the block width, which means the
|
||||
* whole block will be programmed. For this case, we should not allow
|
||||
* this block to be programmed again by locking this block.
|
||||
*
|
||||
* If the block was programmed partially, we should allow this block to
|
||||
* be programmed again.
|
||||
*/
|
||||
if (bytes < SPRD_EFUSE_BLOCK_WIDTH)
|
||||
lock = false;
|
||||
else
|
||||
lock = true;
|
||||
|
||||
ret = sprd_efuse_raw_prog(efuse, offset, blk_double, lock, val);
|
||||
|
||||
clk_disable_unprepare(efuse->clk);
|
||||
|
||||
|
|
|
|||
|
|
@ -464,7 +464,8 @@ static ssize_t dev_rescan_store(struct device *dev,
|
|||
}
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(dev_rescan);
|
||||
static struct device_attribute dev_attr_dev_rescan = __ATTR(rescan, 0200, NULL,
|
||||
dev_rescan_store);
|
||||
|
||||
static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
|
|
@ -501,7 +502,8 @@ static ssize_t bus_rescan_store(struct device *dev,
|
|||
}
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(bus_rescan);
|
||||
static struct device_attribute dev_attr_bus_rescan = __ATTR(rescan, 0200, NULL,
|
||||
bus_rescan_store);
|
||||
|
||||
#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
|
||||
static ssize_t d3cold_allowed_store(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -464,9 +464,15 @@ static int sprd_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id,
|
|||
case PIN_CONFIG_INPUT_ENABLE:
|
||||
arg = (reg >> SLEEP_INPUT_SHIFT) & SLEEP_INPUT_MASK;
|
||||
break;
|
||||
case PIN_CONFIG_OUTPUT:
|
||||
case PIN_CONFIG_OUTPUT_ENABLE:
|
||||
arg = reg & SLEEP_OUTPUT_MASK;
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
||||
if ((reg & SLEEP_OUTPUT) || (reg & SLEEP_INPUT))
|
||||
return -EINVAL;
|
||||
|
||||
arg = 1;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||
arg = (reg >> DRIVE_STRENGTH_SHIFT) &
|
||||
DRIVE_STRENGTH_MASK;
|
||||
|
|
@ -635,13 +641,23 @@ static int sprd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id,
|
|||
shift = SLEEP_INPUT_SHIFT;
|
||||
}
|
||||
break;
|
||||
case PIN_CONFIG_OUTPUT:
|
||||
case PIN_CONFIG_OUTPUT_ENABLE:
|
||||
if (is_sleep_config == true) {
|
||||
val |= SLEEP_OUTPUT;
|
||||
if (arg > 0)
|
||||
val |= SLEEP_OUTPUT;
|
||||
else
|
||||
val &= ~SLEEP_OUTPUT;
|
||||
|
||||
mask = SLEEP_OUTPUT_MASK;
|
||||
shift = SLEEP_OUTPUT_SHIFT;
|
||||
}
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
||||
if (is_sleep_config == true) {
|
||||
val = shift = 0;
|
||||
mask = SLEEP_OUTPUT | SLEEP_INPUT;
|
||||
}
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||
if (arg < 2 || arg > 60)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/property.h>
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#define PS_STAT_VBUS_TRIGGER BIT(0)
|
||||
#define PS_STAT_BAT_CHRG_DIR BIT(2)
|
||||
|
|
@ -545,6 +546,49 @@ out:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* The HP Pavilion x2 10 series comes in a number of variants:
|
||||
* Bay Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "815D"
|
||||
* Cherry Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "813E"
|
||||
* Cherry Trail SoC + TI PMIC, DMI_BOARD_NAME: "827C" or "82F4"
|
||||
*
|
||||
* The variants with the AXP288 PMIC are all kinds of special:
|
||||
*
|
||||
* 1. All variants use a Type-C connector which the AXP288 does not support, so
|
||||
* when using a Type-C charger it is not recognized. Unlike most AXP288 devices,
|
||||
* this model actually has mostly working ACPI AC / Battery code, the ACPI code
|
||||
* "solves" this by simply setting the input_current_limit to 3A.
|
||||
* There are still some issues with the ACPI code, so we use this native driver,
|
||||
* and to solve the charging not working (500mA is not enough) issue we hardcode
|
||||
* the 3A input_current_limit like the ACPI code does.
|
||||
*
|
||||
* 2. If no charger is connected the machine boots with the vbus-path disabled.
|
||||
* Normally this is done when a 5V boost converter is active to avoid the PMIC
|
||||
* trying to charge from the 5V boost converter's output. This is done when
|
||||
* an OTG host cable is inserted and the ID pin on the micro-B receptacle is
|
||||
* pulled low and the ID pin has an ACPI event handler associated with it
|
||||
* which re-enables the vbus-path when the ID pin is pulled high when the
|
||||
* OTG host cable is removed. The Type-C connector has no ID pin, there is
|
||||
* no ID pin handler and there appears to be no 5V boost converter, so we
|
||||
* end up not charging because the vbus-path is disabled, until we unplug
|
||||
* the charger which automatically clears the vbus-path disable bit and then
|
||||
* on the second plug-in of the adapter we start charging. To solve the not
|
||||
* charging on first charger plugin we unconditionally enable the vbus-path at
|
||||
* probe on this model, which is safe since there is no 5V boost converter.
|
||||
*/
|
||||
static const struct dmi_system_id axp288_hp_x2_dmi_ids[] = {
|
||||
{
|
||||
/*
|
||||
* Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry
|
||||
* Trail model has "HP", so we only match on product_name.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
|
||||
},
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
static void axp288_charger_extcon_evt_worker(struct work_struct *work)
|
||||
{
|
||||
struct axp288_chrg_info *info =
|
||||
|
|
@ -568,7 +612,11 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
|
|||
}
|
||||
|
||||
/* Determine cable/charger type */
|
||||
if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
|
||||
if (dmi_check_system(axp288_hp_x2_dmi_ids)) {
|
||||
/* See comment above axp288_hp_x2_dmi_ids declaration */
|
||||
dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n");
|
||||
current_limit = 3000000;
|
||||
} else if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
|
||||
dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n");
|
||||
current_limit = 500000;
|
||||
} else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
|
||||
|
|
@ -685,6 +733,13 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (dmi_check_system(axp288_hp_x2_dmi_ids)) {
|
||||
/* See comment above axp288_hp_x2_dmi_ids declaration */
|
||||
ret = axp288_charger_vbus_path_select(info, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read current charge voltage and current limit */
|
||||
ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val);
|
||||
if (ret < 0) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,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", "Over current"
|
||||
"Safety timer expire", "Over current", "Warm", "Cool", "Hot"
|
||||
};
|
||||
|
||||
static const char * const power_supply_technology_text[] = {
|
||||
|
|
|
|||
|
|
@ -336,7 +336,9 @@ int ufshcd_hba_init_crypto_spec(struct ufs_hba *hba,
|
|||
ufshcd_clear_all_keyslots(hba);
|
||||
|
||||
hba->ksm = keyslot_manager_create(hba->dev, ufshcd_num_keyslots(hba),
|
||||
ksm_ops, crypto_modes_supported, hba);
|
||||
ksm_ops,
|
||||
BLK_CRYPTO_FEATURE_STANDARD_KEYS,
|
||||
crypto_modes_supported, hba);
|
||||
|
||||
if (!hba->ksm) {
|
||||
err = -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout)
|
|||
client->pkt_cnt = 0;
|
||||
client->client.dev = dev;
|
||||
client->client.tx_block = false;
|
||||
client->client.knows_txdone = true;
|
||||
client->chan = mbox_request_channel(&client->client, index);
|
||||
|
||||
if (IS_ERR(client->chan)) {
|
||||
|
|
|
|||
|
|
@ -45,12 +45,6 @@ static void free_duped_table(struct sg_table *table)
|
|||
kfree(table);
|
||||
}
|
||||
|
||||
struct ion_dma_buf_attachment {
|
||||
struct device *dev;
|
||||
struct sg_table *table;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static int ion_dma_buf_attach(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attachment)
|
||||
{
|
||||
|
|
@ -293,11 +287,16 @@ static void *ion_dma_buf_vmap(struct dma_buf *dmabuf)
|
|||
{
|
||||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
struct ion_heap *heap = buffer->heap;
|
||||
void *vaddr;
|
||||
|
||||
if (!heap->buf_ops.vmap)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
if (heap->buf_ops.vmap)
|
||||
return heap->buf_ops.vmap(dmabuf);
|
||||
|
||||
return heap->buf_ops.vmap(dmabuf);
|
||||
mutex_lock(&buffer->lock);
|
||||
vaddr = ion_buffer_kmap_get(buffer);
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
|
||||
|
|
@ -305,10 +304,14 @@ static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
|
|||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
struct ion_heap *heap = buffer->heap;
|
||||
|
||||
if (!heap->buf_ops.vunmap)
|
||||
if (heap->buf_ops.vunmap) {
|
||||
heap->buf_ops.vunmap(dmabuf, vaddr);
|
||||
return;
|
||||
}
|
||||
|
||||
return heap->buf_ops.vunmap(dmabuf, vaddr);
|
||||
mutex_lock(&buffer->lock);
|
||||
ion_buffer_kmap_put(buffer);
|
||||
mutex_unlock(&buffer->lock);
|
||||
}
|
||||
|
||||
static int ion_dma_buf_get_flags(struct dma_buf *dmabuf, unsigned long *flags)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* iTCO Vendor Specific Support hooks */
|
||||
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
|
||||
extern int iTCO_vendorsupport;
|
||||
extern void iTCO_vendor_pre_start(struct resource *, unsigned int);
|
||||
extern void iTCO_vendor_pre_stop(struct resource *);
|
||||
extern int iTCO_vendor_check_noreboot_on(void);
|
||||
#else
|
||||
#define iTCO_vendorsupport 0
|
||||
#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
|
||||
#define iTCO_vendor_pre_stop(acpibase) {}
|
||||
#define iTCO_vendor_check_noreboot_on() 1
|
||||
|
|
|
|||
|
|
@ -39,8 +39,10 @@
|
|||
/* Broken BIOS */
|
||||
#define BROKEN_BIOS 911
|
||||
|
||||
static int vendorsupport;
|
||||
module_param(vendorsupport, int, 0);
|
||||
int iTCO_vendorsupport;
|
||||
EXPORT_SYMBOL(iTCO_vendorsupport);
|
||||
|
||||
module_param_named(vendorsupport, iTCO_vendorsupport, int, 0);
|
||||
MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
|
||||
"0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
|
||||
|
||||
|
|
@ -152,7 +154,7 @@ static void broken_bios_stop(struct resource *smires)
|
|||
void iTCO_vendor_pre_start(struct resource *smires,
|
||||
unsigned int heartbeat)
|
||||
{
|
||||
switch (vendorsupport) {
|
||||
switch (iTCO_vendorsupport) {
|
||||
case SUPERMICRO_OLD_BOARD:
|
||||
supermicro_old_pre_start(smires);
|
||||
break;
|
||||
|
|
@ -165,7 +167,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_start);
|
|||
|
||||
void iTCO_vendor_pre_stop(struct resource *smires)
|
||||
{
|
||||
switch (vendorsupport) {
|
||||
switch (iTCO_vendorsupport) {
|
||||
case SUPERMICRO_OLD_BOARD:
|
||||
supermicro_old_pre_stop(smires);
|
||||
break;
|
||||
|
|
@ -178,7 +180,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_stop);
|
|||
|
||||
int iTCO_vendor_check_noreboot_on(void)
|
||||
{
|
||||
switch (vendorsupport) {
|
||||
switch (iTCO_vendorsupport) {
|
||||
case SUPERMICRO_OLD_BOARD:
|
||||
return 0;
|
||||
default:
|
||||
|
|
@ -189,13 +191,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
|
|||
|
||||
static int __init iTCO_vendor_init_module(void)
|
||||
{
|
||||
if (vendorsupport == SUPERMICRO_NEW_BOARD) {
|
||||
if (iTCO_vendorsupport == SUPERMICRO_NEW_BOARD) {
|
||||
pr_warn("Option vendorsupport=%d is no longer supported, "
|
||||
"please use the w83627hf_wdt driver instead\n",
|
||||
SUPERMICRO_NEW_BOARD);
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_info("vendor-support=%d\n", vendorsupport);
|
||||
pr_info("vendor-support=%d\n", iTCO_vendorsupport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -459,13 +459,25 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
|
|||
if (!p->tco_res)
|
||||
return -ENODEV;
|
||||
|
||||
p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI);
|
||||
if (!p->smi_res)
|
||||
return -ENODEV;
|
||||
|
||||
p->iTCO_version = pdata->version;
|
||||
p->pci_dev = to_pci_dev(dev->parent);
|
||||
|
||||
p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI);
|
||||
if (p->smi_res) {
|
||||
/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
|
||||
if (!devm_request_region(dev, p->smi_res->start,
|
||||
resource_size(p->smi_res),
|
||||
pdev->name)) {
|
||||
pr_err("I/O address 0x%04llx already in use, device disabled\n",
|
||||
(u64)SMI_EN(p));
|
||||
return -EBUSY;
|
||||
}
|
||||
} else if (iTCO_vendorsupport ||
|
||||
turn_SMI_watchdog_clear_off >= p->iTCO_version) {
|
||||
pr_err("SMI I/O resource is missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
iTCO_wdt_no_reboot_bit_setup(p, pdata);
|
||||
|
||||
/*
|
||||
|
|
@ -492,14 +504,6 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
|
|||
/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
|
||||
p->update_no_reboot_bit(p->no_reboot_priv, true);
|
||||
|
||||
/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
|
||||
if (!devm_request_region(dev, p->smi_res->start,
|
||||
resource_size(p->smi_res),
|
||||
pdev->name)) {
|
||||
pr_err("I/O address 0x%04llx already in use, device disabled\n",
|
||||
(u64)SMI_EN(p));
|
||||
return -EBUSY;
|
||||
}
|
||||
if (turn_SMI_watchdog_clear_off >= p->iTCO_version) {
|
||||
/*
|
||||
* Bit 13: TCO_EN -> 0
|
||||
|
|
|
|||
|
|
@ -326,7 +326,8 @@ extern void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);
|
|||
|
||||
/* inline_crypt.c */
|
||||
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
|
||||
extern void fscrypt_select_encryption_impl(struct fscrypt_info *ci);
|
||||
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)
|
||||
|
|
@ -370,8 +371,10 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
|
|||
|
||||
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
|
||||
|
||||
static inline void fscrypt_select_encryption_impl(struct fscrypt_info *ci)
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -25,26 +25,76 @@ struct fscrypt_blk_crypto_key {
|
|||
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);
|
||||
}
|
||||
|
||||
/* Enable inline encryption for this file if supported. */
|
||||
void fscrypt_select_encryption_impl(struct fscrypt_info *ci)
|
||||
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;
|
||||
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;
|
||||
return 0;
|
||||
|
||||
/* blk-crypto must implement the needed encryption algorithm */
|
||||
if (ci->ci_mode->blk_crypto_mode == BLK_ENCRYPTION_MODE_INVALID)
|
||||
return;
|
||||
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;
|
||||
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);
|
||||
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
if (!keyslot_manager_crypto_mode_supported(devs[i]->ksm,
|
||||
crypto_mode,
|
||||
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,
|
||||
|
|
@ -56,14 +106,13 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_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;
|
||||
int num_devs = 1;
|
||||
int num_devs;
|
||||
int queue_refs = 0;
|
||||
struct fscrypt_blk_crypto_key *blk_key;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
if (sb->s_cop->get_num_devices)
|
||||
num_devs = sb->s_cop->get_num_devices(sb);
|
||||
num_devs = fscrypt_get_num_devices(sb);
|
||||
if (WARN_ON(num_devs < 1))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -72,10 +121,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
|
|||
return -ENOMEM;
|
||||
|
||||
blk_key->num_devs = num_devs;
|
||||
if (num_devs == 1)
|
||||
blk_key->devs[0] = bdev_get_queue(sb->s_bdev);
|
||||
else
|
||||
sb->s_cop->get_devices(sb, blk_key->devs);
|
||||
fscrypt_get_devices(sb, num_devs, blk_key->devs);
|
||||
|
||||
BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE >
|
||||
BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE);
|
||||
|
|
@ -103,6 +149,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
|
|||
queue_refs++;
|
||||
|
||||
err = blk_crypto_start_using_mode(crypto_mode, sb->s_blocksize,
|
||||
is_hw_wrapped,
|
||||
blk_key->devs[i]);
|
||||
if (err) {
|
||||
fscrypt_err(inode,
|
||||
|
|
|
|||
|
|
@ -328,8 +328,6 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
|
|||
struct fscrypt_key_specifier mk_spec;
|
||||
int err;
|
||||
|
||||
fscrypt_select_encryption_impl(ci);
|
||||
|
||||
switch (ci->ci_policy.version) {
|
||||
case FSCRYPT_POLICY_V1:
|
||||
mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
|
||||
|
|
@ -354,6 +352,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
|
||||
|
|
@ -388,6 +390,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);
|
||||
|
|
|
|||
|
|
@ -27,28 +27,19 @@ 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);
|
||||
spin_lock_init(&mi->mi_log.rl_writer_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,6 +48,26 @@ err:
|
|||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
int incfs_realloc_mount_info(struct mount_info *mi,
|
||||
struct mount_options *options)
|
||||
{
|
||||
kfree(mi->mi_log.rl_ring_buf);
|
||||
mi->mi_log.rl_ring_buf = NULL;
|
||||
mi->mi_log.rl_size = 0;
|
||||
|
||||
mi->mi_options = *options;
|
||||
if (options->read_log_pages != 0) {
|
||||
size_t buf_size = PAGE_SIZE * options->read_log_pages;
|
||||
|
||||
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)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void incfs_free_mount_info(struct mount_info *mi)
|
||||
{
|
||||
if (!mi)
|
||||
|
|
@ -371,11 +382,19 @@ static int get_data_file_block(struct data_file *df, int index,
|
|||
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)
|
||||
{
|
||||
if (*size_out + sizeof(*range) > size)
|
||||
return -ERANGE;
|
||||
int error = check_room_for_one_range(size, *size_out);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (copy_to_user(((char *)buffer) + *size_out, range, sizeof(*range)))
|
||||
return -EFAULT;
|
||||
|
|
@ -384,6 +403,34 @@ static int copy_one_range(struct incfs_filled_range *range, void __user *buffer,
|
|||
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;
|
||||
}
|
||||
|
||||
int incfs_get_filled_blocks(struct data_file *df,
|
||||
struct incfs_get_filled_blocks_args *arg)
|
||||
{
|
||||
|
|
@ -400,6 +447,7 @@ int incfs_get_filled_blocks(struct data_file *df,
|
|||
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");
|
||||
|
|
@ -407,14 +455,22 @@ int incfs_get_filled_blocks(struct data_file *df,
|
|||
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 copy_one_range(&range, buffer, size, size_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (arg->index_out = arg->start_index; arg->index_out < end_index;
|
||||
|
|
@ -429,13 +485,20 @@ int incfs_get_filled_blocks(struct data_file *df,
|
|||
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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -443,17 +506,15 @@ int incfs_get_filled_blocks(struct data_file *df,
|
|||
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;
|
||||
|
||||
df->df_header_flags |= INCFS_FILE_COMPLETE;
|
||||
result = incfs_update_file_header_flags(
|
||||
df->df_backing_file_context, df->df_header_flags);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,6 +223,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);
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ static int append_md_to_backing_file(struct backing_file_context *bfc,
|
|||
return result;
|
||||
}
|
||||
|
||||
int incfs_update_file_header_flags(struct backing_file_context *bfc, u32 flags)
|
||||
int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags)
|
||||
{
|
||||
if (!bfc)
|
||||
return -EFAULT;
|
||||
|
|
|
|||
|
|
@ -311,7 +311,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,
|
||||
struct mem_range sig, u32 tree_size);
|
||||
|
||||
int incfs_update_file_header_flags(struct backing_file_context *bfc, u32 flags);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -347,8 +347,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)
|
||||
|
|
@ -894,6 +894,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;
|
||||
|
|
@ -1444,6 +1445,9 @@ static long ioctl_get_filled_blocks(struct file *f, void __user *arg)
|
|||
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;
|
||||
|
||||
|
|
@ -1676,6 +1680,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;
|
||||
|
|
@ -1978,6 +1983,7 @@ static void dentry_release(struct dentry *d)
|
|||
|
||||
if (di)
|
||||
path_put(&di->backing_path);
|
||||
kfree(d->d_fsdata);
|
||||
d->d_fsdata = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2189,7 +2195,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;
|
||||
|
|
@ -2210,12 +2216,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;
|
||||
}
|
||||
|
||||
|
|
@ -2223,7 +2228,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@ int blk_crypto_init_key(struct blk_crypto_key *blk_key,
|
|||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int data_unit_size);
|
||||
|
||||
int blk_crypto_start_using_mode(enum blk_crypto_mode_num crypto_mode,
|
||||
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);
|
||||
|
||||
|
|
@ -39,22 +44,10 @@ static inline bool blk_crypto_endio(struct bio *bio)
|
|||
|
||||
#ifdef CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK
|
||||
|
||||
int blk_crypto_start_using_mode(enum blk_crypto_mode_num mode_num,
|
||||
unsigned int data_unit_size,
|
||||
struct request_queue *q);
|
||||
|
||||
int blk_crypto_fallback_init(void);
|
||||
|
||||
#else /* CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK */
|
||||
|
||||
static inline int
|
||||
blk_crypto_start_using_mode(enum blk_crypto_mode_num mode_num,
|
||||
unsigned int data_unit_size,
|
||||
struct request_queue *q)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blk_crypto_fallback_init(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ struct ftrace_likely_data {
|
|||
unsigned long constant;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ENABLE_MUST_CHECK
|
||||
#if defined(CONFIG_ENABLE_MUST_CHECK) && !defined(__GENKSYMS__)
|
||||
#define __must_check __attribute__((__warn_unused_result__))
|
||||
#else
|
||||
#define __must_check
|
||||
|
|
|
|||
|
|
@ -201,9 +201,6 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy)
|
|||
return cpumask_weight(policy->cpus) > 1;
|
||||
}
|
||||
|
||||
/* /sys/devices/system/cpu/cpufreq: entry point for global variables */
|
||||
extern struct kobject *cpufreq_global_kobject;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
unsigned int cpufreq_get(unsigned int cpu);
|
||||
unsigned int cpufreq_quick_get(unsigned int cpu);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ struct vm_area_struct;
|
|||
#else
|
||||
#define ___GFP_NOLOCKDEP 0
|
||||
#endif
|
||||
#define ___GFP_CMA 0x1000000u
|
||||
/* If the above are modified, __GFP_BITS_SHIFT may need updating */
|
||||
|
||||
/*
|
||||
|
|
@ -57,6 +58,7 @@ struct vm_area_struct;
|
|||
#define __GFP_HIGHMEM ((__force gfp_t)___GFP_HIGHMEM)
|
||||
#define __GFP_DMA32 ((__force gfp_t)___GFP_DMA32)
|
||||
#define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* ZONE_MOVABLE allowed */
|
||||
#define __GFP_CMA ((__force gfp_t)___GFP_CMA)
|
||||
#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
|
||||
|
||||
/**
|
||||
|
|
@ -217,8 +219,13 @@ struct vm_area_struct;
|
|||
#define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP)
|
||||
|
||||
/* Room for N __GFP_FOO bits */
|
||||
#define __GFP_BITS_SHIFT (23 + IS_ENABLED(CONFIG_LOCKDEP))
|
||||
#define __GFP_BITS_SHIFT (25)
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
|
||||
#else
|
||||
#define __GFP_BITS_MASK (((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) & \
|
||||
~0x800000u)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* DOC: Useful GFP flag combinations
|
||||
|
|
|
|||
|
|
@ -205,7 +205,12 @@ static inline struct page *
|
|||
alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
|
||||
unsigned long vaddr)
|
||||
{
|
||||
#ifndef CONFIG_CMA
|
||||
return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
|
||||
#else
|
||||
return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma,
|
||||
vaddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void clear_highpage(struct page *page)
|
||||
|
|
|
|||
|
|
@ -144,6 +144,18 @@ struct ion_heap {
|
|||
|
||||
#define ion_device_add_heap(heap) __ion_device_add_heap(heap, THIS_MODULE)
|
||||
|
||||
/**
|
||||
* struct ion_dma_buf_attachment - hold device-table attachment data for buffer
|
||||
* @dev: device attached to the buffer.
|
||||
* @table: cached mapping.
|
||||
* @list: list of ion_dma_buf_attachment.
|
||||
*/
|
||||
struct ion_dma_buf_attachment {
|
||||
struct device *dev;
|
||||
struct sg_table *table;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ION
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@
|
|||
|
||||
#include <linux/bio.h>
|
||||
|
||||
/* 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;
|
||||
|
|
@ -45,6 +54,7 @@ struct keyslot_manager *keyslot_manager_create(
|
|||
struct device *dev,
|
||||
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);
|
||||
|
||||
|
|
@ -57,7 +67,8 @@ 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 data_unit_size);
|
||||
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);
|
||||
|
|
@ -71,6 +82,7 @@ void keyslot_manager_destroy(struct keyslot_manager *ksm);
|
|||
struct keyslot_manager *keyslot_manager_create_passthrough(
|
||||
struct device *dev,
|
||||
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);
|
||||
|
||||
|
|
|
|||
7
include/linux/mfd/sc27xx-pmic.h
Normal file
7
include/linux/mfd/sc27xx-pmic.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __LINUX_MFD_SC27XX_PMIC_H
|
||||
#define __LINUX_MFD_SC27XX_PMIC_H
|
||||
|
||||
extern enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev);
|
||||
|
||||
#endif /* __LINUX_MFD_SC27XX_PMIC_H */
|
||||
|
|
@ -463,6 +463,9 @@ struct mmc_host {
|
|||
bool cqe_enabled;
|
||||
bool cqe_on;
|
||||
|
||||
/* Host Software Queue support */
|
||||
bool hsq_enabled;
|
||||
|
||||
unsigned long private[0] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ enum migratetype {
|
|||
MIGRATE_UNMOVABLE,
|
||||
MIGRATE_MOVABLE,
|
||||
MIGRATE_RECLAIMABLE,
|
||||
MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
|
||||
MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
|
||||
#ifdef CONFIG_CMA
|
||||
/*
|
||||
* MIGRATE_CMA migration type is designed to mimic the way
|
||||
|
|
@ -61,6 +59,8 @@ enum migratetype {
|
|||
*/
|
||||
MIGRATE_CMA,
|
||||
#endif
|
||||
MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
|
||||
MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
|
||||
#ifdef CONFIG_MEMORY_ISOLATION
|
||||
MIGRATE_ISOLATE, /* can't allocate from here */
|
||||
#endif
|
||||
|
|
@ -73,9 +73,11 @@ extern const char * const migratetype_names[MIGRATE_TYPES];
|
|||
#ifdef CONFIG_CMA
|
||||
# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
|
||||
# define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA)
|
||||
# define get_cma_migrate_type() MIGRATE_CMA
|
||||
#else
|
||||
# define is_migrate_cma(migratetype) false
|
||||
# define is_migrate_cma_page(_page) false
|
||||
# define get_cma_migrate_type() MIGRATE_MOVABLE
|
||||
#endif
|
||||
|
||||
static inline bool is_migrate_movable(int mt)
|
||||
|
|
@ -444,6 +446,10 @@ struct zone {
|
|||
struct pglist_data *zone_pgdat;
|
||||
struct per_cpu_pageset __percpu *pageset;
|
||||
|
||||
#ifdef CONFIG_CMA
|
||||
bool cma_alloc;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPARSEMEM
|
||||
/*
|
||||
* Flags for a pageblock_nr_pages block. See pageblock-flags.h.
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ enum {
|
|||
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,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
|||
|
|
@ -20,11 +20,18 @@
|
|||
|
||||
#define MAX_SUSPEND_ABORT_LEN 256
|
||||
|
||||
void log_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 */
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
#ifndef __UAPI_CORESIGHT_STM_H_
|
||||
#define __UAPI_CORESIGHT_STM_H_
|
||||
|
||||
#define STM_FLAG_TIMESTAMPED BIT(3)
|
||||
#define STM_FLAG_GUARANTEED BIT(7)
|
||||
#include <linux/const.h>
|
||||
|
||||
#define STM_FLAG_TIMESTAMPED _BITUL(3)
|
||||
#define STM_FLAG_GUARANTEED _BITUL(7)
|
||||
|
||||
/*
|
||||
* The CoreSight STM supports guaranteed and invariant timing
|
||||
|
|
|
|||
|
|
@ -321,6 +321,9 @@ struct incfs_get_filled_blocks_args {
|
|||
/* 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ config GKI_HIDDEN_SND_SOC_CONFIGS
|
|||
select SND_SOC_GENERIC_DMAENGINE_PCM if (SND_SOC && SND)
|
||||
select SND_PCM_IEC958
|
||||
select SND_SOC_COMPRESS if (SND_SOC && SND)
|
||||
select SND_SOC_TOPOLOGY if (SND_SOC && SND)
|
||||
help
|
||||
Dummy config option used to enable hidden SND_SOC configs.
|
||||
These are normally selected implicitly when a module
|
||||
|
|
|
|||
|
|
@ -35,4 +35,4 @@ include/generated/compile.h: FORCE
|
|||
@$($(quiet)chk_compile.h)
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
|
||||
"$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" \
|
||||
"$(CONFIG_PREEMPT_RT)" "$(CC) $(KBUILD_CFLAGS)"
|
||||
"$(CONFIG_PREEMPT_RT)" "$(CC) $(KBUILD_CFLAGS)" "$(LD)"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
|
||||
#include <trace/events/irq.h>
|
||||
|
||||
|
|
@ -507,8 +508,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
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ out:
|
|||
* 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);
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ static int padata_replace(struct padata_instance *pinst)
|
|||
{
|
||||
int notification_mask = 0;
|
||||
struct padata_shell *ps;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
pinst->flags |= PADATA_RESET;
|
||||
|
||||
|
|
@ -643,8 +643,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:
|
||||
|
|
@ -662,8 +662,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <linux/kmod.h>
|
||||
#include <trace/events/power.h>
|
||||
#include <linux/cpuset.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
|
||||
/*
|
||||
* Timeout for stopping processes
|
||||
|
|
@ -39,9 +38,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();
|
||||
|
||||
|
|
@ -71,11 +67,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ static void s2idle_loop(void)
|
|||
}
|
||||
|
||||
pm_wakeup_clear(false);
|
||||
clear_wakeup_reasons();
|
||||
|
||||
s2idle_enter();
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -417,7 +418,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);
|
||||
|
|
@ -453,9 +454,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();
|
||||
|
|
@ -490,7 +488,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))
|
||||
|
|
@ -509,11 +507,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");
|
||||
|
|
|
|||
|
|
@ -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,42 +26,282 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
#define MAX_WAKEUP_REASON_IRQS 32
|
||||
static int irq_list[MAX_WAKEUP_REASON_IRQS];
|
||||
static int irqcount;
|
||||
static DEFINE_SPINLOCK(wakeup_reason_lock);
|
||||
|
||||
static LIST_HEAD(leaf_irqs); /* kept in ascending IRQ sorted order */
|
||||
static LIST_HEAD(parent_irqs); /* unordered */
|
||||
|
||||
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 spinlock_t 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;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&resume_reason_lock, flags);
|
||||
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;
|
||||
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_irqrestore(&resume_reason_lock, flags);
|
||||
|
||||
spin_unlock_irqrestore(&wakeup_reason_lock, flags);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -90,8 +330,8 @@ static ssize_t last_suspend_time_show(struct kobject *kobj,
|
|||
|
||||
/* Export suspend_resume_time and sleep_time in pair here. */
|
||||
return sprintf(buf, "%llu.%09lu %llu.%09lu\n",
|
||||
suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec,
|
||||
sleep_time.tv_sec, sleep_time.tv_nsec);
|
||||
suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec,
|
||||
sleep_time.tv_sec, sleep_time.tv_nsec);
|
||||
}
|
||||
|
||||
static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason);
|
||||
|
|
@ -106,74 +346,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;
|
||||
unsigned long flags;
|
||||
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_irqsave(&resume_reason_lock, flags);
|
||||
if (irqcount == MAX_WAKEUP_REASON_IRQS) {
|
||||
spin_unlock_irqrestore(&resume_reason_lock, flags);
|
||||
printk(KERN_WARNING "Resume caused by more than %d IRQs\n",
|
||||
MAX_WAKEUP_REASON_IRQS);
|
||||
return;
|
||||
}
|
||||
|
||||
irq_list[irqcount++] = irq;
|
||||
spin_unlock_irqrestore(&resume_reason_lock, flags);
|
||||
}
|
||||
|
||||
void log_suspend_abort_reason(const char *fmt, ...)
|
||||
{
|
||||
unsigned long flags;
|
||||
va_list args;
|
||||
|
||||
spin_lock_irqsave(&resume_reason_lock, flags);
|
||||
|
||||
//Suspend abort reason has already been logged.
|
||||
if (suspend_abort) {
|
||||
spin_unlock_irqrestore(&resume_reason_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
suspend_abort = true;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args);
|
||||
va_end(args);
|
||||
spin_unlock_irqrestore(&resume_reason_lock, flags);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
unsigned long flags;
|
||||
switch (pm_event) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
spin_lock_irqsave(&resume_reason_lock, flags);
|
||||
irqcount = 0;
|
||||
suspend_abort = false;
|
||||
spin_unlock_irqrestore(&resume_reason_lock, flags);
|
||||
/* 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;
|
||||
|
|
@ -185,31 +375,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)
|
||||
{
|
||||
int retval;
|
||||
spin_lock_init(&resume_reason_lock);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -41,8 +41,67 @@ static int convert_prio(int prio)
|
|||
return cpupri;
|
||||
}
|
||||
|
||||
static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
|
||||
struct cpumask *lowest_mask, int idx)
|
||||
{
|
||||
struct cpupri_vec *vec = &cp->pri_to_cpu[idx];
|
||||
int skip = 0;
|
||||
|
||||
if (!atomic_read(&(vec)->count))
|
||||
skip = 1;
|
||||
/*
|
||||
* When looking at the vector, we need to read the counter,
|
||||
* do a memory barrier, then read the mask.
|
||||
*
|
||||
* Note: This is still all racey, but we can deal with it.
|
||||
* Ideally, we only want to look at masks that are set.
|
||||
*
|
||||
* If a mask is not set, then the only thing wrong is that we
|
||||
* did a little more work than necessary.
|
||||
*
|
||||
* If we read a zero count but the mask is set, because of the
|
||||
* memory barriers, that can only happen when the highest prio
|
||||
* task for a run queue has left the run queue, in which case,
|
||||
* it will be followed by a pull. If the task we are processing
|
||||
* fails to find a proper place to go, that pull request will
|
||||
* pull this task if the run queue is running at a lower
|
||||
* priority.
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
/* Need to do the rmb for every iteration */
|
||||
if (skip)
|
||||
return 0;
|
||||
|
||||
if (cpumask_any_and(p->cpus_ptr, vec->mask) >= nr_cpu_ids)
|
||||
return 0;
|
||||
|
||||
if (lowest_mask) {
|
||||
cpumask_and(lowest_mask, p->cpus_ptr, vec->mask);
|
||||
|
||||
/*
|
||||
* We have to ensure that we have at least one bit
|
||||
* still set in the array, since the map could have
|
||||
* been concurrently emptied between the first and
|
||||
* second reads of vec->mask. If we hit this
|
||||
* condition, simply act as though we never hit this
|
||||
* priority level and continue on.
|
||||
*/
|
||||
if (cpumask_empty(lowest_mask))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cpupri_find(struct cpupri *cp, struct task_struct *p,
|
||||
struct cpumask *lowest_mask)
|
||||
{
|
||||
return cpupri_find_fitness(cp, p, lowest_mask, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* cpupri_find - find the best (lowest-pri) CPU in the system
|
||||
* cpupri_find_fitness - find the best (lowest-pri) CPU in the system
|
||||
* @cp: The cpupri context
|
||||
* @p: The task
|
||||
* @lowest_mask: A mask to fill in with selected CPUs (or NULL)
|
||||
|
|
@ -58,84 +117,59 @@ static int convert_prio(int prio)
|
|||
*
|
||||
* Return: (int)bool - CPUs were found
|
||||
*/
|
||||
int cpupri_find(struct cpupri *cp, struct task_struct *p,
|
||||
int cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
|
||||
struct cpumask *lowest_mask,
|
||||
bool (*fitness_fn)(struct task_struct *p, int cpu))
|
||||
{
|
||||
int idx = 0;
|
||||
int task_pri = convert_prio(p->prio);
|
||||
int idx, cpu;
|
||||
|
||||
BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);
|
||||
|
||||
for (idx = 0; idx < task_pri; idx++) {
|
||||
struct cpupri_vec *vec = &cp->pri_to_cpu[idx];
|
||||
int skip = 0;
|
||||
|
||||
if (!atomic_read(&(vec)->count))
|
||||
skip = 1;
|
||||
/*
|
||||
* When looking at the vector, we need to read the counter,
|
||||
* do a memory barrier, then read the mask.
|
||||
*
|
||||
* Note: This is still all racey, but we can deal with it.
|
||||
* Ideally, we only want to look at masks that are set.
|
||||
*
|
||||
* If a mask is not set, then the only thing wrong is that we
|
||||
* did a little more work than necessary.
|
||||
*
|
||||
* If we read a zero count but the mask is set, because of the
|
||||
* memory barriers, that can only happen when the highest prio
|
||||
* task for a run queue has left the run queue, in which case,
|
||||
* it will be followed by a pull. If the task we are processing
|
||||
* fails to find a proper place to go, that pull request will
|
||||
* pull this task if the run queue is running at a lower
|
||||
* priority.
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
/* Need to do the rmb for every iteration */
|
||||
if (skip)
|
||||
if (!__cpupri_find(cp, p, lowest_mask, idx))
|
||||
continue;
|
||||
|
||||
if (cpumask_any_and(p->cpus_ptr, vec->mask) >= nr_cpu_ids)
|
||||
continue;
|
||||
if (!lowest_mask || !fitness_fn)
|
||||
return 1;
|
||||
|
||||
if (lowest_mask) {
|
||||
int cpu;
|
||||
|
||||
cpumask_and(lowest_mask, p->cpus_ptr, vec->mask);
|
||||
|
||||
/*
|
||||
* We have to ensure that we have at least one bit
|
||||
* still set in the array, since the map could have
|
||||
* been concurrently emptied between the first and
|
||||
* second reads of vec->mask. If we hit this
|
||||
* condition, simply act as though we never hit this
|
||||
* priority level and continue on.
|
||||
*/
|
||||
if (cpumask_empty(lowest_mask))
|
||||
continue;
|
||||
|
||||
if (!fitness_fn)
|
||||
return 1;
|
||||
|
||||
/* Ensure the capacity of the CPUs fit the task */
|
||||
for_each_cpu(cpu, lowest_mask) {
|
||||
if (!fitness_fn(p, cpu))
|
||||
cpumask_clear_cpu(cpu, lowest_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* If no CPU at the current priority can fit the task
|
||||
* continue looking
|
||||
*/
|
||||
if (cpumask_empty(lowest_mask))
|
||||
continue;
|
||||
/* Ensure the capacity of the CPUs fit the task */
|
||||
for_each_cpu(cpu, lowest_mask) {
|
||||
if (!fitness_fn(p, cpu))
|
||||
cpumask_clear_cpu(cpu, lowest_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* If no CPU at the current priority can fit the task
|
||||
* continue looking
|
||||
*/
|
||||
if (cpumask_empty(lowest_mask))
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we failed to find a fitting lowest_mask, kick off a new search
|
||||
* but without taking into account any fitness criteria this time.
|
||||
*
|
||||
* This rule favours honouring priority over fitting the task in the
|
||||
* correct CPU (Capacity Awareness being the only user now).
|
||||
* The idea is that if a higher priority task can run, then it should
|
||||
* run even if this ends up being on unfitting CPU.
|
||||
*
|
||||
* The cost of this trade-off is not entirely clear and will probably
|
||||
* be good for some workloads and bad for others.
|
||||
*
|
||||
* The main idea here is that if some CPUs were overcommitted, we try
|
||||
* to spread which is what the scheduler traditionally did. Sys admins
|
||||
* must do proper RT planning to avoid overloading the system if they
|
||||
* really care.
|
||||
*/
|
||||
if (fitness_fn)
|
||||
return cpupri_find(cp, p, lowest_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ struct cpupri {
|
|||
|
||||
#ifdef CONFIG_SMP
|
||||
int cpupri_find(struct cpupri *cp, struct task_struct *p,
|
||||
struct cpumask *lowest_mask,
|
||||
bool (*fitness_fn)(struct task_struct *p, int cpu));
|
||||
struct cpumask *lowest_mask);
|
||||
int cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
|
||||
struct cpumask *lowest_mask,
|
||||
bool (*fitness_fn)(struct task_struct *p, int cpu));
|
||||
void cpupri_set(struct cpupri *cp, int cpu, int pri);
|
||||
int cpupri_init(struct cpupri *cp);
|
||||
void cpupri_cleanup(struct cpupri *cp);
|
||||
|
|
|
|||
|
|
@ -1474,6 +1474,13 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
|
|||
if (test || !rt_task_fits_capacity(p, cpu)) {
|
||||
int target = find_lowest_rq(p);
|
||||
|
||||
/*
|
||||
* Bail out if we were forcing a migration to find a better
|
||||
* fitting CPU but our search failed.
|
||||
*/
|
||||
if (!test && target != -1 && !rt_task_fits_capacity(p, target))
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* Don't bother moving it if the destination CPU is
|
||||
* not running a lower priority task.
|
||||
|
|
@ -1482,6 +1489,8 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
|
|||
p->prio < cpu_rq(target)->rt.highest_prio.curr)
|
||||
cpu = target;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
out:
|
||||
|
|
@ -1495,7 +1504,7 @@ static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
|
|||
* let's hope p can move out.
|
||||
*/
|
||||
if (rq->curr->nr_cpus_allowed == 1 ||
|
||||
!cpupri_find(&rq->rd->cpupri, rq->curr, NULL, NULL))
|
||||
!cpupri_find(&rq->rd->cpupri, rq->curr, NULL))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
|
@ -1503,7 +1512,7 @@ static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
|
|||
* see if it is pushed or pulled somewhere else.
|
||||
*/
|
||||
if (p->nr_cpus_allowed != 1 &&
|
||||
cpupri_find(&rq->rd->cpupri, p, NULL, NULL))
|
||||
cpupri_find(&rq->rd->cpupri, p, NULL))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
|
@ -1650,8 +1659,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
|
|||
static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
|
||||
{
|
||||
if (!task_running(rq, p) &&
|
||||
cpumask_test_cpu(cpu, p->cpus_ptr) &&
|
||||
rt_task_fits_capacity(p, cpu))
|
||||
cpumask_test_cpu(cpu, p->cpus_ptr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1685,6 +1693,7 @@ static int find_lowest_rq(struct task_struct *task)
|
|||
struct cpumask *lowest_mask = this_cpu_cpumask_var_ptr(local_cpu_mask);
|
||||
int this_cpu = smp_processor_id();
|
||||
int cpu = task_cpu(task);
|
||||
int ret;
|
||||
|
||||
/* Make sure the mask is initialized first */
|
||||
if (unlikely(!lowest_mask))
|
||||
|
|
@ -1693,8 +1702,22 @@ static int find_lowest_rq(struct task_struct *task)
|
|||
if (task->nr_cpus_allowed == 1)
|
||||
return -1; /* No other targets possible */
|
||||
|
||||
if (!cpupri_find(&task_rq(task)->rd->cpupri, task, lowest_mask,
|
||||
rt_task_fits_capacity))
|
||||
/*
|
||||
* If we're on asym system ensure we consider the different capacities
|
||||
* of the CPUs when searching for the lowest_mask.
|
||||
*/
|
||||
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
|
||||
|
||||
ret = cpupri_find_fitness(&task_rq(task)->rd->cpupri,
|
||||
task, lowest_mask,
|
||||
rt_task_fits_capacity);
|
||||
} else {
|
||||
|
||||
ret = cpupri_find(&task_rq(task)->rd->cpupri,
|
||||
task, lowest_mask);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return -1; /* No targets found */
|
||||
|
||||
/*
|
||||
|
|
@ -2205,7 +2228,7 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p)
|
|||
(rq->curr->nr_cpus_allowed < 2 ||
|
||||
rq->curr->prio <= p->prio);
|
||||
|
||||
if (need_to_push || !rt_task_fits_capacity(p, cpu_of(rq)))
|
||||
if (need_to_push)
|
||||
push_rt_tasks(rq);
|
||||
}
|
||||
|
||||
|
|
@ -2277,10 +2300,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
|
|||
*/
|
||||
if (task_on_rq_queued(p) && rq->curr != p) {
|
||||
#ifdef CONFIG_SMP
|
||||
bool need_to_push = rq->rt.overloaded ||
|
||||
!rt_task_fits_capacity(p, cpu_of(rq));
|
||||
|
||||
if (p->nr_cpus_allowed > 1 && need_to_push)
|
||||
if (p->nr_cpus_allowed > 1 && rq->rt.overloaded)
|
||||
rt_queue_push_tasks(rq);
|
||||
#endif /* CONFIG_SMP */
|
||||
if (p->prio < rq->curr->prio && cpu_online(cpu_of(rq)))
|
||||
|
|
|
|||
|
|
@ -1627,7 +1627,7 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,
|
|||
struct work_struct *work = &dwork->work;
|
||||
|
||||
WARN_ON_ONCE(!wq);
|
||||
#ifndef CONFIG_CFI
|
||||
#ifndef CONFIG_CFI_CLANG
|
||||
WARN_ON_ONCE(timer->function != delayed_work_timer_fn);
|
||||
#endif
|
||||
WARN_ON_ONCE(timer_pending(timer));
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
static unsigned int tests_run;
|
||||
static unsigned int tests_passed;
|
||||
|
||||
static const unsigned int order_limit =
|
||||
IS_ENABLED(CONFIG_XARRAY_MULTI) ? BITS_PER_LONG : 1;
|
||||
|
||||
#ifndef XA_DEBUG
|
||||
# ifdef __KERNEL__
|
||||
void xa_dump(const struct xarray *xa) { }
|
||||
|
|
@ -959,6 +962,20 @@ static noinline void check_multi_find_2(struct xarray *xa)
|
|||
}
|
||||
}
|
||||
|
||||
static noinline void check_multi_find_3(struct xarray *xa)
|
||||
{
|
||||
unsigned int order;
|
||||
|
||||
for (order = 5; order < order_limit; order++) {
|
||||
unsigned long index = 1UL << (order - 5);
|
||||
|
||||
XA_BUG_ON(xa, !xa_empty(xa));
|
||||
xa_store_order(xa, 0, order - 4, xa_mk_index(0), GFP_KERNEL);
|
||||
XA_BUG_ON(xa, xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT));
|
||||
xa_erase_index(xa, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static noinline void check_find_1(struct xarray *xa)
|
||||
{
|
||||
unsigned long i, j, k;
|
||||
|
|
@ -1081,6 +1098,7 @@ static noinline void check_find(struct xarray *xa)
|
|||
for (i = 2; i < 10; i++)
|
||||
check_multi_find_1(xa, i);
|
||||
check_multi_find_2(xa);
|
||||
check_multi_find_3(xa);
|
||||
}
|
||||
|
||||
/* See find_swap_entry() in mm/shmem.c */
|
||||
|
|
|
|||
|
|
@ -1839,7 +1839,8 @@ static bool xas_sibling(struct xa_state *xas)
|
|||
if (!node)
|
||||
return false;
|
||||
mask = (XA_CHUNK_SIZE << node->shift) - 1;
|
||||
return (xas->xa_index & mask) > (xas->xa_offset << node->shift);
|
||||
return (xas->xa_index & mask) >
|
||||
((unsigned long)xas->xa_offset << node->shift);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2823,7 +2823,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;
|
||||
|
|
@ -2831,6 +2833,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:
|
||||
|
|
|
|||
114
mm/page_alloc.c
114
mm/page_alloc.c
|
|
@ -293,10 +293,10 @@ const char * const migratetype_names[MIGRATE_TYPES] = {
|
|||
"Unmovable",
|
||||
"Movable",
|
||||
"Reclaimable",
|
||||
"HighAtomic",
|
||||
#ifdef CONFIG_CMA
|
||||
"CMA",
|
||||
#endif
|
||||
"HighAtomic",
|
||||
#ifdef CONFIG_MEMORY_ISOLATION
|
||||
"Isolate",
|
||||
#endif
|
||||
|
|
@ -2725,19 +2725,37 @@ __rmqueue(struct zone *zone, unsigned int order, int migratetype,
|
|||
|
||||
retry:
|
||||
page = __rmqueue_smallest(zone, order, migratetype);
|
||||
if (unlikely(!page)) {
|
||||
if (migratetype == MIGRATE_MOVABLE)
|
||||
page = __rmqueue_cma_fallback(zone, order);
|
||||
|
||||
if (!page && __rmqueue_fallback(zone, order, migratetype,
|
||||
alloc_flags))
|
||||
goto retry;
|
||||
}
|
||||
if (unlikely(!page) && __rmqueue_fallback(zone, order, migratetype,
|
||||
alloc_flags))
|
||||
goto retry;
|
||||
|
||||
trace_mm_page_alloc_zone_locked(page, order, migratetype);
|
||||
return page;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMA
|
||||
static struct page *__rmqueue_cma(struct zone *zone, unsigned int order,
|
||||
int migratetype,
|
||||
unsigned int alloc_flags)
|
||||
{
|
||||
struct page *page = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CMA))
|
||||
if (!zone->cma_alloc)
|
||||
page = __rmqueue_cma_fallback(zone, order);
|
||||
trace_mm_page_alloc_zone_locked(page, order, MIGRATE_CMA);
|
||||
return page;
|
||||
}
|
||||
#else
|
||||
static inline struct page *__rmqueue_cma(struct zone *zone, unsigned int order,
|
||||
int migratetype,
|
||||
unsigned int alloc_flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Obtain a specified number of elements from the buddy allocator, all under
|
||||
* a single hold of the lock, for efficiency. Add them to the supplied list.
|
||||
|
|
@ -2751,8 +2769,19 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
|
|||
|
||||
spin_lock(&zone->lock);
|
||||
for (i = 0; i < count; ++i) {
|
||||
struct page *page = __rmqueue(zone, order, migratetype,
|
||||
alloc_flags);
|
||||
struct page *page;
|
||||
|
||||
/*
|
||||
* If migrate type CMA is being requested only try to
|
||||
* satisfy the request with CMA pages to try and increase
|
||||
* CMA utlization.
|
||||
*/
|
||||
if (is_migrate_cma(migratetype))
|
||||
page = __rmqueue_cma(zone, order, migratetype,
|
||||
alloc_flags);
|
||||
else
|
||||
page = __rmqueue(zone, order, migratetype, alloc_flags);
|
||||
|
||||
if (unlikely(page == NULL))
|
||||
break;
|
||||
|
||||
|
|
@ -2787,6 +2816,28 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
|
|||
return alloced;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the pcp list that corresponds to the migrate type if that list isn't
|
||||
* empty.
|
||||
* If the list is empty return NULL.
|
||||
*/
|
||||
static struct list_head *get_populated_pcp_list(struct zone *zone,
|
||||
unsigned int order, struct per_cpu_pages *pcp,
|
||||
int migratetype, unsigned int alloc_flags)
|
||||
{
|
||||
struct list_head *list = &pcp->lists[migratetype];
|
||||
|
||||
if (list_empty(list)) {
|
||||
pcp->count += rmqueue_bulk(zone, order,
|
||||
pcp->batch, list,
|
||||
migratetype, alloc_flags);
|
||||
|
||||
if (list_empty(list))
|
||||
list = NULL;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
/*
|
||||
* Called from the vmstat counter updater to drain pagesets of this
|
||||
|
|
@ -3216,16 +3267,28 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z)
|
|||
static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype,
|
||||
unsigned int alloc_flags,
|
||||
struct per_cpu_pages *pcp,
|
||||
struct list_head *list)
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct page *page;
|
||||
struct page *page = NULL;
|
||||
struct list_head *list = NULL;
|
||||
|
||||
do {
|
||||
if (list_empty(list)) {
|
||||
pcp->count += rmqueue_bulk(zone, 0,
|
||||
pcp->batch, list,
|
||||
/* First try to get CMA pages */
|
||||
if (migratetype == MIGRATE_MOVABLE &&
|
||||
gfp_flags & __GFP_CMA) {
|
||||
list = get_populated_pcp_list(zone, 0, pcp,
|
||||
get_cma_migrate_type(), alloc_flags);
|
||||
}
|
||||
|
||||
if (list == NULL) {
|
||||
/*
|
||||
* Either CMA is not suitable or there are no
|
||||
* free CMA pages.
|
||||
*/
|
||||
list = get_populated_pcp_list(zone, 0, pcp,
|
||||
migratetype, alloc_flags);
|
||||
if (unlikely(list_empty(list)))
|
||||
if (unlikely(list == NULL) ||
|
||||
unlikely(list_empty(list)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -3243,14 +3306,13 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,
|
|||
int migratetype, unsigned int alloc_flags)
|
||||
{
|
||||
struct per_cpu_pages *pcp;
|
||||
struct list_head *list;
|
||||
struct page *page;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
pcp = &this_cpu_ptr(zone->pageset)->pcp;
|
||||
list = &pcp->lists[migratetype];
|
||||
page = __rmqueue_pcplist(zone, migratetype, alloc_flags, pcp, list);
|
||||
page = __rmqueue_pcplist(zone, migratetype, alloc_flags, pcp,
|
||||
gfp_flags);
|
||||
if (page) {
|
||||
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1);
|
||||
zone_statistics(preferred_zone, zone);
|
||||
|
|
@ -3286,14 +3348,22 @@ struct page *rmqueue(struct zone *preferred_zone,
|
|||
|
||||
do {
|
||||
page = NULL;
|
||||
|
||||
if (alloc_flags & ALLOC_HARDER) {
|
||||
page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
|
||||
if (page)
|
||||
trace_mm_page_alloc_zone_locked(page, order, migratetype);
|
||||
}
|
||||
|
||||
if (!page && migratetype == MIGRATE_MOVABLE &&
|
||||
gfp_flags & __GFP_CMA)
|
||||
page = __rmqueue_cma(zone, order, migratetype,
|
||||
alloc_flags);
|
||||
|
||||
if (!page)
|
||||
page = __rmqueue(zone, order, migratetype, alloc_flags);
|
||||
} while (page && check_new_pages(page, order));
|
||||
|
||||
spin_unlock(&zone->lock);
|
||||
if (!page)
|
||||
goto failed;
|
||||
|
|
@ -8442,6 +8512,9 @@ int alloc_contig_range(unsigned long start, unsigned long end,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_CMA
|
||||
cc.zone->cma_alloc = 1;
|
||||
#endif
|
||||
/*
|
||||
* In case of -EBUSY, we'd like to know which page causes problem.
|
||||
* So, just fall through. test_pages_isolated() has a tracepoint
|
||||
|
|
@ -8523,6 +8596,9 @@ int alloc_contig_range(unsigned long start, unsigned long end,
|
|||
done:
|
||||
undo_isolate_page_range(pfn_max_align_down(start),
|
||||
pfn_max_align_up(end), migratetype);
|
||||
#ifdef CONFIG_CMA
|
||||
cc.zone->cma_alloc = 0;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_CONTIG_ALLOC */
|
||||
|
|
|
|||
|
|
@ -2795,6 +2795,8 @@ static u16 skb_tx_hash(const struct net_device *dev,
|
|||
|
||||
if (skb_rx_queue_recorded(skb)) {
|
||||
hash = skb_get_rx_queue(skb);
|
||||
if (hash >= qoffset)
|
||||
hash -= qoffset;
|
||||
while (unlikely(hash >= qcount))
|
||||
hash -= qcount;
|
||||
return hash + qoffset;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue