mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-04 18:19:28 +09:00
Merge branch 'android14-6.1' into android14-6.1-lts
This catches the -lts branch up with a lot of abi updates and resolves a merge conflict in f2fs. Changes in here include: *976b055754UPSTREAM: HID: Use kvzalloc instead of kzalloc in hid_register_field() *fadb08b366FROMGIT: xhci: Fix Link TRB DMA in command ring stopped completion event *19b68814b1Merge tag 'android14-6.1.112_r00' into android14-6.1 *29d66b3902UPSTREAM: exit: Sleep at TASK_IDLE when waiting for application core dump *179ccc9377UPSTREAM: spi: spi-geni-qcom: Rename the label unmap_if_dma *9a072aa707UPSTREAM: spi: spi-geni-qcom: Add SPI Device mode support for GENI based QuPv3 *759bab9407ANDROID: GKI: update symbol list for honor *f949397a1bANDROID: GKI: net: add vendor hooks for link data path *3165cd1163ANDROID: ABI: Update symbol list for spi-geni-qcom updates *3b727b0154UPSTREAM: spi: spi-geni-qcom: Do not do DMA map/unmap inside driver, use framework instead *a874ed06ebUPSTREAM: Revert "tty: serial: simplify qcom_geni_serial_send_chunk_fifo()" *e9c03c47d6UPSTREAM: serial: qcom-geni: Don't cancel/abort if we can't get the port lock *2c16ff3847UPSTREAM: serial: qcom_geni: Convert to platform remove callback returning void *7161dbc311UPSTREAM: serial: qcom-geni: Use port lock wrappers *cd5bd514c0UPSTREAM: tty: serial: qcom-geni-serial: Poll primary sequencer irq status after cancel_tx *5722a4dd8bUPSTREAM: serial: qcom-geni: clean up clock-rate debug printk *d5e0fbcd4aUPSTREAM: serial: qcom-geni: use icc tag defines *5bdef2817aANDROID: ABI: update gki symbol list *a03d1670d2ANDROID: Add vendor hook for cma adjusting *e02772c76dBACKPORT: firmware: arm_scmi: Queue in scmi layer for mailbox implementation *4dc2498506UPSTREAM: tty: serial: simplify qcom_geni_serial_send_chunk_fifo() *719b876f95UPSTREAM: tty: serial: qcom-geni-serial: Add a poll_init() function *d15f99d2b5UPSTREAM: serial: qcom-geni: drop bogus uart_write_wakeup() *3991e7fcc9UPSTREAM: serial: qcom-geni: fix mapping of empty DMA buffer *64bccf317eUPSTREAM: serial: qcom-geni: fix DMA mapping leak on shutdown *4c3917c600UPSTREAM: serial: qcom-geni: fix console shutdown hang *8bbc5694dbUPSTREAM: serial: qcom_geni: Fix variable naming *53be6ca12dBACKPORT: tty: serial: qcom-geni-serial: add support for serial engine DMA *3321cd20f3BACKPORT: soc: qcom-geni-se: add more symbol definitions *61df751af7BACKPORT: tty: serial: qcom-geni-serial: use of_device_id data *3ebd383e35BACKPORT: tty: serial: qcom-geni-serial: drop the return value from handle_rx *a88673be7eUPSTREAM: tty: serial: qcom-geni-serial: refactor qcom_geni_serial_send_chunk_fifo() *94076b81a1UPSTREAM: soc: qcom: geni-se: add GP_LENGTH/IRQ_EN_SET/IRQ_EN_CLEAR registers *a137aa79a6UPSTREAM: soc: qcom: geni-se: Add M_TX_FIFO_NOT_EMPTY bit definition *1790581f0aFROMLIST: ufs: core: requeue aborted request *51903b71f0FROMLIST: ufs: core: fix the issue of ICU failure *00f19bd9edANDROID: GKI: Add symbol for rockchip pci remove *5e1f4bb11fANDROID: abi_gki_aarch64_qcom: Add pci_ecam_map_bus and pci_host_common_probe *72f51dd698ANDROID: abi_gki_aarch64_honor: whitelist symbols added for skip memcg reclaim by priority *f2b3f5888fANDROID: mm: add vendor hook to skip memcg reclaim by priority *add3d68602ANDROID: KVM: arm64: Don't run a protected VCPU if it isn't runnable *1fe91f863aANDROID: usb: Optimization the transfer rate of accessory mode in USB3.2 mode *299cc91948UPSTREAM: spi: spi-geni-qcom: Select FIFO mode for chip select *b490c66749ANDROID: KVM: arm64: Don't skip accounting when memcache top-up fails *1181501872ANDROID: KVM: arm64: Fix accounting when VM creation fails *8baadbac00UPSTREAM: spi: geni-qcom: Convert to platform remove callback returning void *5ab05b86efUPSTREAM: spi: spi-geni-qcom: Add support for SE DMA mode *271bd223ddUPSTREAM: soc: qcom: geni-se: Add SPI Device mode support for GENI based QuPv3 *27021bed80UPSTREAM: tty: serial: qcom-geni-serial: split out the FIFO tx code *ad717604beUPSTREAM: tty: serial: qcom-geni-serial: remove unneeded tabs *ad37632534UPSTREAM: tty: serial: qcom-geni-serial: refactor qcom_geni_serial_isr() *1f0775355fUPSTREAM: tty: serial: qcom-geni-serial: remove stray newlines *59cbbd0b09UPSTREAM: tty: serial: qcom-geni-serial: improve the to_dev_port() macro *f4eec633c0UPSTREAM: tty: serial: qcom-geni-serial: align #define values *b92a6c8545UPSTREAM: tty: serial: qcom-geni-serial: remove unused symbols *6e6cda8f06UPSTREAM: tty: serial: qcom-geni-serial: drop unneeded forward definitions *d75a50763eUPSTREAM: tty: serial: qcom-geni-serial: stop operations in progress at shutdown *481220c5b9ANDROID: abi_gki_aarch64_qcom: whitelist mm symbols *e697302b05ANDROID: mm: export lru_gen_caps *1a3bbc1910ANDROID: mm: export unpack_shadow *a6266110c1UPSTREAM: i2c: qcom-geni: Use IRQF_NO_AUTOEN flag in request_irq() *c24feb930aUPSTREAM: i2c: qcom-geni: Use goto for clearer exit path *80c036f7f2UPSTREAM: i2c: qcom-geni: Add missing geni_icc_disable in geni_i2c_runtime_resume *688cbb4ceeUPSTREAM: i2c: qcom-geni: Add missing geni_icc_disable in geni_i2c_runtime_resume *aff2261bb1UPSTREAM: i2c: qcom-geni: Add missing clk_disable_unprepare in geni_i2c_runtime_resume *371a327f3dUPSTREAM: i2c: qcom-geni: use 'time_left' variable with wait_for_completion_timeout() *c756c6b094UPSTREAM: i2c: qcom-geni: remove printout on handled timeouts *fa329140c1UPSTREAM: i2c: qcom-geni: fix missing clk_disable_unprepare() and geni_se_resources_off() *8fd3f0784dUPSTREAM: i2c: qcom-geni: Convert to devm_platform_ioremap_resource() *02b20eb4bcUPSTREAM: i2c: Convert to platform remove callback returning void *a650b9fb29UPSTREAM: i2c: qcom-geni: change i2c_master_hub to static *aa4151b832UPSTREAM: i2c: qcom-geni: add support for I2C Master Hub variant *47d1f8edd6UPSTREAM: i2c: qcom-geni: add desc struct to prepare support for I2C Master Hub variant *752034bc87UPSTREAM: wifi: cfg80211: fix reporting failed MLO links status with cfg80211_connect_done *40c204b003UPSTREAM: scsi: ufs: core: Do not set link to OFF state while waking up from hibernation *2589c7fa08UPSTREAM: mm/mglru: fix overshooting shrinker memory *4d8187d2c8UPSTREAM: gso: fix udp gso fraglist segmentation after pull from frag_list *b11f74b6c1UPSTREAM: soc: qcom: geni-se: Do not bother about enable/disable of interrupts in secondary sequencer *f9d2a8a3bfUPSTREAM: soc: qcom: geni-se: Add interfaces geni_se_tx_init_dma() and geni_se_rx_init_dma() *8097478ae8UPSTREAM: unicode: Don't special case ignorable code points *d41d398db6BACKPORT: f2fs: fix to handle segment allocation failure correctly *751a02f798UPSTREAM: f2fs: stop checkpoint when get a out-of-bounds segment *acc7335e1fBACKPORT: f2fs: kill heap-based allocation *19e119d2d0Reapply "io_uring: drop any code related to SCM_RIGHTS" *80e851bf0dFROMGIT: scsi: ufs: core: Support Updating UIC Command Timeout *0d60f50b9dANDROID: GKI: Update symbol list for mtk *0ff444ed0bUPSTREAM: Revert "usb: typec: tcpm: clear pd_event queue in PORT_RESET" *311457e823ANDROID: GKI: update symbol list for transsion *8d29837471UPSTREAM: firmware_loader: Abort all upcoming firmware load request once reboot triggered *a9d791a2b2UPSTREAM: firmware_loader: Refactor kill_pending_fw_fallback_reqs() *0e8b65e41fANDROID: sched: Make uclamp changes depend on CAP_SYS_NICE *d4dab27b9dUPSTREAM: f2fs: fix to update i_ctime in __f2fs_setxattr() *d645f73da1UPSTREAM: f2fs: atomic: fix to truncate pagecache before on-disk metadata truncation *693980c220BACKPORT: f2fs: Create COW inode from parent dentry for atomic write *e35539a5acBACKPORT: f2fs: atomic: fix to avoid racing w/ GC *9de4353ca0UPSTREAM: f2fs: use meta inode for GC of COW file *9b5ee2f2b1BACKPORT: f2fs: use meta inode for GC of atomic file *30f8a76da5ANDROID: abi_gki_aarch64_qcom: Add missing symbol to QCOM list *6f2e0215d7ANDROID: GKI: Add KMI symbols for virtio-audio *ba06e1f121ANDROID: fix up ABI with change to private struct geni_wrapper *e0de5c9e33UPSTREAM: soc: qcom: geni-se: add desc struct to specify clocks from device match data *1cdc168f1eANDROID: GKI: Update symbol list for mtk *7c49c3aceaUPSTREAM: arm64: cputype: Add Neoverse-V3 definitions *53769a60e3UPSTREAM: arm64: cputype: Add Cortex-X4 definitions *ecc82c7e71UPSTREAM: arm64: barrier: Restore spec_bar() macro *bd3cc5c733UPSTREAM: KVM: arm64: Add memory length checks and remove inline in do_ffa_mem_xfer *a43e7c2c12ANDROID: GKI: Update symbol list for BCMSTB *5162f9a67bUPSTREAM: arm64: Add Neoverse-V2 part *1105954181UPSTREAM: usb: dwc3: core: update LC timer as per USB Spec V3.2 *cc274231f6ANDROID: GKI: Add symbol for pci power limit Change-Id: Ie47fa8a9c5b1da4140b099de4d9d6647089c6e18 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -122,6 +122,7 @@ filegroup(
|
||||
"android/abi_gki_aarch64_sony",
|
||||
"android/abi_gki_aarch64_sunxi",
|
||||
"android/abi_gki_aarch64_telechips",
|
||||
"android/abi_gki_aarch64_transsion",
|
||||
"android/abi_gki_aarch64_tuxera",
|
||||
"android/abi_gki_aarch64_type_visibility",
|
||||
"android/abi_gki_aarch64_unisoc",
|
||||
|
||||
@@ -126,9 +126,7 @@ norecovery Disable the roll-forward recovery routine, mounted read-
|
||||
discard/nodiscard Enable/disable real-time discard in f2fs, if discard is
|
||||
enabled, f2fs will issue discard/TRIM commands when a
|
||||
segment is cleaned.
|
||||
no_heap Disable heap-style segment allocation which finds free
|
||||
segments for data from the beginning of main area, while
|
||||
for node from the end of main area.
|
||||
heap/no_heap Deprecated.
|
||||
nouser_xattr Disable Extended User Attributes. Note: xattr is enabled
|
||||
by default if CONFIG_F2FS_FS_XATTR is selected.
|
||||
noacl Disable POSIX Access Control List. Note: acl is enabled
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -147,6 +147,7 @@
|
||||
dma_map_sg_attrs
|
||||
dma_set_coherent_mask
|
||||
dma_set_mask
|
||||
dma_sync_single_for_device
|
||||
dma_unmap_page_attrs
|
||||
dma_unmap_sg_attrs
|
||||
do_trace_netlink_extack
|
||||
@@ -188,6 +189,7 @@
|
||||
get_net_ns_by_fd
|
||||
get_net_ns_by_pid
|
||||
get_random_bytes
|
||||
get_zeroed_page
|
||||
gic_nonsecure_priorities
|
||||
gpiochip_add_data_with_key
|
||||
gpiochip_find
|
||||
@@ -415,6 +417,7 @@
|
||||
phy_start
|
||||
phy_stop
|
||||
phy_trigger_machine
|
||||
platform_device_put
|
||||
platform_device_register_full
|
||||
platform_device_unregister
|
||||
__platform_driver_probe
|
||||
@@ -783,7 +786,6 @@
|
||||
dma_sync_single_for_cpu
|
||||
of_get_ethdev_address
|
||||
of_platform_populate
|
||||
platform_get_irq_byname
|
||||
__skb_pad
|
||||
synchronize_irq
|
||||
|
||||
@@ -863,6 +865,23 @@
|
||||
of_find_net_device_by_node
|
||||
of_find_node_by_phandle
|
||||
|
||||
# required by brcmstb-iommu.ko
|
||||
devm_get_free_pages
|
||||
generic_device_group
|
||||
iommu_device_register
|
||||
iommu_device_sysfs_add
|
||||
iommu_device_sysfs_remove
|
||||
iommu_device_unlink
|
||||
iommu_device_unregister
|
||||
iommu_fwspec_init
|
||||
iommu_group_alloc
|
||||
iommu_group_put
|
||||
iommu_group_ref_get
|
||||
iommu_group_set_name
|
||||
pci_device_group
|
||||
pci_find_host_bridge
|
||||
platform_get_irq_byname
|
||||
|
||||
# required by brcmstb-proc-info.ko
|
||||
find_get_pid
|
||||
generic_file_open
|
||||
@@ -1075,7 +1094,6 @@
|
||||
platform_device_add_data
|
||||
platform_device_add_resources
|
||||
platform_device_alloc
|
||||
platform_device_put
|
||||
softnet_data
|
||||
|
||||
# required by gpio-brcmstb.ko
|
||||
@@ -1594,7 +1612,6 @@
|
||||
dma_get_slave_caps
|
||||
dma_release_channel
|
||||
dma_request_chan
|
||||
dma_sync_single_for_device
|
||||
empty_zero_page
|
||||
gpiochip_request_own_desc
|
||||
__of_get_address
|
||||
@@ -1689,7 +1706,6 @@
|
||||
device_find_child_by_name
|
||||
device_for_each_child
|
||||
_find_first_zero_bit
|
||||
get_zeroed_page
|
||||
rtnl_configure_link
|
||||
rtnl_create_link
|
||||
|
||||
@@ -1751,3 +1767,11 @@
|
||||
# required by bstm.ko
|
||||
phys_mem_access_prot
|
||||
generic_access_phys
|
||||
|
||||
# required by bcm_astra.ko
|
||||
strnlen_user
|
||||
tty_buffer_set_limit
|
||||
tty_buffer_request_room
|
||||
|
||||
# required by bcm_athena.ko
|
||||
__read_overflow2_field
|
||||
|
||||
@@ -1145,6 +1145,8 @@
|
||||
geni_se_rx_dma_unprep
|
||||
geni_se_tx_dma_prep
|
||||
geni_se_tx_dma_unprep
|
||||
geni_se_rx_init_dma
|
||||
geni_se_tx_init_dma
|
||||
i2c_get_dma_safe_msg_buf
|
||||
i2c_put_dma_safe_msg_buf
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
__tracepoint_android_vh_modify_scan_control
|
||||
__tracepoint_android_vh_should_continue_reclaim
|
||||
__tracepoint_android_vh_tune_fault_around_bytes
|
||||
__tracepoint_android_vh_should_memcg_bypass
|
||||
__traceiter_android_vh_get_page_wmark
|
||||
__traceiter_android_vh_page_add_new_anon_rmap
|
||||
__traceiter_android_vh_do_shrink_slab
|
||||
@@ -25,6 +26,7 @@
|
||||
__traceiter_android_vh_modify_scan_control
|
||||
__traceiter_android_vh_should_continue_reclaim
|
||||
__traceiter_android_vh_tune_fault_around_bytes
|
||||
__traceiter_android_vh_should_memcg_bypass
|
||||
binder_alloc_copy_from_buffer
|
||||
kfree
|
||||
__kmalloc
|
||||
@@ -46,3 +48,7 @@
|
||||
udp4_lib_lookup
|
||||
udp6_lib_lookup
|
||||
next_arg
|
||||
__tracepoint_android_vh_dc_send_copy
|
||||
__traceiter_android_vh_dc_send_copy
|
||||
__tracepoint_android_vh_dc_receive
|
||||
__traceiter_android_vh_dc_receive
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
alarm_start_relative
|
||||
alarm_try_to_cancel
|
||||
alloc_chrdev_region
|
||||
alloc_contig_range
|
||||
alloc_etherdev_mqs
|
||||
alloc_io_pgtable_ops
|
||||
alloc_netdev_mqs
|
||||
@@ -31,6 +32,8 @@
|
||||
android_rvh_probe_register
|
||||
anon_inode_getfd
|
||||
anon_inode_getfile
|
||||
arc4_crypt
|
||||
arc4_setkey
|
||||
__arch_clear_user
|
||||
__arch_copy_from_user
|
||||
__arch_copy_to_user
|
||||
@@ -593,6 +596,7 @@
|
||||
dev_pm_opp_put_opp_table
|
||||
dev_pm_opp_register_notifier
|
||||
dev_pm_opp_remove_all_dynamic
|
||||
dev_pm_opp_remove_table
|
||||
dev_pm_opp_set_config
|
||||
dev_pm_opp_unregister_notifier
|
||||
dev_pm_qos_add_notifier
|
||||
@@ -964,6 +968,7 @@
|
||||
frame_vector_destroy
|
||||
frame_vector_to_pages
|
||||
frame_vector_to_pfns
|
||||
free_contig_range
|
||||
free_io_pgtable_ops
|
||||
free_irq
|
||||
free_netdev
|
||||
|
||||
@@ -1879,6 +1879,7 @@
|
||||
lowpan_register_netdevice
|
||||
lowpan_unregister_netdev
|
||||
lowpan_unregister_netdevice
|
||||
lru_gen_caps
|
||||
mac_pton
|
||||
mas_find
|
||||
match_string
|
||||
@@ -2292,12 +2293,14 @@
|
||||
pcie_capability_clear_and_set_word
|
||||
pcie_capability_read_dword
|
||||
pcie_capability_read_word
|
||||
pci_ecam_map_bus
|
||||
pci_enable_device
|
||||
pci_enable_pcie_error_reporting
|
||||
pci_find_ext_capability
|
||||
pci_free_irq_vectors
|
||||
pci_get_device
|
||||
pci_get_domain_bus_and_slot
|
||||
pci_host_common_probe
|
||||
pci_host_probe
|
||||
pci_iomap
|
||||
pci_iounmap
|
||||
@@ -2488,6 +2491,7 @@
|
||||
power_supply_get_property
|
||||
power_supply_put
|
||||
power_supply_register
|
||||
power_supply_register_no_ws
|
||||
power_supply_reg_notifier
|
||||
power_supply_set_property
|
||||
power_supply_unregister
|
||||
@@ -3766,6 +3770,7 @@
|
||||
__uio_register_device
|
||||
uio_unregister_device
|
||||
unlock_page
|
||||
unpack_shadow
|
||||
unregister_blkdev
|
||||
unregister_candev
|
||||
__unregister_chrdev
|
||||
|
||||
@@ -2105,6 +2105,7 @@
|
||||
# required by pcie-dw-rockchip.ko
|
||||
device_release_driver
|
||||
dw_pcie_find_ext_capability
|
||||
dw_pcie_host_deinit
|
||||
dw_pcie_host_init
|
||||
dw_pcie_link_up
|
||||
dw_pcie_read
|
||||
@@ -2121,6 +2122,7 @@
|
||||
devm_pci_remap_cfg_resource
|
||||
jiffies_to_usecs
|
||||
of_pci_get_max_link_speed
|
||||
of_pci_get_slot_power_limit
|
||||
pci_host_probe
|
||||
pci_remove_root_bus
|
||||
pci_stop_root_bus
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
__traceiter_android_vh_delayacct_compact_end
|
||||
__traceiter_android_vh_delayacct_wpcopy_start
|
||||
__traceiter_android_vh_delayacct_wpcopy_end
|
||||
__traceiter_android_vh_exit_mm
|
||||
__tracepoint_android_rvh_delayacct_init
|
||||
__tracepoint_android_rvh_delayacct_tsk_init
|
||||
__tracepoint_android_rvh_delayacct_tsk_free
|
||||
@@ -35,3 +36,37 @@
|
||||
__tracepoint_android_vh_delayacct_compact_end
|
||||
__tracepoint_android_vh_delayacct_wpcopy_start
|
||||
__tracepoint_android_vh_delayacct_wpcopy_end
|
||||
__tracepoint_android_vh_exit_mm
|
||||
|
||||
# required by tran_io.ko
|
||||
__percpu_counter_init
|
||||
_atomic_dec_and_lock_irqsave
|
||||
add_disk_randomness
|
||||
bio_uninit
|
||||
blk_mq_alloc_disk_for_queue
|
||||
block_read_full_folio
|
||||
bsg_register_queue
|
||||
bsg_unregister_queue
|
||||
buffer_check_dirty_writeback
|
||||
call_rcu_hurry
|
||||
clock_t_to_jiffies
|
||||
devcgroup_check_permission
|
||||
filemap_fdatawait_keep_errors
|
||||
folio_mark_dirty
|
||||
folio_unlock
|
||||
invalidate_bh_lrus
|
||||
io_cgrp_subsys
|
||||
mempool_exit
|
||||
mempool_init
|
||||
percpu_counter_destroy
|
||||
percpu_ref_exit
|
||||
percpu_ref_init
|
||||
percpu_ref_is_zero
|
||||
percpu_ref_kill_and_confirm
|
||||
percpu_ref_resurrect
|
||||
percpu_ref_switch_to_atomic_sync
|
||||
percpu_ref_switch_to_percpu
|
||||
read_cache_folio
|
||||
register_tracepoint_module_notifier
|
||||
scsi_register_driver
|
||||
trace_seq_puts
|
||||
|
||||
@@ -1367,6 +1367,12 @@
|
||||
snd_pcm_set_ops
|
||||
wait_for_completion_interruptible_timeout
|
||||
|
||||
# required by virtio-audio
|
||||
snd_device_new
|
||||
snd_pcm_hw_limit_rates
|
||||
_snd_pcm_stream_lock_irqsave
|
||||
snd_pcm_stream_unlock_irqrestore
|
||||
|
||||
# required by vkms.ko
|
||||
__devm_drm_dev_alloc
|
||||
devres_open_group
|
||||
|
||||
@@ -116,6 +116,10 @@
|
||||
__tracepoint_android_rvh_check_preempt_tick
|
||||
__tracepoint_android_rvh_dequeue_entity
|
||||
__tracepoint_android_rvh_enqueue_entity
|
||||
__traceiter_android_vh_alloc_flags_cma_adjust
|
||||
__traceiter_android_vh_rmqueue_cma_fallback
|
||||
__tracepoint_android_vh_alloc_flags_cma_adjust
|
||||
__tracepoint_android_vh_rmqueue_cma_fallback
|
||||
console_printk
|
||||
__traceiter_android_vh_binder_transaction_init
|
||||
__tracepoint_android_vh_binder_transaction_init
|
||||
|
||||
@@ -411,9 +411,9 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static __always_inline void do_ffa_mem_xfer(const u64 func_id,
|
||||
struct arm_smccc_res *res,
|
||||
struct kvm_cpu_context *ctxt)
|
||||
static void __do_ffa_mem_xfer(const u64 func_id,
|
||||
struct arm_smccc_res *res,
|
||||
struct kvm_cpu_context *ctxt)
|
||||
{
|
||||
DECLARE_REG(u32, len, ctxt, 1);
|
||||
DECLARE_REG(u32, fraglen, ctxt, 2);
|
||||
@@ -424,9 +424,6 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
|
||||
u32 offset, nr_ranges;
|
||||
int ret = 0;
|
||||
|
||||
BUILD_BUG_ON(func_id != FFA_FN64_MEM_SHARE &&
|
||||
func_id != FFA_FN64_MEM_LEND);
|
||||
|
||||
if (addr_mbz || npages_mbz || fraglen > len ||
|
||||
fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
|
||||
ret = FFA_RET_INVALID_PARAMETERS;
|
||||
@@ -445,6 +442,11 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (len > ffa_desc_buf.len) {
|
||||
ret = FFA_RET_NO_MEMORY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
buf = hyp_buffers.tx;
|
||||
memcpy(buf, host_buffers.tx, fraglen);
|
||||
|
||||
@@ -494,6 +496,13 @@ err_unshare:
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
#define do_ffa_mem_xfer(fid, res, ctxt) \
|
||||
do { \
|
||||
BUILD_BUG_ON((fid) != FFA_FN64_MEM_SHARE && \
|
||||
(fid) != FFA_FN64_MEM_LEND); \
|
||||
__do_ffa_mem_xfer((fid), (res), (ctxt)); \
|
||||
} while (0);
|
||||
|
||||
static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
|
||||
struct kvm_cpu_context *ctxt)
|
||||
{
|
||||
|
||||
@@ -576,9 +576,6 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
hyp_entry_exit_handler_fn ec_handler;
|
||||
u8 esr_ec;
|
||||
|
||||
if (READ_ONCE(hyp_vcpu->power_state) == PSCI_0_2_AFFINITY_LEVEL_ON_PENDING)
|
||||
pkvm_reset_vcpu(hyp_vcpu);
|
||||
|
||||
/*
|
||||
* If we deal with a non-protected guest and the state is potentially
|
||||
* dirty (from a host perspective), copy the state back into the hyp
|
||||
@@ -823,19 +820,29 @@ static struct kvm_vcpu *__get_host_hyp_vcpus(struct kvm_vcpu *arg,
|
||||
__get_host_hyp_vcpus(__vcpu, hyp_vcpup); \
|
||||
})
|
||||
|
||||
static bool is_vcpu_runnable(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
{
|
||||
return (!pkvm_hyp_vcpu_is_protected(hyp_vcpu) ||
|
||||
hyp_vcpu->power_state == PSCI_0_2_AFFINITY_LEVEL_ON);
|
||||
}
|
||||
|
||||
static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
struct pkvm_hyp_vcpu *hyp_vcpu;
|
||||
struct kvm_vcpu *host_vcpu;
|
||||
int ret;
|
||||
int ret = ARM_EXCEPTION_IL;
|
||||
|
||||
host_vcpu = get_host_hyp_vcpus(host_ctxt, 1, &hyp_vcpu);
|
||||
if (!host_vcpu) {
|
||||
ret = -EINVAL;
|
||||
if (!host_vcpu)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(hyp_vcpu)) {
|
||||
if (hyp_vcpu->power_state == PSCI_0_2_AFFINITY_LEVEL_ON_PENDING)
|
||||
pkvm_reset_vcpu(hyp_vcpu);
|
||||
|
||||
if (unlikely(!is_vcpu_runnable(hyp_vcpu)))
|
||||
goto out;
|
||||
|
||||
flush_hyp_vcpu(hyp_vcpu);
|
||||
|
||||
ret = __kvm_vcpu_run(&hyp_vcpu->vcpu);
|
||||
|
||||
@@ -981,9 +981,7 @@ int topup_hyp_memcache(struct kvm_vcpu *vcpu)
|
||||
err = __topup_hyp_memcache(mc, kvm_mmu_cache_min_pages(vcpu->kvm),
|
||||
hyp_mc_alloc_fn,
|
||||
kvm_host_pa, NULL);
|
||||
if (!err)
|
||||
account_hyp_memcache(mc, prev_nr_pages, vcpu->kvm);
|
||||
|
||||
account_hyp_memcache(mc, prev_nr_pages, vcpu->kvm);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,6 +262,8 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
host_kvm->arch.pkvm.handle = handle;
|
||||
|
||||
total_sz = hyp_vm_sz + last_ran_sz + pgd_sz;
|
||||
atomic64_set(&host_kvm->stat.protected_hyp_mem, total_sz);
|
||||
kvm_account_pgtable_pages(pgd, pgd_sz >> PAGE_SHIFT);
|
||||
|
||||
/* Donate memory for the vcpus at hyp and initialize it. */
|
||||
hyp_vcpu_sz = PAGE_ALIGN(PKVM_HYP_VCPU_SIZE);
|
||||
@@ -280,18 +282,15 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
|
||||
goto destroy_vm;
|
||||
}
|
||||
|
||||
total_sz += hyp_vcpu_sz;
|
||||
|
||||
ret = kvm_call_hyp_nvhe(__pkvm_init_vcpu, handle, host_vcpu,
|
||||
hyp_vcpu);
|
||||
if (ret) {
|
||||
free_pages_exact(hyp_vcpu, hyp_vcpu_sz);
|
||||
goto destroy_vm;
|
||||
}
|
||||
}
|
||||
|
||||
atomic64_set(&host_kvm->stat.protected_hyp_mem, total_sz);
|
||||
kvm_account_pgtable_pages(pgd, pgd_sz >> PAGE_SHIFT);
|
||||
atomic64_add(hyp_vcpu_sz, &host_kvm->stat.protected_hyp_mem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -214,6 +214,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_shmem_get_folio);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_record_pcpu_rwsem_time_early);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_check_mmap_file);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_check_file_open);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_dc_send_copy);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_dc_receive);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_check_bpf_syscall);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_ignore_dmabuf_vmap_bounds);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_rproc_recovery);
|
||||
@@ -344,6 +346,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_ctl_dirty_rate);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_check_hibernation_swap);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_cpu_resume);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_hib_resume_bdev);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_flags_cma_adjust);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_rmqueue_cma_fallback);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_encrypt_page);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_init_aes_encrypt);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_skip_swap_map_write);
|
||||
@@ -425,6 +429,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_do_read_fault);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_queue_request_and_unlock);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_fuse_request_end);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_rwsem_read_trylock_failed);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_should_memcg_bypass);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_shmem_swapin_folio);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_wp_page);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_swap_page);
|
||||
|
||||
@@ -46,7 +46,7 @@ static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv, long timeout)
|
||||
|
||||
static LIST_HEAD(pending_fw_head);
|
||||
|
||||
void kill_pending_fw_fallback_reqs(bool only_kill_custom)
|
||||
void kill_pending_fw_fallback_reqs(bool kill_all)
|
||||
{
|
||||
struct fw_priv *fw_priv;
|
||||
struct fw_priv *next;
|
||||
@@ -54,9 +54,13 @@ void kill_pending_fw_fallback_reqs(bool only_kill_custom)
|
||||
mutex_lock(&fw_lock);
|
||||
list_for_each_entry_safe(fw_priv, next, &pending_fw_head,
|
||||
pending_list) {
|
||||
if (!fw_priv->need_uevent || !only_kill_custom)
|
||||
if (kill_all || !fw_priv->need_uevent)
|
||||
__fw_load_abort(fw_priv);
|
||||
}
|
||||
|
||||
if (kill_all)
|
||||
fw_load_abort_all = true;
|
||||
|
||||
mutex_unlock(&fw_lock);
|
||||
}
|
||||
|
||||
@@ -86,7 +90,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout)
|
||||
}
|
||||
|
||||
mutex_lock(&fw_lock);
|
||||
if (fw_state_is_aborted(fw_priv)) {
|
||||
if (fw_load_abort_all || fw_state_is_aborted(fw_priv)) {
|
||||
mutex_unlock(&fw_lock);
|
||||
retval = -EINTR;
|
||||
goto out;
|
||||
|
||||
@@ -13,7 +13,7 @@ int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
||||
struct device *device,
|
||||
u32 opt_flags,
|
||||
int ret);
|
||||
void kill_pending_fw_fallback_reqs(bool only_kill_custom);
|
||||
void kill_pending_fw_fallback_reqs(bool kill_all);
|
||||
|
||||
void fw_fallback_set_cache_timeout(void);
|
||||
void fw_fallback_set_default_timeout(void);
|
||||
@@ -28,7 +28,7 @@ static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { }
|
||||
static inline void kill_pending_fw_fallback_reqs(bool kill_all) { }
|
||||
static inline void fw_fallback_set_cache_timeout(void) { }
|
||||
static inline void fw_fallback_set_default_timeout(void) { }
|
||||
#endif /* CONFIG_FW_LOADER_USER_HELPER */
|
||||
|
||||
@@ -88,6 +88,7 @@ struct fw_priv {
|
||||
|
||||
extern struct mutex fw_lock;
|
||||
extern struct firmware_cache fw_cache;
|
||||
extern bool fw_load_abort_all;
|
||||
|
||||
static inline bool __fw_state_check(struct fw_priv *fw_priv,
|
||||
enum fw_status status)
|
||||
|
||||
@@ -93,6 +93,7 @@ static inline struct fw_priv *to_fw_priv(struct kref *ref)
|
||||
DEFINE_MUTEX(fw_lock);
|
||||
|
||||
struct firmware_cache fw_cache;
|
||||
bool fw_load_abort_all;
|
||||
|
||||
void fw_state_init(struct fw_priv *fw_priv)
|
||||
{
|
||||
@@ -1560,10 +1561,10 @@ static int fw_pm_notify(struct notifier_block *notify_block,
|
||||
case PM_SUSPEND_PREPARE:
|
||||
case PM_RESTORE_PREPARE:
|
||||
/*
|
||||
* kill pending fallback requests with a custom fallback
|
||||
* to avoid stalling suspend.
|
||||
* Here, kill pending fallback requests will only kill
|
||||
* non-uevent firmware request to avoid stalling suspend.
|
||||
*/
|
||||
kill_pending_fw_fallback_reqs(true);
|
||||
kill_pending_fw_fallback_reqs(false);
|
||||
device_cache_fw_images();
|
||||
break;
|
||||
|
||||
@@ -1648,7 +1649,7 @@ static int fw_shutdown_notify(struct notifier_block *unused1,
|
||||
* Kill all pending fallback requests to avoid both stalling shutdown,
|
||||
* and avoid a deadlock with the usermode_lock.
|
||||
*/
|
||||
kill_pending_fw_fallback_reqs(false);
|
||||
kill_pending_fw_fallback_reqs(true);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
@@ -22,12 +22,14 @@
|
||||
* @chan: Transmit/Receive mailbox channel
|
||||
* @cinfo: SCMI channel info
|
||||
* @shmem: Transmit/Receive shared memory area
|
||||
* @chan_lock: Lock that prevents multiple xfers from being queued
|
||||
*/
|
||||
struct scmi_mailbox {
|
||||
struct mbox_client cl;
|
||||
struct mbox_chan *chan;
|
||||
struct scmi_chan_info *cinfo;
|
||||
struct scmi_shared_mem __iomem *shmem;
|
||||
struct mutex chan_lock;
|
||||
};
|
||||
|
||||
#define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl)
|
||||
@@ -157,6 +159,7 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
||||
|
||||
cinfo->transport_info = smbox;
|
||||
smbox->cinfo = cinfo;
|
||||
mutex_init(&smbox->chan_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -184,13 +187,23 @@ static int mailbox_send_message(struct scmi_chan_info *cinfo,
|
||||
struct scmi_mailbox *smbox = cinfo->transport_info;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The mailbox layer has its own queue. However the mailbox queue confuses
|
||||
* the per message SCMI timeouts since the clock starts when the message is
|
||||
* submitted into the mailbox queue. So when multiple messages are queued up
|
||||
* the clock starts on all messages instead of only the one inflight.
|
||||
*/
|
||||
mutex_lock(&smbox->chan_lock);
|
||||
|
||||
ret = mbox_send_message(smbox->chan, xfer);
|
||||
|
||||
/* mbox_send_message returns non-negative value on success, so reset */
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&smbox->chan_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret,
|
||||
@@ -198,13 +211,10 @@ static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret,
|
||||
{
|
||||
struct scmi_mailbox *smbox = cinfo->transport_info;
|
||||
|
||||
/*
|
||||
* NOTE: we might prefer not to need the mailbox ticker to manage the
|
||||
* transfer queueing since the protocol layer queues things by itself.
|
||||
* Unfortunately, we have to kick the mailbox framework after we have
|
||||
* received our message.
|
||||
*/
|
||||
mbox_client_txdone(smbox->chan, ret);
|
||||
|
||||
/* Release channel */
|
||||
mutex_unlock(&smbox->chan_lock);
|
||||
}
|
||||
|
||||
static void mailbox_fetch_response(struct scmi_chan_info *cinfo,
|
||||
|
||||
@@ -101,9 +101,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
|
||||
return NULL;
|
||||
}
|
||||
|
||||
field = kzalloc((sizeof(struct hid_field) +
|
||||
usages * sizeof(struct hid_usage) +
|
||||
3 * usages * sizeof(unsigned int)), GFP_KERNEL);
|
||||
field = kvzalloc((sizeof(struct hid_field) +
|
||||
usages * sizeof(struct hid_usage) +
|
||||
3 * usages * sizeof(unsigned int)), GFP_KERNEL);
|
||||
if (!field)
|
||||
return NULL;
|
||||
|
||||
@@ -667,7 +667,7 @@ static void hid_free_report(struct hid_report *report)
|
||||
kfree(report->field_entries);
|
||||
|
||||
for (n = 0; n < report->maxfield; n++)
|
||||
kfree(report->field[n]);
|
||||
kvfree(report->field[n]);
|
||||
kfree(report);
|
||||
}
|
||||
|
||||
|
||||
@@ -586,7 +586,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
|
||||
{
|
||||
struct dma_slave_config config = {};
|
||||
struct gpi_i2c_config peripheral = {};
|
||||
int i, ret = 0, timeout;
|
||||
int i, ret = 0;
|
||||
unsigned long time_left;
|
||||
dma_addr_t tx_addr, rx_addr;
|
||||
void *tx_buf = NULL, *rx_buf = NULL;
|
||||
const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
|
||||
@@ -629,12 +630,9 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
|
||||
|
||||
dma_async_issue_pending(gi2c->tx_c);
|
||||
|
||||
timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!timeout) {
|
||||
dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n",
|
||||
gi2c->cur->flags, gi2c->cur->addr);
|
||||
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!time_left)
|
||||
gi2c->err = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (gi2c->err) {
|
||||
ret = gi2c->err;
|
||||
@@ -767,7 +765,6 @@ err_tx:
|
||||
static int geni_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c;
|
||||
struct resource *res;
|
||||
u32 proto, tx_depth, fifo_disable;
|
||||
int ret;
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -779,8 +776,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
gi2c->se.dev = dev;
|
||||
gi2c->se.wrapper = dev_get_drvdata(dev->parent);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
gi2c->se.base = devm_ioremap_resource(dev, res);
|
||||
gi2c->se.base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(gi2c->se.base))
|
||||
return PTR_ERR(gi2c->se.base);
|
||||
|
||||
@@ -821,15 +817,13 @@ static int geni_i2c_probe(struct platform_device *pdev)
|
||||
init_completion(&gi2c->done);
|
||||
spin_lock_init(&gi2c->lock);
|
||||
platform_set_drvdata(pdev, gi2c);
|
||||
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0,
|
||||
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN,
|
||||
dev_name(dev), gi2c);
|
||||
if (ret) {
|
||||
dev_err(dev, "Request_irq failed:%d: err:%d\n",
|
||||
gi2c->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
/* Disable the interrupt so that the system can enter low-power mode */
|
||||
disable_irq(gi2c->irq);
|
||||
i2c_set_adapdata(&gi2c->adap, gi2c);
|
||||
gi2c->adap.dev.parent = dev;
|
||||
gi2c->adap.dev.of_node = dev->of_node;
|
||||
@@ -942,14 +936,13 @@ err_dma:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int geni_i2c_remove(struct platform_device *pdev)
|
||||
static void geni_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&gi2c->adap);
|
||||
release_gpi_dma(gi2c);
|
||||
pm_runtime_disable(gi2c->se.dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void geni_i2c_shutdown(struct platform_device *pdev)
|
||||
@@ -990,21 +983,24 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(gi2c->core_clk);
|
||||
if (ret) {
|
||||
geni_icc_disable(&gi2c->se);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto out_icc_disable;
|
||||
|
||||
ret = geni_se_resources_on(&gi2c->se);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(gi2c->core_clk);
|
||||
geni_icc_disable(&gi2c->se);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto out_clk_disable;
|
||||
|
||||
enable_irq(gi2c->irq);
|
||||
gi2c->suspended = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
out_clk_disable:
|
||||
clk_disable_unprepare(gi2c->core_clk);
|
||||
out_icc_disable:
|
||||
geni_icc_disable(&gi2c->se);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
|
||||
@@ -1036,15 +1032,23 @@ static const struct dev_pm_ops geni_i2c_pm_ops = {
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct geni_i2c_desc i2c_master_hub = {
|
||||
.has_core_clk = true,
|
||||
.icc_ddr = NULL,
|
||||
.no_dma_support = true,
|
||||
.tx_fifo_depth = 16,
|
||||
};
|
||||
|
||||
static const struct of_device_id geni_i2c_dt_match[] = {
|
||||
{ .compatible = "qcom,geni-i2c" },
|
||||
{ .compatible = "qcom,geni-i2c-master-hub", .data = &i2c_master_hub },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
|
||||
|
||||
static struct platform_driver geni_i2c_driver = {
|
||||
.probe = geni_i2c_probe,
|
||||
.remove = geni_i2c_remove,
|
||||
.remove_new = geni_i2c_remove,
|
||||
.shutdown = geni_i2c_shutdown,
|
||||
.driver = {
|
||||
.name = "geni_i2c",
|
||||
|
||||
@@ -81,19 +81,31 @@
|
||||
*/
|
||||
|
||||
#define MAX_CLK_PERF_LEVEL 32
|
||||
#define NUM_AHB_CLKS 2
|
||||
#define MAX_CLKS 2
|
||||
|
||||
/**
|
||||
* struct geni_wrapper - Data structure to represent the QUP Wrapper Core
|
||||
* @dev: Device pointer of the QUP wrapper core
|
||||
* @base: Base address of this instance of QUP wrapper core
|
||||
* @ahb_clks: Handle to the primary & secondary AHB clocks
|
||||
* @clks: Handle to the primary & optional secondary AHB clocks
|
||||
* @num_clks: Count of clocks
|
||||
* @to_core: Core ICC path
|
||||
*/
|
||||
struct geni_wrapper {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk_bulk_data ahb_clks[NUM_AHB_CLKS];
|
||||
struct clk_bulk_data clks[MAX_CLKS];
|
||||
unsigned int num_clks;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct geni_se_desc - Data structure to represent the QUP Wrapper resources
|
||||
* @clks: Name of the primary & optional secondary AHB clocks
|
||||
* @num_clks: Count of clock names
|
||||
*/
|
||||
struct geni_se_desc {
|
||||
unsigned int num_clks;
|
||||
const char * const *clks;
|
||||
};
|
||||
|
||||
static const char * const icc_path_names[] = {"qup-core", "qup-config",
|
||||
@@ -269,27 +281,14 @@ static void geni_se_select_fifo_mode(struct geni_se *se)
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
/*
|
||||
* The RX path for the UART is asynchronous and so needs more
|
||||
* complex logic for enabling / disabling its interrupts.
|
||||
*
|
||||
* Specific notes:
|
||||
* - The done and TX-related interrupts are managed manually.
|
||||
* - We don't RX from the main sequencer (we use the secondary) so
|
||||
* we don't need the RX-related interrupts enabled in the main
|
||||
* sequencer for UART.
|
||||
*/
|
||||
/* UART driver manages enabling / disabling interrupts internally */
|
||||
if (proto != GENI_SE_UART) {
|
||||
/* Non-UART use only primary sequencer so dont bother about S_IRQ */
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
|
||||
val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val |= S_CMD_DONE_EN;
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
@@ -305,17 +304,14 @@ static void geni_se_select_dma_mode(struct geni_se *se)
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
/* UART driver manages enabling / disabling interrupts internally */
|
||||
if (proto != GENI_SE_UART) {
|
||||
/* Non-UART use only primary sequencer so dont bother about S_IRQ */
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
|
||||
val &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val &= ~S_CMD_DONE_EN;
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
@@ -332,10 +328,6 @@ static void geni_se_select_gpi_mode(struct geni_se *se)
|
||||
|
||||
writel(0, se->base + SE_IRQ_EN);
|
||||
|
||||
val = readl(se->base + SE_GENI_S_IRQ_EN);
|
||||
val &= ~S_CMD_DONE_EN;
|
||||
writel(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
|
||||
val = readl(se->base + SE_GENI_M_IRQ_EN);
|
||||
val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN |
|
||||
M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
|
||||
@@ -496,8 +488,7 @@ static void geni_se_clks_off(struct geni_se *se)
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
clk_disable_unprepare(se->clk);
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks),
|
||||
wrapper->ahb_clks);
|
||||
clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,15 +519,13 @@ static int geni_se_clks_on(struct geni_se *se)
|
||||
int ret;
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(wrapper->ahb_clks),
|
||||
wrapper->ahb_clks);
|
||||
ret = clk_bulk_prepare_enable(wrapper->num_clks, wrapper->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(se->clk);
|
||||
if (ret)
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks),
|
||||
wrapper->ahb_clks);
|
||||
clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -673,6 +662,30 @@ EXPORT_SYMBOL(geni_se_clk_freq_match);
|
||||
#define GENI_SE_DMA_EOT_EN BIT(1)
|
||||
#define GENI_SE_DMA_AHB_ERR_EN BIT(2)
|
||||
#define GENI_SE_DMA_EOT_BUF BIT(0)
|
||||
|
||||
/**
|
||||
* geni_se_tx_init_dma() - Initiate TX DMA transfer on the serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @iova: Mapped DMA address.
|
||||
* @len: Length of the TX buffer.
|
||||
*
|
||||
* This function is used to initiate DMA TX transfer.
|
||||
*/
|
||||
void geni_se_tx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = GENI_SE_DMA_DONE_EN;
|
||||
val |= GENI_SE_DMA_EOT_EN;
|
||||
val |= GENI_SE_DMA_AHB_ERR_EN;
|
||||
writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET);
|
||||
writel_relaxed(lower_32_bits(iova), se->base + SE_DMA_TX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(iova), se->base + SE_DMA_TX_PTR_H);
|
||||
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
|
||||
writel(len, se->base + SE_DMA_TX_LEN);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_tx_init_dma);
|
||||
|
||||
/**
|
||||
* geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
@@ -688,7 +701,6 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
u32 val;
|
||||
|
||||
if (!wrapper)
|
||||
return -EINVAL;
|
||||
@@ -697,18 +709,35 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
if (dma_mapping_error(wrapper->dev, *iova))
|
||||
return -EIO;
|
||||
|
||||
val = GENI_SE_DMA_DONE_EN;
|
||||
val |= GENI_SE_DMA_EOT_EN;
|
||||
val |= GENI_SE_DMA_AHB_ERR_EN;
|
||||
writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET);
|
||||
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
|
||||
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
|
||||
writel(len, se->base + SE_DMA_TX_LEN);
|
||||
geni_se_tx_init_dma(se, *iova, len);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_tx_dma_prep);
|
||||
|
||||
/**
|
||||
* geni_se_rx_init_dma() - Initiate RX DMA transfer on the serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @iova: Mapped DMA address.
|
||||
* @len: Length of the RX buffer.
|
||||
*
|
||||
* This function is used to initiate DMA RX transfer.
|
||||
*/
|
||||
void geni_se_rx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = GENI_SE_DMA_DONE_EN;
|
||||
val |= GENI_SE_DMA_EOT_EN;
|
||||
val |= GENI_SE_DMA_AHB_ERR_EN;
|
||||
writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET);
|
||||
writel_relaxed(lower_32_bits(iova), se->base + SE_DMA_RX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(iova), se->base + SE_DMA_RX_PTR_H);
|
||||
/* RX does not have EOT buffer type bit. So just reset RX_ATTR */
|
||||
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
|
||||
writel(len, se->base + SE_DMA_RX_LEN);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_rx_init_dma);
|
||||
|
||||
/**
|
||||
* geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
@@ -724,7 +753,6 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
u32 val;
|
||||
|
||||
if (!wrapper)
|
||||
return -EINVAL;
|
||||
@@ -733,15 +761,7 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
if (dma_mapping_error(wrapper->dev, *iova))
|
||||
return -EIO;
|
||||
|
||||
val = GENI_SE_DMA_DONE_EN;
|
||||
val |= GENI_SE_DMA_EOT_EN;
|
||||
val |= GENI_SE_DMA_AHB_ERR_EN;
|
||||
writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET);
|
||||
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_RX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
|
||||
/* RX does not have EOT buffer type bit. So just reset RX_ATTR */
|
||||
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
|
||||
writel(len, se->base + SE_DMA_RX_LEN);
|
||||
geni_se_rx_init_dma(se, *iova, len);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_rx_dma_prep);
|
||||
@@ -887,11 +907,33 @@ static int geni_se_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(wrapper->base);
|
||||
|
||||
if (!has_acpi_companion(&pdev->dev)) {
|
||||
wrapper->ahb_clks[0].id = "m-ahb";
|
||||
wrapper->ahb_clks[1].id = "s-ahb";
|
||||
ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
|
||||
const struct geni_se_desc *desc;
|
||||
int i;
|
||||
|
||||
desc = device_get_match_data(&pdev->dev);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
wrapper->num_clks = min_t(unsigned int, desc->num_clks, MAX_CLKS);
|
||||
|
||||
for (i = 0; i < wrapper->num_clks; ++i)
|
||||
wrapper->clks[i].id = desc->clks[i];
|
||||
|
||||
ret = of_count_phandle_with_args(dev->of_node, "clocks", "#clock-cells");
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "invalid clocks property at %pOF\n", dev->of_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < wrapper->num_clks) {
|
||||
dev_err(dev, "invalid clocks count at %pOF, expected %d entries\n",
|
||||
dev->of_node, wrapper->num_clks);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_clk_bulk_get(dev, wrapper->num_clks, wrapper->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "Err getting AHB clks %d\n", ret);
|
||||
dev_err(dev, "Err getting clks %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -901,8 +943,18 @@ static int geni_se_probe(struct platform_device *pdev)
|
||||
return devm_of_platform_populate(dev);
|
||||
}
|
||||
|
||||
static const char * const qup_clks[] = {
|
||||
"m-ahb",
|
||||
"s-ahb",
|
||||
};
|
||||
|
||||
static const struct geni_se_desc qup_desc = {
|
||||
.clks = qup_clks,
|
||||
.num_clks = ARRAY_SIZE(qup_clks),
|
||||
};
|
||||
|
||||
static const struct of_device_id geni_se_dt_match[] = {
|
||||
{ .compatible = "qcom,geni-se-qup", },
|
||||
{ .compatible = "qcom,geni-se-qup", .data = &qup_desc },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, geni_se_dt_match);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/soc/qcom/geni-se.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spinlock.h>
|
||||
@@ -52,6 +53,9 @@
|
||||
#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10)
|
||||
#define SPI_CS_CLK_DELAY_SHFT 10
|
||||
|
||||
#define SE_SPI_SLAVE_EN (0x2BC)
|
||||
#define SPI_SLAVE_EN BIT(0)
|
||||
|
||||
/* M_CMD OP codes for SPI */
|
||||
#define SPI_TX_ONLY 1
|
||||
#define SPI_RX_ONLY 2
|
||||
@@ -87,6 +91,8 @@ struct spi_geni_master {
|
||||
struct completion cs_done;
|
||||
struct completion cancel_done;
|
||||
struct completion abort_done;
|
||||
struct completion tx_reset_done;
|
||||
struct completion rx_reset_done;
|
||||
unsigned int oversampling;
|
||||
spinlock_t lock;
|
||||
int irq;
|
||||
@@ -97,6 +103,16 @@ struct spi_geni_master {
|
||||
int cur_xfer_mode;
|
||||
};
|
||||
|
||||
static void spi_slv_setup(struct spi_geni_master *mas)
|
||||
{
|
||||
struct geni_se *se = &mas->se;
|
||||
|
||||
writel(SPI_SLAVE_EN, se->base + SE_SPI_SLAVE_EN);
|
||||
writel(GENI_IO_MUX_0_EN, se->base + GENI_OUTPUT_CTRL);
|
||||
writel(START_TRIGGER, se->base + SE_GENI_CFG_SEQ_START);
|
||||
dev_dbg(mas->dev, "spi slave setup done\n");
|
||||
}
|
||||
|
||||
static int get_spi_clk_cfg(unsigned int speed_hz,
|
||||
struct spi_geni_master *mas,
|
||||
unsigned int *clk_idx,
|
||||
@@ -129,23 +145,37 @@ static int get_spi_clk_cfg(unsigned int speed_hz,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_fifo_timeout(struct spi_master *spi,
|
||||
static void handle_se_timeout(struct spi_master *spi,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
unsigned long time_left;
|
||||
struct geni_se *se = &mas->se;
|
||||
const struct spi_transfer *xfer;
|
||||
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->cancel_done);
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO)
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
|
||||
xfer = mas->cur_xfer;
|
||||
mas->cur_xfer = NULL;
|
||||
|
||||
if (spi->slave) {
|
||||
/*
|
||||
* skip CMD Cancel sequnece since spi slave
|
||||
* doesn`t support CMD Cancel sequnece
|
||||
*/
|
||||
spin_unlock_irq(&mas->lock);
|
||||
goto reset_if_dma;
|
||||
}
|
||||
|
||||
reinit_completion(&mas->cancel_done);
|
||||
geni_se_cancel_m_cmd(se);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
|
||||
time_left = wait_for_completion_timeout(&mas->cancel_done, HZ);
|
||||
if (time_left)
|
||||
return;
|
||||
goto reset_if_dma;
|
||||
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->abort_done);
|
||||
@@ -162,6 +192,37 @@ static void handle_fifo_timeout(struct spi_master *spi,
|
||||
*/
|
||||
mas->abort_failed = true;
|
||||
}
|
||||
|
||||
reset_if_dma:
|
||||
if (mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
if (xfer) {
|
||||
if (xfer->tx_buf) {
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->tx_reset_done);
|
||||
writel(1, se->base + SE_DMA_TX_FSM_RST);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
time_left = wait_for_completion_timeout(&mas->tx_reset_done, HZ);
|
||||
if (!time_left)
|
||||
dev_err(mas->dev, "DMA TX RESET failed\n");
|
||||
}
|
||||
if (xfer->rx_buf) {
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->rx_reset_done);
|
||||
writel(1, se->base + SE_DMA_RX_FSM_RST);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
time_left = wait_for_completion_timeout(&mas->rx_reset_done, HZ);
|
||||
if (!time_left)
|
||||
dev_err(mas->dev, "DMA RX RESET failed\n");
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This can happen if a timeout happened and we had to wait
|
||||
* for lock in this function because isr was holding the lock
|
||||
* and handling transfer completion at that time.
|
||||
*/
|
||||
dev_warn(mas->dev, "Cancel/Abort on completed SPI transfer\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg)
|
||||
@@ -178,7 +239,8 @@ static void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg)
|
||||
|
||||
switch (mas->cur_xfer_mode) {
|
||||
case GENI_SE_FIFO:
|
||||
handle_fifo_timeout(spi, msg);
|
||||
case GENI_SE_DMA:
|
||||
handle_se_timeout(spi, msg);
|
||||
break;
|
||||
case GENI_GPI_DMA:
|
||||
handle_gpi_timeout(spi, msg);
|
||||
@@ -250,6 +312,10 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
||||
}
|
||||
|
||||
mas->cs_flag = set_flag;
|
||||
/* set xfer_mode to FIFO to complete cs_done in isr */
|
||||
mas->cur_xfer_mode = GENI_SE_FIFO;
|
||||
geni_se_select_mode(se, mas->cur_xfer_mode);
|
||||
|
||||
reinit_completion(&mas->cs_done);
|
||||
if (set_flag)
|
||||
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
|
||||
@@ -260,7 +326,7 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
||||
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
|
||||
if (!time_left) {
|
||||
dev_warn(mas->dev, "Timeout setting chip select\n");
|
||||
handle_fifo_timeout(spi, NULL);
|
||||
handle_se_timeout(spi, NULL);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -477,13 +543,40 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32 get_xfer_len_in_words(struct spi_transfer *xfer,
|
||||
struct spi_geni_master *mas)
|
||||
{
|
||||
u32 len;
|
||||
|
||||
if (!(mas->cur_bits_per_word % MIN_WORD_LEN))
|
||||
len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word;
|
||||
else
|
||||
len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1);
|
||||
len &= TRANS_LEN_MSK;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool geni_can_dma(struct spi_controller *ctlr,
|
||||
struct spi_device *slv, struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
|
||||
u32 len, fifo_size;
|
||||
|
||||
/* check if dma is supported */
|
||||
return mas->cur_xfer_mode != GENI_SE_FIFO;
|
||||
if (mas->cur_xfer_mode == GENI_GPI_DMA)
|
||||
return true;
|
||||
|
||||
/* Set SE DMA mode for SPI slave. */
|
||||
if (ctlr->slave)
|
||||
return true;
|
||||
|
||||
len = get_xfer_len_in_words(xfer, mas);
|
||||
fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
|
||||
|
||||
if (len > fifo_size)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int spi_geni_prepare_message(struct spi_master *spi,
|
||||
@@ -494,6 +587,7 @@ static int spi_geni_prepare_message(struct spi_master *spi,
|
||||
|
||||
switch (mas->cur_xfer_mode) {
|
||||
case GENI_SE_FIFO:
|
||||
case GENI_SE_DMA:
|
||||
if (spi_geni_is_abort_still_pending(mas))
|
||||
return -EBUSY;
|
||||
ret = setup_fifo_params(spi_msg->spi, spi);
|
||||
@@ -553,6 +647,7 @@ static void spi_geni_release_dma_chan(struct spi_geni_master *mas)
|
||||
|
||||
static int spi_geni_init(struct spi_geni_master *mas)
|
||||
{
|
||||
struct spi_master *spi = dev_get_drvdata(mas->dev);
|
||||
struct geni_se *se = &mas->se;
|
||||
unsigned int proto, major, minor, ver;
|
||||
u32 spi_tx_cfg, fifo_disable;
|
||||
@@ -561,7 +656,14 @@ static int spi_geni_init(struct spi_geni_master *mas)
|
||||
pm_runtime_get_sync(mas->dev);
|
||||
|
||||
proto = geni_se_read_proto(se);
|
||||
if (proto != GENI_SE_SPI) {
|
||||
|
||||
if (spi->slave) {
|
||||
if (proto != GENI_SE_SPI_SLAVE) {
|
||||
dev_err(mas->dev, "Invalid proto %d\n", proto);
|
||||
goto out_pm;
|
||||
}
|
||||
spi_slv_setup(mas);
|
||||
} else if (proto != GENI_SE_SPI) {
|
||||
dev_err(mas->dev, "Invalid proto %d\n", proto);
|
||||
goto out_pm;
|
||||
}
|
||||
@@ -599,7 +701,7 @@ static int spi_geni_init(struct spi_geni_master *mas)
|
||||
goto out_pm;
|
||||
}
|
||||
/*
|
||||
* in case of failure to get dma channel, we can still do the
|
||||
* in case of failure to get gpi dma channel, we can still do the
|
||||
* FIFO mode, so fallthrough
|
||||
*/
|
||||
dev_warn(mas->dev, "FIFO mode disabled, but couldn't get DMA, fall back to FIFO mode\n");
|
||||
@@ -613,9 +715,11 @@ static int spi_geni_init(struct spi_geni_master *mas)
|
||||
}
|
||||
|
||||
/* We always control CS manually */
|
||||
spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
|
||||
spi_tx_cfg &= ~CS_TOGGLE;
|
||||
writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
|
||||
if (!spi->slave) {
|
||||
spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
|
||||
spi_tx_cfg &= ~CS_TOGGLE;
|
||||
writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
|
||||
}
|
||||
|
||||
out_pm:
|
||||
pm_runtime_put(mas->dev);
|
||||
@@ -718,7 +822,7 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
|
||||
mas->rx_rem_bytes -= rx_bytes;
|
||||
}
|
||||
|
||||
static void setup_fifo_xfer(struct spi_transfer *xfer,
|
||||
static int setup_se_xfer(struct spi_transfer *xfer,
|
||||
struct spi_geni_master *mas,
|
||||
u16 mode, struct spi_master *spi)
|
||||
{
|
||||
@@ -750,16 +854,12 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
|
||||
/* Speed and bits per word can be overridden per transfer */
|
||||
ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz);
|
||||
if (ret)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
mas->tx_rem_bytes = 0;
|
||||
mas->rx_rem_bytes = 0;
|
||||
|
||||
if (!(mas->cur_bits_per_word % MIN_WORD_LEN))
|
||||
len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word;
|
||||
else
|
||||
len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1);
|
||||
len &= TRANS_LEN_MSK;
|
||||
len = get_xfer_len_in_words(xfer, mas);
|
||||
|
||||
mas->cur_xfer = xfer;
|
||||
if (xfer->tx_buf) {
|
||||
@@ -774,17 +874,43 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
|
||||
mas->rx_rem_bytes = xfer->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select DMA mode if sgt are present; and with only 1 entry
|
||||
* This is not a serious limitation because the xfer buffers are
|
||||
* expected to fit into in 1 entry almost always, and if any
|
||||
* doesn't for any reason we fall back to FIFO mode anyway
|
||||
*/
|
||||
if (!xfer->tx_sg.nents && !xfer->rx_sg.nents)
|
||||
mas->cur_xfer_mode = GENI_SE_FIFO;
|
||||
else if (xfer->tx_sg.nents > 1 || xfer->rx_sg.nents > 1) {
|
||||
dev_warn_once(mas->dev, "Doing FIFO, cannot handle tx_nents-%d, rx_nents-%d\n",
|
||||
xfer->tx_sg.nents, xfer->rx_sg.nents);
|
||||
mas->cur_xfer_mode = GENI_SE_FIFO;
|
||||
} else
|
||||
mas->cur_xfer_mode = GENI_SE_DMA;
|
||||
geni_se_select_mode(se, mas->cur_xfer_mode);
|
||||
|
||||
/*
|
||||
* Lock around right before we start the transfer since our
|
||||
* interrupt could come in at any time now.
|
||||
*/
|
||||
spin_lock_irq(&mas->lock);
|
||||
geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION);
|
||||
if (m_cmd & SPI_TX_ONLY) {
|
||||
|
||||
if (mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
if (m_cmd & SPI_RX_ONLY)
|
||||
geni_se_rx_init_dma(se, sg_dma_address(xfer->rx_sg.sgl),
|
||||
sg_dma_len(xfer->rx_sg.sgl));
|
||||
if (m_cmd & SPI_TX_ONLY)
|
||||
geni_se_tx_init_dma(se, sg_dma_address(xfer->tx_sg.sgl),
|
||||
sg_dma_len(xfer->tx_sg.sgl));
|
||||
} else if (m_cmd & SPI_TX_ONLY) {
|
||||
if (geni_spi_handle_tx(mas))
|
||||
writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&mas->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_geni_transfer_one(struct spi_master *spi,
|
||||
@@ -792,6 +918,7 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
int ret;
|
||||
|
||||
if (spi_geni_is_abort_still_pending(mas))
|
||||
return -EBUSY;
|
||||
@@ -800,9 +927,12 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
||||
if (!xfer->len)
|
||||
return 0;
|
||||
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO) {
|
||||
setup_fifo_xfer(xfer, mas, slv->mode, spi);
|
||||
return 1;
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO || mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
ret = setup_se_xfer(xfer, mas, slv->mode, spi);
|
||||
/* SPI framework expects +ve ret code to wait for transfer complete */
|
||||
if (!ret)
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
return setup_gsi_xfer(xfer, mas, slv, spi);
|
||||
}
|
||||
@@ -825,39 +955,62 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
|
||||
|
||||
spin_lock(&mas->lock);
|
||||
|
||||
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
|
||||
geni_spi_handle_rx(mas);
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO) {
|
||||
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
|
||||
geni_spi_handle_rx(mas);
|
||||
|
||||
if (m_irq & M_TX_FIFO_WATERMARK_EN)
|
||||
geni_spi_handle_tx(mas);
|
||||
if (m_irq & M_TX_FIFO_WATERMARK_EN)
|
||||
geni_spi_handle_tx(mas);
|
||||
|
||||
if (m_irq & M_CMD_DONE_EN) {
|
||||
if (mas->cur_xfer) {
|
||||
if (m_irq & M_CMD_DONE_EN) {
|
||||
if (mas->cur_xfer) {
|
||||
spi_finalize_current_transfer(spi);
|
||||
mas->cur_xfer = NULL;
|
||||
/*
|
||||
* If this happens, then a CMD_DONE came before all the
|
||||
* Tx buffer bytes were sent out. This is unusual, log
|
||||
* this condition and disable the WM interrupt to
|
||||
* prevent the system from stalling due an interrupt
|
||||
* storm.
|
||||
*
|
||||
* If this happens when all Rx bytes haven't been
|
||||
* received, log the condition. The only known time
|
||||
* this can happen is if bits_per_word != 8 and some
|
||||
* registers that expect xfer lengths in num spi_words
|
||||
* weren't written correctly.
|
||||
*/
|
||||
if (mas->tx_rem_bytes) {
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
|
||||
mas->tx_rem_bytes, mas->cur_bits_per_word);
|
||||
}
|
||||
if (mas->rx_rem_bytes)
|
||||
dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
|
||||
mas->rx_rem_bytes, mas->cur_bits_per_word);
|
||||
} else {
|
||||
complete(&mas->cs_done);
|
||||
}
|
||||
}
|
||||
} else if (mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
const struct spi_transfer *xfer = mas->cur_xfer;
|
||||
u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
|
||||
u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
|
||||
|
||||
if (dma_tx_status)
|
||||
writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
if (dma_rx_status)
|
||||
writel(dma_rx_status, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
if (dma_tx_status & TX_DMA_DONE)
|
||||
mas->tx_rem_bytes = 0;
|
||||
if (dma_rx_status & RX_DMA_DONE)
|
||||
mas->rx_rem_bytes = 0;
|
||||
if (dma_tx_status & TX_RESET_DONE)
|
||||
complete(&mas->tx_reset_done);
|
||||
if (dma_rx_status & RX_RESET_DONE)
|
||||
complete(&mas->rx_reset_done);
|
||||
if (!mas->tx_rem_bytes && !mas->rx_rem_bytes && xfer) {
|
||||
spi_finalize_current_transfer(spi);
|
||||
mas->cur_xfer = NULL;
|
||||
/*
|
||||
* If this happens, then a CMD_DONE came before all the
|
||||
* Tx buffer bytes were sent out. This is unusual, log
|
||||
* this condition and disable the WM interrupt to
|
||||
* prevent the system from stalling due an interrupt
|
||||
* storm.
|
||||
*
|
||||
* If this happens when all Rx bytes haven't been
|
||||
* received, log the condition. The only known time
|
||||
* this can happen is if bits_per_word != 8 and some
|
||||
* registers that expect xfer lengths in num spi_words
|
||||
* weren't written correctly.
|
||||
*/
|
||||
if (mas->tx_rem_bytes) {
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
|
||||
mas->tx_rem_bytes, mas->cur_bits_per_word);
|
||||
}
|
||||
if (mas->rx_rem_bytes)
|
||||
dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
|
||||
mas->rx_rem_bytes, mas->cur_bits_per_word);
|
||||
} else {
|
||||
complete(&mas->cs_done);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,6 +1093,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||
spi->num_chipselect = 4;
|
||||
spi->max_speed_hz = 50000000;
|
||||
spi->max_dma_len = 0xffff0; /* 24 bits for tx/rx dma length */
|
||||
spi->prepare_message = spi_geni_prepare_message;
|
||||
spi->transfer_one = spi_geni_transfer_one;
|
||||
spi->can_dma = geni_can_dma;
|
||||
@@ -951,6 +1105,8 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
init_completion(&mas->cs_done);
|
||||
init_completion(&mas->cancel_done);
|
||||
init_completion(&mas->abort_done);
|
||||
init_completion(&mas->tx_reset_done);
|
||||
init_completion(&mas->rx_reset_done);
|
||||
spin_lock_init(&mas->lock);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
|
||||
@@ -958,6 +1114,9 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (device_property_read_bool(&pdev->dev, "spi-slave"))
|
||||
spi->slave = true;
|
||||
|
||||
ret = geni_icc_get(&mas->se, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -978,7 +1137,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
* for dma (gsi) mode, the gsi will set cs based on params passed in
|
||||
* TRE
|
||||
*/
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO)
|
||||
if (!spi->slave && mas->cur_xfer_mode == GENI_SE_FIFO)
|
||||
spi->set_cs = spi_geni_set_cs;
|
||||
|
||||
/*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -510,7 +510,7 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag)
|
||||
struct scsi_cmnd *cmd = lrbp->cmd;
|
||||
struct ufs_hw_queue *hwq;
|
||||
void __iomem *reg, *opr_sqd_base;
|
||||
u32 nexus, id, val;
|
||||
u32 nexus, id, val, rtc;
|
||||
int err;
|
||||
|
||||
if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC)
|
||||
@@ -540,17 +540,18 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag)
|
||||
opr_sqd_base = mcq_opr_base(hba, OPR_SQD, id);
|
||||
writel(nexus, opr_sqd_base + REG_SQCTI);
|
||||
|
||||
/* SQRTCy.ICU = 1 */
|
||||
writel(SQ_ICU, opr_sqd_base + REG_SQRTC);
|
||||
/* Initiate Cleanup */
|
||||
writel(readl(opr_sqd_base + REG_SQRTC) | SQ_ICU,
|
||||
opr_sqd_base + REG_SQRTC);
|
||||
|
||||
/* Poll SQRTSy.CUS = 1. Return result from SQRTSy.RTC */
|
||||
reg = opr_sqd_base + REG_SQRTS;
|
||||
err = read_poll_timeout(readl, val, val & SQ_CUS, 20,
|
||||
MCQ_POLL_US, false, reg);
|
||||
if (err)
|
||||
dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%ld\n",
|
||||
__func__, id, task_tag,
|
||||
FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg)));
|
||||
rtc = FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg));
|
||||
if (err || rtc)
|
||||
dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%d RTC=%d\n",
|
||||
__func__, id, task_tag, err, rtc);
|
||||
|
||||
if (ufshcd_mcq_sq_start(hba, hwq))
|
||||
err = -ETIMEDOUT;
|
||||
|
||||
@@ -54,8 +54,10 @@
|
||||
|
||||
|
||||
/* UIC command timeout, unit: ms */
|
||||
#define UIC_CMD_TIMEOUT 500
|
||||
|
||||
enum {
|
||||
UIC_CMD_TIMEOUT_DEFAULT = 500,
|
||||
UIC_CMD_TIMEOUT_MAX = 2000,
|
||||
};
|
||||
/* NOP OUT retries waiting for NOP IN response */
|
||||
#define NOP_OUT_RETRIES 10
|
||||
/* Timeout after 50 msecs if NOP OUT hangs without response */
|
||||
@@ -129,6 +131,23 @@ static const struct kernel_param_ops mcq_mode_ops = {
|
||||
module_param_cb(use_mcq_mode, &mcq_mode_ops, &use_mcq_mode, 0644);
|
||||
MODULE_PARM_DESC(use_mcq_mode, "Control MCQ mode for controllers starting from UFSHCI 4.0. 1 - enable MCQ, 0 - disable MCQ. MCQ is enabled by default");
|
||||
|
||||
static unsigned int uic_cmd_timeout = UIC_CMD_TIMEOUT_DEFAULT;
|
||||
|
||||
static int uic_cmd_timeout_set(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
return param_set_uint_minmax(val, kp, UIC_CMD_TIMEOUT_DEFAULT,
|
||||
UIC_CMD_TIMEOUT_MAX);
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops uic_cmd_timeout_ops = {
|
||||
.set = uic_cmd_timeout_set,
|
||||
.get = param_get_uint,
|
||||
};
|
||||
|
||||
module_param_cb(uic_cmd_timeout, &uic_cmd_timeout_ops, &uic_cmd_timeout, 0644);
|
||||
MODULE_PARM_DESC(uic_cmd_timeout,
|
||||
"UFS UIC command timeout in milliseconds. Defaults to 500ms. Supported values range from 500ms to 2 seconds inclusively");
|
||||
|
||||
#define ufshcd_toggle_vreg(_dev, _vreg, _on) \
|
||||
({ \
|
||||
int _ret; \
|
||||
@@ -2380,7 +2399,7 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
|
||||
{
|
||||
u32 val;
|
||||
int ret = read_poll_timeout(ufshcd_readl, val, val & UIC_COMMAND_READY,
|
||||
500, UIC_CMD_TIMEOUT * 1000, false, hba,
|
||||
500, uic_cmd_timeout * 1000, false, hba,
|
||||
REG_CONTROLLER_STATUS);
|
||||
return ret == 0 ? true : false;
|
||||
}
|
||||
@@ -2439,7 +2458,7 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
|
||||
lockdep_assert_held(&hba->uic_cmd_mutex);
|
||||
|
||||
if (wait_for_completion_timeout(&uic_cmd->done,
|
||||
msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
|
||||
msecs_to_jiffies(uic_cmd_timeout))) {
|
||||
ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
|
||||
} else {
|
||||
ret = -ETIMEDOUT;
|
||||
@@ -4257,7 +4276,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(hba->uic_async_done,
|
||||
msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
|
||||
msecs_to_jiffies(uic_cmd_timeout))) {
|
||||
dev_err(hba->dev,
|
||||
"pwr ctrl cmd 0x%x with mode 0x%x completion timeout\n",
|
||||
cmd->command, cmd->argument3);
|
||||
@@ -5401,10 +5420,12 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp,
|
||||
}
|
||||
break;
|
||||
case OCS_ABORTED:
|
||||
result |= DID_ABORT << 16;
|
||||
break;
|
||||
case OCS_INVALID_COMMAND_STATUS:
|
||||
result |= DID_REQUEUE << 16;
|
||||
dev_warn(hba->dev,
|
||||
"OCS %s from controller for tag %d\n",
|
||||
(ocs == OCS_ABORTED? "aborted" : "invalid"),
|
||||
lrbp->task_tag);
|
||||
break;
|
||||
case OCS_INVALID_CMD_TABLE_ATTR:
|
||||
case OCS_INVALID_PRDT_ATTR:
|
||||
@@ -6477,9 +6498,6 @@ static bool ufshcd_abort_all(struct ufs_hba *hba)
|
||||
|
||||
if (is_mcq_enabled(hba)) {
|
||||
struct ufshcd_lrb *lrbp;
|
||||
int tag;
|
||||
struct ufs_hw_queue *hwq;
|
||||
unsigned long flags;
|
||||
|
||||
for (tag = 0; tag < hba->nutrs; tag++) {
|
||||
lrbp = &hba->lrb[tag];
|
||||
@@ -6493,13 +6511,6 @@ static bool ufshcd_abort_all(struct ufs_hba *hba)
|
||||
needs_reset = true;
|
||||
goto out;
|
||||
}
|
||||
hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(lrbp->cmd));
|
||||
if (!hwq)
|
||||
return 0;
|
||||
spin_lock_irqsave(&hwq->cq_lock, flags);
|
||||
if (ufshcd_cmd_inflight(lrbp->cmd))
|
||||
ufshcd_release_scsi_cmd(hba, lrbp);
|
||||
spin_unlock_irqrestore(&hwq->cq_lock, flags);
|
||||
}
|
||||
} else {
|
||||
/* Clear pending transfer requests */
|
||||
@@ -10269,9 +10280,6 @@ int ufshcd_system_restore(struct device *dev)
|
||||
*/
|
||||
ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_BASE_H);
|
||||
|
||||
/* Resuming from hibernate, assume that link was OFF */
|
||||
ufshcd_set_link_off(hba);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ static struct usb_ss_ep_comp_descriptor acc_superspeedplus_comp_desc = {
|
||||
|
||||
/* the following 2 values can be tweaked if necessary */
|
||||
.bMaxBurst = 6,
|
||||
/* .bmAttributes = 0, */
|
||||
.bmAttributes = 16,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acc_superspeed_in_desc = {
|
||||
@@ -197,7 +197,7 @@ static struct usb_ss_ep_comp_descriptor acc_superspeed_comp_desc = {
|
||||
|
||||
/* the following 2 values can be tweaked if necessary */
|
||||
.bMaxBurst = 6,
|
||||
/* .bmAttributes = 0, */
|
||||
.bmAttributes = 16,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acc_highspeed_in_desc = {
|
||||
|
||||
@@ -1691,6 +1691,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||||
|
||||
trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic);
|
||||
|
||||
cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
|
||||
|
||||
/* If CMD ring stopped we own the trbs between enqueue and dequeue */
|
||||
if (cmd_comp_code == COMP_COMMAND_RING_STOPPED) {
|
||||
complete_all(&xhci->cmd_ring_stop_completion);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
|
||||
cmd_trb);
|
||||
/*
|
||||
@@ -1707,14 +1715,6 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||||
|
||||
cancel_delayed_work(&xhci->cmd_timer);
|
||||
|
||||
cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
|
||||
|
||||
/* If CMD ring stopped we own the trbs between enqueue and dequeue */
|
||||
if (cmd_comp_code == COMP_COMMAND_RING_STOPPED) {
|
||||
complete_all(&xhci->cmd_ring_stop_completion);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd->command_trb != xhci->cmd_ring->dequeue) {
|
||||
xhci_err(xhci,
|
||||
"Command completion event does not match command\n");
|
||||
|
||||
@@ -4935,7 +4935,6 @@ static void run_state_machine(struct tcpm_port *port)
|
||||
break;
|
||||
case PORT_RESET:
|
||||
tcpm_reset_port(port);
|
||||
port->pd_events = 0;
|
||||
tcpm_set_cc(port, TYPEC_CC_OPEN);
|
||||
tcpm_set_state(port, PORT_RESET_WAIT_OFF,
|
||||
PD_T_ERROR_RECOVERY);
|
||||
|
||||
@@ -1485,13 +1485,17 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
|
||||
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
|
||||
old_blkaddr = dn->data_blkaddr;
|
||||
f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
|
||||
&sum, seg_type, NULL);
|
||||
err = f2fs_allocate_data_block(sbi, NULL, old_blkaddr,
|
||||
&dn->data_blkaddr, &sum, seg_type, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
|
||||
invalidate_mapping_pages(META_MAPPING(sbi),
|
||||
old_blkaddr, old_blkaddr);
|
||||
f2fs_invalidate_compress_page(sbi, old_blkaddr);
|
||||
}
|
||||
|
||||
f2fs_update_data_blkaddr(dn, dn->data_blkaddr);
|
||||
return 0;
|
||||
}
|
||||
@@ -2668,7 +2672,7 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
return true;
|
||||
if (IS_NOQUOTA(inode))
|
||||
return true;
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
if (f2fs_used_in_atomic_write(inode))
|
||||
return true;
|
||||
|
||||
/* swap file is migrating in aligned write mode */
|
||||
@@ -2707,10 +2711,13 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
struct dnode_of_data dn;
|
||||
struct node_info ni;
|
||||
bool ipu_force = false;
|
||||
bool atomic_commit;
|
||||
int err = 0;
|
||||
|
||||
/* Use COW inode to make dnode_of_data for atomic write */
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
atomic_commit = f2fs_is_atomic_file(inode) &&
|
||||
page_private_atomic(fio->page);
|
||||
if (atomic_commit)
|
||||
set_new_dnode(&dn, F2FS_I(inode)->cow_inode, NULL, NULL, 0);
|
||||
else
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
@@ -2756,7 +2763,7 @@ got_it:
|
||||
}
|
||||
|
||||
/* wait for GCed page writeback via META_MAPPING */
|
||||
if (fio->post_read)
|
||||
if (fio->meta_gc)
|
||||
f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);
|
||||
|
||||
/*
|
||||
@@ -2814,6 +2821,8 @@ got_it:
|
||||
f2fs_outplace_write_data(&dn, fio);
|
||||
trace_f2fs_do_write_data_page(page, OPU);
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
if (atomic_commit)
|
||||
clear_page_private_atomic(page);
|
||||
out_writepage:
|
||||
f2fs_put_dnode(&dn);
|
||||
out:
|
||||
@@ -2852,7 +2861,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
|
||||
.submitted = 0,
|
||||
.compr_blocks = compr_blocks,
|
||||
.need_lock = compr_blocks ? LOCK_DONE : LOCK_RETRY,
|
||||
.post_read = f2fs_post_read_required(inode) ? 1 : 0,
|
||||
.meta_gc = f2fs_meta_inode_gc_required(inode) ? 1 : 0,
|
||||
.io_type = io_type,
|
||||
.io_wbc = wbc,
|
||||
.bio = bio,
|
||||
@@ -3734,6 +3743,9 @@ static int f2fs_write_end(struct file *file,
|
||||
|
||||
set_page_dirty(page);
|
||||
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
set_page_private_atomic(page);
|
||||
|
||||
if (pos + copied > i_size_read(inode) &&
|
||||
!f2fs_verity_in_progress(inode)) {
|
||||
f2fs_i_size_write(inode, pos + copied);
|
||||
|
||||
@@ -839,7 +839,11 @@ struct f2fs_inode_info {
|
||||
struct task_struct *atomic_write_task; /* store atomic write task */
|
||||
struct extent_tree *extent_tree[NR_EXTENT_CACHES];
|
||||
/* cached extent_tree entry */
|
||||
struct inode *cow_inode; /* copy-on-write inode for atomic write */
|
||||
union {
|
||||
struct inode *cow_inode; /* copy-on-write inode for atomic write */
|
||||
struct inode *atomic_inode;
|
||||
/* point to atomic_inode, available only for cow_inode */
|
||||
};
|
||||
|
||||
/* avoid racing between foreground op and gc */
|
||||
struct f2fs_rwsem i_gc_rwsem[2];
|
||||
@@ -1207,7 +1211,7 @@ struct f2fs_io_info {
|
||||
unsigned int is_por:1; /* indicate IO is from recovery or not */
|
||||
unsigned int retry:1; /* need to reallocate block address */
|
||||
unsigned int encrypted:1; /* indicate file is encrypted */
|
||||
unsigned int post_read:1; /* require post read */
|
||||
unsigned int meta_gc:1; /* require meta inode GC */
|
||||
enum iostat_type io_type; /* io type */
|
||||
struct writeback_control *io_wbc; /* writeback control */
|
||||
struct bio **bio; /* bio for ipu */
|
||||
@@ -1397,7 +1401,8 @@ static inline void f2fs_clear_bit(unsigned int nr, char *addr);
|
||||
* bit 2 PAGE_PRIVATE_ONGOING_MIGRATION
|
||||
* bit 3 PAGE_PRIVATE_INLINE_INODE
|
||||
* bit 4 PAGE_PRIVATE_REF_RESOURCE
|
||||
* bit 5- f2fs private data
|
||||
* bit 5 PAGE_PRIVATE_ATOMIC_WRITE
|
||||
* bit 6- f2fs private data
|
||||
*
|
||||
* Layout B: lowest bit should be 0
|
||||
* page.private is a wrapped pointer.
|
||||
@@ -1408,6 +1413,7 @@ enum {
|
||||
PAGE_PRIVATE_ONGOING_MIGRATION, /* data page which is on-going migrating */
|
||||
PAGE_PRIVATE_INLINE_INODE, /* inode page contains inline data */
|
||||
PAGE_PRIVATE_REF_RESOURCE, /* dirty page has referenced resources */
|
||||
PAGE_PRIVATE_ATOMIC_WRITE, /* data page from atomic write path */
|
||||
PAGE_PRIVATE_MAX
|
||||
};
|
||||
|
||||
@@ -2346,16 +2352,19 @@ PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER);
|
||||
PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE);
|
||||
PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION);
|
||||
PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE);
|
||||
PAGE_PRIVATE_GET_FUNC(atomic, ATOMIC_WRITE);
|
||||
|
||||
PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE);
|
||||
PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE);
|
||||
PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION);
|
||||
PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE);
|
||||
PAGE_PRIVATE_SET_FUNC(atomic, ATOMIC_WRITE);
|
||||
|
||||
PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE);
|
||||
|
||||
static inline unsigned long get_page_private_data(struct page *page)
|
||||
{
|
||||
@@ -2387,6 +2396,7 @@ static inline void clear_page_private_all(struct page *page)
|
||||
clear_page_private_reference(page);
|
||||
clear_page_private_gcing(page);
|
||||
clear_page_private_inline(page);
|
||||
clear_page_private_atomic(page);
|
||||
|
||||
f2fs_bug_on(F2FS_P_SB(page), page_private(page));
|
||||
}
|
||||
@@ -3667,7 +3677,7 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
|
||||
block_t old_addr, block_t new_addr,
|
||||
unsigned char version, bool recover_curseg,
|
||||
bool recover_newaddr);
|
||||
void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
block_t old_blkaddr, block_t *new_blkaddr,
|
||||
struct f2fs_summary *sum, int type,
|
||||
struct f2fs_io_info *fio);
|
||||
@@ -4208,6 +4218,16 @@ static inline bool f2fs_post_read_required(struct inode *inode)
|
||||
f2fs_compressed_file(inode);
|
||||
}
|
||||
|
||||
static inline bool f2fs_used_in_atomic_write(struct inode *inode)
|
||||
{
|
||||
return f2fs_is_atomic_file(inode) || f2fs_is_cow_file(inode);
|
||||
}
|
||||
|
||||
static inline bool f2fs_meta_inode_gc_required(struct inode *inode)
|
||||
{
|
||||
return f2fs_post_read_required(inode) || f2fs_used_in_atomic_write(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* compress.c
|
||||
*/
|
||||
|
||||
@@ -2095,7 +2095,6 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
|
||||
struct user_namespace *mnt_userns = file_mnt_user_ns(filp);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct inode *pinode;
|
||||
loff_t isize;
|
||||
int ret;
|
||||
|
||||
@@ -2144,15 +2143,10 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
|
||||
/* Check if the inode already has a COW inode */
|
||||
if (fi->cow_inode == NULL) {
|
||||
/* Create a COW inode for atomic write */
|
||||
pinode = f2fs_iget(inode->i_sb, fi->i_pino);
|
||||
if (IS_ERR(pinode)) {
|
||||
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
ret = PTR_ERR(pinode);
|
||||
goto out;
|
||||
}
|
||||
struct dentry *dentry = file_dentry(filp);
|
||||
struct inode *dir = d_inode(dentry->d_parent);
|
||||
|
||||
ret = f2fs_get_tmpfile(mnt_userns, pinode, &fi->cow_inode);
|
||||
iput(pinode);
|
||||
ret = f2fs_get_tmpfile(mnt_userns, dir, &fi->cow_inode);
|
||||
if (ret) {
|
||||
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
goto out;
|
||||
@@ -2160,6 +2154,9 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
|
||||
|
||||
set_inode_flag(fi->cow_inode, FI_COW_FILE);
|
||||
clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
|
||||
|
||||
/* Set the COW inode's atomic_inode to the atomic inode */
|
||||
F2FS_I(fi->cow_inode)->atomic_inode = inode;
|
||||
} else {
|
||||
/* Reuse the already created COW inode */
|
||||
f2fs_bug_on(sbi, get_dirty_pages(fi->cow_inode));
|
||||
@@ -2297,8 +2294,11 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
|
||||
case F2FS_GOING_DOWN_METASYNC:
|
||||
/* do checkpoint only */
|
||||
ret = f2fs_sync_fs(sb, 1);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (ret == -EIO)
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
|
||||
set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
|
||||
break;
|
||||
@@ -2317,6 +2317,8 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
|
||||
set_sbi_flag(sbi, SBI_IS_DIRTY);
|
||||
/* do checkpoint only */
|
||||
ret = f2fs_sync_fs(sb, 1);
|
||||
if (ret == -EIO)
|
||||
ret = 0;
|
||||
goto out;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
||||
25
fs/f2fs/gc.c
25
fs/f2fs/gc.c
@@ -280,11 +280,10 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
|
||||
p->max_search > sbi->max_victim_search)
|
||||
p->max_search = sbi->max_victim_search;
|
||||
|
||||
/* let's select beginning hot/small space first in no_heap mode*/
|
||||
/* let's select beginning hot/small space first. */
|
||||
if (f2fs_need_rand_seg(sbi))
|
||||
p->offset = prandom_u32_max(MAIN_SECS(sbi) * sbi->segs_per_sec);
|
||||
else if (test_opt(sbi, NOHEAP) &&
|
||||
(type == CURSEG_HOT_DATA || IS_NODESEG(type)))
|
||||
else if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
|
||||
p->offset = 0;
|
||||
else
|
||||
p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
|
||||
@@ -1172,7 +1171,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
static int ra_data_block(struct inode *inode, pgoff_t index)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct address_space *mapping = f2fs_is_cow_file(inode) ?
|
||||
F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
|
||||
struct dnode_of_data dn;
|
||||
struct page *page;
|
||||
struct f2fs_io_info fio = {
|
||||
@@ -1264,6 +1264,8 @@ put_page:
|
||||
static int move_data_block(struct inode *inode, block_t bidx,
|
||||
int gc_type, unsigned int segno, int off)
|
||||
{
|
||||
struct address_space *mapping = f2fs_is_cow_file(inode) ?
|
||||
F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
|
||||
struct f2fs_io_info fio = {
|
||||
.sbi = F2FS_I_SB(inode),
|
||||
.ino = inode->i_ino,
|
||||
@@ -1287,7 +1289,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
CURSEG_ALL_DATA_ATGC : CURSEG_COLD_DATA;
|
||||
|
||||
/* do not read out */
|
||||
page = f2fs_grab_cache_page(inode->i_mapping, bidx, false);
|
||||
page = f2fs_grab_cache_page(mapping, bidx, false);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1364,8 +1366,13 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
|
||||
|
||||
/* allocate block address */
|
||||
f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
|
||||
err = f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
|
||||
&sum, type, NULL);
|
||||
if (err) {
|
||||
f2fs_put_page(mpage, 1);
|
||||
/* filesystem should shutdown, no need to recovery block */
|
||||
goto up_out;
|
||||
}
|
||||
|
||||
fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
|
||||
newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS);
|
||||
@@ -1586,7 +1593,7 @@ next_step:
|
||||
start_bidx = f2fs_start_bidx_of_node(nofs, inode) +
|
||||
ofs_in_node;
|
||||
|
||||
if (f2fs_post_read_required(inode)) {
|
||||
if (f2fs_meta_inode_gc_required(inode)) {
|
||||
int err = ra_data_block(inode, start_bidx);
|
||||
|
||||
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
@@ -1637,7 +1644,7 @@ next_step:
|
||||
|
||||
start_bidx = f2fs_start_bidx_of_node(nofs, inode)
|
||||
+ ofs_in_node;
|
||||
if (f2fs_post_read_required(inode))
|
||||
if (f2fs_meta_inode_gc_required(inode))
|
||||
err = move_data_block(inode, start_bidx,
|
||||
gc_type, segno, off);
|
||||
else
|
||||
@@ -1645,7 +1652,7 @@ next_step:
|
||||
segno, off);
|
||||
|
||||
if (!err && (gc_type == FG_GC ||
|
||||
f2fs_post_read_required(inode)))
|
||||
f2fs_meta_inode_gc_required(inode)))
|
||||
submitted++;
|
||||
|
||||
if (locked) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
static bool support_inline_data(struct inode *inode)
|
||||
{
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
if (f2fs_used_in_atomic_write(inode))
|
||||
return false;
|
||||
if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))
|
||||
return false;
|
||||
|
||||
@@ -749,8 +749,9 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
|
||||
f2fs_abort_atomic_write(inode, true);
|
||||
|
||||
if (fi->cow_inode) {
|
||||
if (fi->cow_inode && f2fs_is_cow_file(fi->cow_inode)) {
|
||||
clear_inode_flag(fi->cow_inode, FI_COW_FILE);
|
||||
F2FS_I(fi->cow_inode)->atomic_inode = NULL;
|
||||
iput(fi->cow_inode);
|
||||
fi->cow_inode = NULL;
|
||||
}
|
||||
|
||||
@@ -410,6 +410,9 @@ int f2fs_commit_atomic_write(struct inode *inode)
|
||||
*/
|
||||
void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
|
||||
{
|
||||
if (f2fs_cp_error(sbi))
|
||||
return;
|
||||
|
||||
if (time_to_inject(sbi, FAULT_CHECKPOINT))
|
||||
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT);
|
||||
|
||||
@@ -2553,18 +2556,17 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi,
|
||||
* Find a new segment from the free segments bitmap to right order
|
||||
* This function should be returned with success, otherwise BUG
|
||||
*/
|
||||
static void get_new_segment(struct f2fs_sb_info *sbi,
|
||||
unsigned int *newseg, bool new_sec, int dir)
|
||||
static int get_new_segment(struct f2fs_sb_info *sbi,
|
||||
unsigned int *newseg, bool new_sec)
|
||||
{
|
||||
struct free_segmap_info *free_i = FREE_I(sbi);
|
||||
unsigned int segno, secno, zoneno;
|
||||
unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone;
|
||||
unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg);
|
||||
unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg);
|
||||
unsigned int left_start = hint;
|
||||
bool init = true;
|
||||
int go_left = 0;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&free_i->segmap_lock);
|
||||
|
||||
@@ -2577,30 +2579,13 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
|
||||
find_other_zone:
|
||||
secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
|
||||
if (secno >= MAIN_SECS(sbi)) {
|
||||
if (dir == ALLOC_RIGHT) {
|
||||
secno = find_first_zero_bit(free_i->free_secmap,
|
||||
secno = find_first_zero_bit(free_i->free_secmap,
|
||||
MAIN_SECS(sbi));
|
||||
f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi));
|
||||
} else {
|
||||
go_left = 1;
|
||||
left_start = hint - 1;
|
||||
if (secno >= MAIN_SECS(sbi)) {
|
||||
ret = -ENOSPC;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
if (go_left == 0)
|
||||
goto skip_left;
|
||||
|
||||
while (test_bit(left_start, free_i->free_secmap)) {
|
||||
if (left_start > 0) {
|
||||
left_start--;
|
||||
continue;
|
||||
}
|
||||
left_start = find_first_zero_bit(free_i->free_secmap,
|
||||
MAIN_SECS(sbi));
|
||||
f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi));
|
||||
break;
|
||||
}
|
||||
secno = left_start;
|
||||
skip_left:
|
||||
segno = GET_SEG_FROM_SEC(sbi, secno);
|
||||
zoneno = GET_ZONE_FROM_SEC(sbi, secno);
|
||||
|
||||
@@ -2611,21 +2596,13 @@ skip_left:
|
||||
goto got_it;
|
||||
if (zoneno == old_zoneno)
|
||||
goto got_it;
|
||||
if (dir == ALLOC_LEFT) {
|
||||
if (!go_left && zoneno + 1 >= total_zones)
|
||||
goto got_it;
|
||||
if (go_left && zoneno == 0)
|
||||
goto got_it;
|
||||
}
|
||||
for (i = 0; i < NR_CURSEG_TYPE; i++)
|
||||
if (CURSEG_I(sbi, i)->zone == zoneno)
|
||||
break;
|
||||
|
||||
if (i < NR_CURSEG_TYPE) {
|
||||
/* zone is in user, try another */
|
||||
if (go_left)
|
||||
hint = zoneno * sbi->secs_per_zone - 1;
|
||||
else if (zoneno + 1 >= total_zones)
|
||||
if (zoneno + 1 >= total_zones)
|
||||
hint = 0;
|
||||
else
|
||||
hint = (zoneno + 1) * sbi->secs_per_zone;
|
||||
@@ -2637,7 +2614,14 @@ got_it:
|
||||
f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap));
|
||||
__set_inuse(sbi, segno);
|
||||
*newseg = segno;
|
||||
out_unlock:
|
||||
spin_unlock(&free_i->segmap_lock);
|
||||
|
||||
if (ret) {
|
||||
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_NO_SEGMENT);
|
||||
f2fs_bug_on(sbi, 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
|
||||
@@ -2646,6 +2630,10 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
|
||||
struct summary_footer *sum_footer;
|
||||
unsigned short seg_type = curseg->seg_type;
|
||||
|
||||
/* only happen when get_new_segment() fails */
|
||||
if (curseg->next_segno == NULL_SEGNO)
|
||||
return;
|
||||
|
||||
curseg->inited = true;
|
||||
curseg->segno = curseg->next_segno;
|
||||
curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
|
||||
@@ -2684,8 +2672,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
|
||||
return 0;
|
||||
|
||||
if (test_opt(sbi, NOHEAP) &&
|
||||
(seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type)))
|
||||
if (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type))
|
||||
return 0;
|
||||
|
||||
if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
|
||||
@@ -2705,21 +2692,16 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
|
||||
static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
|
||||
{
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, type);
|
||||
unsigned short seg_type = curseg->seg_type;
|
||||
unsigned int segno = curseg->segno;
|
||||
int dir = ALLOC_LEFT;
|
||||
|
||||
if (curseg->inited)
|
||||
write_sum_page(sbi, curseg->sum_blk,
|
||||
GET_SUM_BLOCK(sbi, segno));
|
||||
if (seg_type == CURSEG_WARM_DATA || seg_type == CURSEG_COLD_DATA)
|
||||
dir = ALLOC_RIGHT;
|
||||
|
||||
if (test_opt(sbi, NOHEAP))
|
||||
dir = ALLOC_RIGHT;
|
||||
|
||||
write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, segno));
|
||||
segno = __get_next_segno(sbi, type);
|
||||
get_new_segment(sbi, &segno, new_sec, dir);
|
||||
if (get_new_segment(sbi, &segno, new_sec)) {
|
||||
curseg->segno = NULL_SEGNO;
|
||||
return;
|
||||
}
|
||||
|
||||
curseg->next_segno = segno;
|
||||
reset_curseg(sbi, type, 1);
|
||||
curseg->alloc_type = LFS;
|
||||
@@ -3327,7 +3309,7 @@ static void f2fs_randomize_chunk(struct f2fs_sb_info *sbi,
|
||||
prandom_u32_max(sbi->max_fragment_hole) + 1;
|
||||
}
|
||||
|
||||
void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
block_t old_blkaddr, block_t *new_blkaddr,
|
||||
struct f2fs_summary *sum, int type,
|
||||
struct f2fs_io_info *fio)
|
||||
@@ -3344,6 +3326,9 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
mutex_lock(&curseg->curseg_mutex);
|
||||
down_write(&sit_i->sentry_lock);
|
||||
|
||||
if (curseg->segno == NULL_SEGNO)
|
||||
goto out_err;
|
||||
|
||||
if (from_gc) {
|
||||
f2fs_bug_on(sbi, GET_SEGNO(sbi, old_blkaddr) == NULL_SEGNO);
|
||||
se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr));
|
||||
@@ -3398,6 +3383,9 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
change_curseg(sbi, type);
|
||||
stat_inc_seg_type(sbi, curseg);
|
||||
}
|
||||
|
||||
if (curseg->segno == NULL_SEGNO)
|
||||
goto out_err;
|
||||
}
|
||||
/*
|
||||
* segment dirty status should be updated after segment allocation,
|
||||
@@ -3433,8 +3421,15 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
}
|
||||
|
||||
mutex_unlock(&curseg->curseg_mutex);
|
||||
|
||||
f2fs_up_read(&SM_I(sbi)->curseg_lock);
|
||||
return 0;
|
||||
out_err:
|
||||
*new_blkaddr = NULL_ADDR;
|
||||
up_write(&sit_i->sentry_lock);
|
||||
mutex_unlock(&curseg->curseg_mutex);
|
||||
f2fs_up_read(&SM_I(sbi)->curseg_lock);
|
||||
return -ENOSPC;
|
||||
|
||||
}
|
||||
|
||||
void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
@@ -3472,8 +3467,17 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
|
||||
if (keep_order)
|
||||
f2fs_down_read(&fio->sbi->io_order_lock);
|
||||
reallocate:
|
||||
f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
|
||||
&fio->new_blkaddr, sum, type, fio);
|
||||
if (f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
|
||||
&fio->new_blkaddr, sum, type, fio)) {
|
||||
if (fscrypt_inode_uses_fs_layer_crypto(fio->page->mapping->host))
|
||||
fscrypt_finalize_bounce_page(&fio->encrypted_page);
|
||||
if (PageWriteback(fio->page))
|
||||
end_page_writeback(fio->page);
|
||||
if (f2fs_in_warm_node_list(fio->sbi, fio->page))
|
||||
f2fs_del_fsync_node_entry(fio->sbi, fio->page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) {
|
||||
invalidate_mapping_pages(META_MAPPING(fio->sbi),
|
||||
fio->old_blkaddr, fio->old_blkaddr);
|
||||
@@ -3488,7 +3492,7 @@ reallocate:
|
||||
}
|
||||
|
||||
f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1);
|
||||
|
||||
out:
|
||||
if (keep_order)
|
||||
f2fs_up_read(&fio->sbi->io_order_lock);
|
||||
}
|
||||
@@ -3571,7 +3575,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
|
||||
goto drop_bio;
|
||||
}
|
||||
|
||||
if (fio->post_read)
|
||||
if (fio->meta_gc)
|
||||
invalidate_mapping_pages(META_MAPPING(sbi),
|
||||
fio->new_blkaddr, fio->new_blkaddr);
|
||||
|
||||
@@ -3740,7 +3744,7 @@ void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct page *cpage;
|
||||
|
||||
if (!f2fs_post_read_required(inode))
|
||||
if (!f2fs_meta_inode_gc_required(inode))
|
||||
return;
|
||||
|
||||
if (!__is_valid_data_blkaddr(blkaddr))
|
||||
@@ -3759,7 +3763,7 @@ void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
block_t i;
|
||||
|
||||
if (!f2fs_post_read_required(inode))
|
||||
if (!f2fs_meta_inode_gc_required(inode))
|
||||
return;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
|
||||
@@ -138,16 +138,6 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
|
||||
#define SECTOR_TO_BLOCK(sectors) \
|
||||
((sectors) >> F2FS_LOG_SECTORS_PER_BLOCK)
|
||||
|
||||
/*
|
||||
* indicate a block allocation direction: RIGHT and LEFT.
|
||||
* RIGHT means allocating new sections towards the end of volume.
|
||||
* LEFT means the opposite direction.
|
||||
*/
|
||||
enum {
|
||||
ALLOC_RIGHT = 0,
|
||||
ALLOC_LEFT
|
||||
};
|
||||
|
||||
/*
|
||||
* In the victim_sel_policy->alloc_mode, there are three block allocation modes.
|
||||
* LFS writes data sequentially with cleaning operations.
|
||||
|
||||
@@ -764,10 +764,8 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
|
||||
clear_opt(sbi, DISCARD);
|
||||
break;
|
||||
case Opt_noheap:
|
||||
set_opt(sbi, NOHEAP);
|
||||
break;
|
||||
case Opt_heap:
|
||||
clear_opt(sbi, NOHEAP);
|
||||
f2fs_warn(sbi, "heap/no_heap options were deprecated");
|
||||
break;
|
||||
#ifdef CONFIG_F2FS_FS_XATTR
|
||||
case Opt_user_xattr:
|
||||
@@ -1980,10 +1978,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
} else {
|
||||
seq_puts(seq, ",nodiscard");
|
||||
}
|
||||
if (test_opt(sbi, NOHEAP))
|
||||
seq_puts(seq, ",no_heap");
|
||||
else
|
||||
seq_puts(seq, ",heap");
|
||||
#ifdef CONFIG_F2FS_FS_XATTR
|
||||
if (test_opt(sbi, XATTR_USER))
|
||||
seq_puts(seq, ",user_xattr");
|
||||
@@ -2141,7 +2135,6 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
set_opt(sbi, INLINE_DATA);
|
||||
set_opt(sbi, INLINE_DENTRY);
|
||||
set_opt(sbi, READ_EXTENT_CACHE);
|
||||
set_opt(sbi, NOHEAP);
|
||||
clear_opt(sbi, DISABLE_CHECKPOINT);
|
||||
set_opt(sbi, MERGE_CHECKPOINT);
|
||||
F2FS_OPTION(sbi).unusable_cap = 0;
|
||||
|
||||
@@ -2230,75 +2230,6 @@ static void nfdicf_init(void)
|
||||
file_fail(fold_name);
|
||||
}
|
||||
|
||||
static void ignore_init(void)
|
||||
{
|
||||
FILE *file;
|
||||
unsigned int unichar;
|
||||
unsigned int first;
|
||||
unsigned int last;
|
||||
unsigned int *um;
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
if (verbose > 0)
|
||||
printf("Parsing %s\n", prop_name);
|
||||
file = fopen(prop_name, "r");
|
||||
if (!file)
|
||||
open_fail(prop_name, errno);
|
||||
assert(file);
|
||||
count = 0;
|
||||
while (fgets(line, LINESIZE, file)) {
|
||||
ret = sscanf(line, "%X..%X ; %s # ", &first, &last, buf0);
|
||||
if (ret == 3) {
|
||||
if (strcmp(buf0, "Default_Ignorable_Code_Point"))
|
||||
continue;
|
||||
if (!utf32valid(first) || !utf32valid(last))
|
||||
line_fail(prop_name, line);
|
||||
for (unichar = first; unichar <= last; unichar++) {
|
||||
free(unicode_data[unichar].utf32nfdi);
|
||||
um = malloc(sizeof(unsigned int));
|
||||
*um = 0;
|
||||
unicode_data[unichar].utf32nfdi = um;
|
||||
free(unicode_data[unichar].utf32nfdicf);
|
||||
um = malloc(sizeof(unsigned int));
|
||||
*um = 0;
|
||||
unicode_data[unichar].utf32nfdicf = um;
|
||||
count++;
|
||||
}
|
||||
if (verbose > 1)
|
||||
printf(" %X..%X Default_Ignorable_Code_Point\n",
|
||||
first, last);
|
||||
continue;
|
||||
}
|
||||
ret = sscanf(line, "%X ; %s # ", &unichar, buf0);
|
||||
if (ret == 2) {
|
||||
if (strcmp(buf0, "Default_Ignorable_Code_Point"))
|
||||
continue;
|
||||
if (!utf32valid(unichar))
|
||||
line_fail(prop_name, line);
|
||||
free(unicode_data[unichar].utf32nfdi);
|
||||
um = malloc(sizeof(unsigned int));
|
||||
*um = 0;
|
||||
unicode_data[unichar].utf32nfdi = um;
|
||||
free(unicode_data[unichar].utf32nfdicf);
|
||||
um = malloc(sizeof(unsigned int));
|
||||
*um = 0;
|
||||
unicode_data[unichar].utf32nfdicf = um;
|
||||
if (verbose > 1)
|
||||
printf(" %X Default_Ignorable_Code_Point\n",
|
||||
unichar);
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
if (verbose > 0)
|
||||
printf("Found %d entries\n", count);
|
||||
if (count == 0)
|
||||
file_fail(prop_name);
|
||||
}
|
||||
|
||||
static void corrections_init(void)
|
||||
{
|
||||
FILE *file;
|
||||
@@ -3410,7 +3341,6 @@ int main(int argc, char *argv[])
|
||||
ccc_init();
|
||||
nfdi_init();
|
||||
nfdicf_init();
|
||||
ignore_init();
|
||||
corrections_init();
|
||||
hangul_decompose();
|
||||
nfdi_decompose();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -81,6 +81,7 @@ enum stop_cp_reason {
|
||||
STOP_CP_REASON_CORRUPTED_SUMMARY,
|
||||
STOP_CP_REASON_UPDATE_INODE,
|
||||
STOP_CP_REASON_FLUSH_FAIL,
|
||||
STOP_CP_REASON_NO_SEGMENT,
|
||||
STOP_CP_REASON_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -330,6 +330,11 @@ struct io_ring_ctx {
|
||||
|
||||
struct list_head io_buffers_pages;
|
||||
|
||||
/*
|
||||
* ANDROID: commit 6e5e6d274956 ("io_uring: drop any code related to
|
||||
* SCM_RIGHTS") removed this variable, but we add it back to preserve
|
||||
* the ABI. The field is not used anywhere.
|
||||
*/
|
||||
#if defined(CONFIG_UNIX)
|
||||
struct socket *ring_sock;
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,7 @@ enum geni_se_protocol_type {
|
||||
GENI_SE_UART,
|
||||
GENI_SE_I2C,
|
||||
GENI_SE_I3C,
|
||||
GENI_SE_SPI_SLAVE,
|
||||
};
|
||||
|
||||
struct geni_wrapper;
|
||||
@@ -73,23 +74,29 @@ struct geni_se {
|
||||
|
||||
/* Common SE registers */
|
||||
#define GENI_FORCE_DEFAULT_REG 0x20
|
||||
#define GENI_OUTPUT_CTRL 0x24
|
||||
#define SE_GENI_STATUS 0x40
|
||||
#define GENI_SER_M_CLK_CFG 0x48
|
||||
#define GENI_SER_S_CLK_CFG 0x4c
|
||||
#define GENI_IF_DISABLE_RO 0x64
|
||||
#define GENI_FW_REVISION_RO 0x68
|
||||
#define SE_GENI_CLK_SEL 0x7c
|
||||
#define SE_GENI_CFG_SEQ_START 0x84
|
||||
#define SE_GENI_DMA_MODE_EN 0x258
|
||||
#define SE_GENI_M_CMD0 0x600
|
||||
#define SE_GENI_M_CMD_CTRL_REG 0x604
|
||||
#define SE_GENI_M_IRQ_STATUS 0x610
|
||||
#define SE_GENI_M_IRQ_EN 0x614
|
||||
#define SE_GENI_M_IRQ_CLEAR 0x618
|
||||
#define SE_GENI_M_IRQ_EN_SET 0x61c
|
||||
#define SE_GENI_M_IRQ_EN_CLEAR 0x620
|
||||
#define SE_GENI_S_CMD0 0x630
|
||||
#define SE_GENI_S_CMD_CTRL_REG 0x634
|
||||
#define SE_GENI_S_IRQ_STATUS 0x640
|
||||
#define SE_GENI_S_IRQ_EN 0x644
|
||||
#define SE_GENI_S_IRQ_CLEAR 0x648
|
||||
#define SE_GENI_S_IRQ_EN_SET 0x64c
|
||||
#define SE_GENI_S_IRQ_EN_CLEAR 0x650
|
||||
#define SE_GENI_TX_FIFOn 0x700
|
||||
#define SE_GENI_RX_FIFOn 0x780
|
||||
#define SE_GENI_TX_FIFO_STATUS 0x800
|
||||
@@ -98,11 +105,14 @@ struct geni_se {
|
||||
#define SE_GENI_RX_WATERMARK_REG 0x810
|
||||
#define SE_GENI_RX_RFR_WATERMARK_REG 0x814
|
||||
#define SE_GENI_IOS 0x908
|
||||
#define SE_GENI_M_GP_LENGTH 0x910
|
||||
#define SE_GENI_S_GP_LENGTH 0x914
|
||||
#define SE_DMA_TX_IRQ_STAT 0xc40
|
||||
#define SE_DMA_TX_IRQ_CLR 0xc44
|
||||
#define SE_DMA_TX_FSM_RST 0xc58
|
||||
#define SE_DMA_RX_IRQ_STAT 0xd40
|
||||
#define SE_DMA_RX_IRQ_CLR 0xd44
|
||||
#define SE_DMA_RX_LEN_IN 0xd54
|
||||
#define SE_DMA_RX_FSM_RST 0xd58
|
||||
#define SE_HW_PARAM_0 0xe24
|
||||
#define SE_HW_PARAM_1 0xe28
|
||||
@@ -110,6 +120,9 @@ struct geni_se {
|
||||
/* GENI_FORCE_DEFAULT_REG fields */
|
||||
#define FORCE_DEFAULT BIT(0)
|
||||
|
||||
/* GENI_OUTPUT_CTRL fields */
|
||||
#define GENI_IO_MUX_0_EN BIT(0)
|
||||
|
||||
/* GENI_STATUS fields */
|
||||
#define M_GENI_CMD_ACTIVE BIT(0)
|
||||
#define S_GENI_CMD_ACTIVE BIT(12)
|
||||
@@ -129,6 +142,9 @@ struct geni_se {
|
||||
/* GENI_CLK_SEL fields */
|
||||
#define CLK_SEL_MSK GENMASK(2, 0)
|
||||
|
||||
/* SE_GENI_CFG_SEQ_START fields */
|
||||
#define START_TRIGGER BIT(0)
|
||||
|
||||
/* SE_GENI_DMA_MODE_EN */
|
||||
#define GENI_DMA_MODE_EN BIT(0)
|
||||
|
||||
@@ -168,6 +184,7 @@ struct geni_se {
|
||||
#define M_GP_IRQ_3_EN BIT(12)
|
||||
#define M_GP_IRQ_4_EN BIT(13)
|
||||
#define M_GP_IRQ_5_EN BIT(14)
|
||||
#define M_TX_FIFO_NOT_EMPTY_EN BIT(21)
|
||||
#define M_IO_DATA_DEASSERT_EN BIT(22)
|
||||
#define M_IO_DATA_ASSERT_EN BIT(23)
|
||||
#define M_RX_FIFO_RD_ERR_EN BIT(24)
|
||||
@@ -223,6 +240,9 @@ struct geni_se {
|
||||
#define IO2_DATA_IN BIT(1)
|
||||
#define RX_DATA_IN BIT(0)
|
||||
|
||||
/* SE_GENI_M_GP_LENGTH and SE_GENI_S_GP_LENGTH fields */
|
||||
#define GP_LENGTH GENMASK(31, 0)
|
||||
|
||||
/* SE_DMA_TX_IRQ_STAT Register fields */
|
||||
#define TX_DMA_DONE BIT(0)
|
||||
#define TX_EOT BIT(1)
|
||||
@@ -235,6 +255,8 @@ struct geni_se {
|
||||
#define RX_SBE BIT(2)
|
||||
#define RX_RESET_DONE BIT(3)
|
||||
#define RX_FLUSH_DONE BIT(4)
|
||||
#define RX_DMA_PARITY_ERR BIT(5)
|
||||
#define RX_DMA_BREAK GENMASK(8, 7)
|
||||
#define RX_GENI_GP_IRQ GENMASK(10, 5)
|
||||
#define RX_GENI_CANCEL_IRQ BIT(11)
|
||||
#define RX_GENI_GP_IRQ_EXT GENMASK(13, 12)
|
||||
@@ -487,9 +509,13 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
|
||||
unsigned int *index, unsigned long *res_freq,
|
||||
bool exact);
|
||||
|
||||
void geni_se_tx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len);
|
||||
|
||||
int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova);
|
||||
|
||||
void geni_se_rx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len);
|
||||
|
||||
int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova);
|
||||
|
||||
|
||||
@@ -282,6 +282,12 @@ DECLARE_HOOK(android_vh_filemap_map_pages,
|
||||
TP_PROTO(struct file *file, pgoff_t first_pgoff,
|
||||
pgoff_t last_pgoff, vm_fault_t ret),
|
||||
TP_ARGS(file, first_pgoff, last_pgoff, ret));
|
||||
DECLARE_HOOK(android_vh_alloc_flags_cma_adjust,
|
||||
TP_PROTO(gfp_t gfp_mask, unsigned int *alloc_flags),
|
||||
TP_ARGS(gfp_mask, alloc_flags));
|
||||
DECLARE_HOOK(android_vh_rmqueue_cma_fallback,
|
||||
TP_PROTO(struct zone *zone, unsigned int order, struct page **page),
|
||||
TP_ARGS(zone, order, page));
|
||||
#endif /* _TRACE_HOOK_MM_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
||||
@@ -16,6 +16,7 @@ DECLARE_HOOK(android_vh_ptype_head,
|
||||
|
||||
struct nf_conn;
|
||||
struct sock;
|
||||
struct net_device;
|
||||
DECLARE_RESTRICTED_HOOK(android_rvh_nf_conn_alloc,
|
||||
TP_PROTO(struct nf_conn *nf_conn), TP_ARGS(nf_conn), 1);
|
||||
DECLARE_RESTRICTED_HOOK(android_rvh_nf_conn_free,
|
||||
@@ -31,7 +32,10 @@ DECLARE_HOOK(android_vh_netlink_poll,
|
||||
TP_PROTO(struct file *file, struct socket *sock, poll_table *wait,
|
||||
__poll_t *mask),
|
||||
TP_ARGS(file, sock, wait, mask));
|
||||
|
||||
DECLARE_HOOK(android_vh_dc_send_copy,
|
||||
TP_PROTO(struct sk_buff *skb, struct net_device *dev), TP_ARGS(skb, dev));
|
||||
DECLARE_HOOK(android_vh_dc_receive,
|
||||
TP_PROTO(struct sk_buff *skb, int *flag), TP_ARGS(skb, flag));
|
||||
/* macro versions of hooks are no longer required */
|
||||
|
||||
#endif /* _TRACE_HOOK_NET_VH_H */
|
||||
|
||||
@@ -72,6 +72,9 @@ DECLARE_HOOK(android_vh_do_folio_trylock,
|
||||
DECLARE_HOOK(android_vh_page_referenced_check_bypass,
|
||||
TP_PROTO(struct folio *folio, unsigned long nr_to_scan, int lru, bool *bypass),
|
||||
TP_ARGS(folio, nr_to_scan, lru, bypass));
|
||||
DECLARE_HOOK(android_vh_should_memcg_bypass,
|
||||
TP_PROTO(struct mem_cgroup *memcg, int priority, bool *bypass),
|
||||
TP_ARGS(memcg, priority, bypass));
|
||||
#endif /* _TRACE_HOOK_VMSCAN_H */
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
|
||||
@@ -95,12 +95,10 @@ static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
|
||||
needs_switch = true;
|
||||
}
|
||||
|
||||
ret = io_scm_file_account(ctx, file);
|
||||
if (!ret) {
|
||||
*io_get_tag_slot(ctx->file_data, slot_index) = 0;
|
||||
io_fixed_file_set(file_slot, file);
|
||||
io_file_bitmap_set(&ctx->file_table, slot_index);
|
||||
}
|
||||
*io_get_tag_slot(ctx->file_data, slot_index) = 0;
|
||||
io_fixed_file_set(file_slot, file);
|
||||
io_file_bitmap_set(&ctx->file_table, slot_index);
|
||||
return 0;
|
||||
err:
|
||||
if (needs_switch)
|
||||
io_rsrc_node_switch(ctx, ctx->file_data);
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
#include <linux/net.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/af_unix.h>
|
||||
#include <net/scm.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/uaccess.h>
|
||||
@@ -2635,12 +2634,6 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
|
||||
WARN_ON_ONCE(!list_empty(&ctx->rsrc_ref_list));
|
||||
WARN_ON_ONCE(!llist_empty(&ctx->rsrc_put_llist));
|
||||
|
||||
#if defined(CONFIG_UNIX)
|
||||
if (ctx->ring_sock) {
|
||||
ctx->ring_sock->file = NULL; /* so that iput() is called */
|
||||
sock_release(ctx->ring_sock);
|
||||
}
|
||||
#endif
|
||||
WARN_ON_ONCE(!list_empty(&ctx->ltimeout_list));
|
||||
|
||||
if (ctx->mm_account) {
|
||||
@@ -3448,32 +3441,12 @@ static int io_uring_install_fd(struct io_ring_ctx *ctx, struct file *file)
|
||||
/*
|
||||
* Allocate an anonymous fd, this is what constitutes the application
|
||||
* visible backing of an io_uring instance. The application mmaps this
|
||||
* fd to gain access to the SQ/CQ ring details. If UNIX sockets are enabled,
|
||||
* we have to tie this fd to a socket for file garbage collection purposes.
|
||||
* fd to gain access to the SQ/CQ ring details.
|
||||
*/
|
||||
static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
|
||||
{
|
||||
struct file *file;
|
||||
#if defined(CONFIG_UNIX)
|
||||
int ret;
|
||||
|
||||
ret = sock_create_kern(&init_net, PF_UNIX, SOCK_RAW, IPPROTO_IP,
|
||||
&ctx->ring_sock);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
#endif
|
||||
|
||||
file = anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx,
|
||||
return anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx,
|
||||
O_RDWR | O_CLOEXEC, NULL);
|
||||
#if defined(CONFIG_UNIX)
|
||||
if (IS_ERR(file)) {
|
||||
sock_release(ctx->ring_sock);
|
||||
ctx->ring_sock = NULL;
|
||||
} else {
|
||||
ctx->ring_sock->file = file;
|
||||
}
|
||||
#endif
|
||||
return file;
|
||||
}
|
||||
|
||||
static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
|
||||
|
||||
151
io_uring/rsrc.c
151
io_uring/rsrc.c
@@ -494,11 +494,6 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
|
||||
err = -EBADF;
|
||||
break;
|
||||
}
|
||||
err = io_scm_file_account(ctx, file);
|
||||
if (err) {
|
||||
fput(file);
|
||||
break;
|
||||
}
|
||||
*io_get_tag_slot(data, i) = tag;
|
||||
io_fixed_file_set(file_slot, file);
|
||||
io_file_bitmap_set(&ctx->file_table, i);
|
||||
@@ -762,22 +757,12 @@ void __io_sqe_files_unregister(struct io_ring_ctx *ctx)
|
||||
for (i = 0; i < ctx->nr_user_files; i++) {
|
||||
struct file *file = io_file_from_index(&ctx->file_table, i);
|
||||
|
||||
/* skip scm accounted files, they'll be freed by ->ring_sock */
|
||||
if (!file || io_file_need_scm(file))
|
||||
if (!file)
|
||||
continue;
|
||||
io_file_bitmap_clear(&ctx->file_table, i);
|
||||
fput(file);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_UNIX)
|
||||
if (ctx->ring_sock) {
|
||||
struct sock *sock = ctx->ring_sock->sk;
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = skb_dequeue(&sock->sk_receive_queue)) != NULL)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
#endif
|
||||
io_free_file_tables(&ctx->file_table);
|
||||
io_file_table_set_alloc_range(ctx, 0, 0);
|
||||
io_rsrc_data_free(ctx->file_data);
|
||||
@@ -805,134 +790,11 @@ int io_sqe_files_unregister(struct io_ring_ctx *ctx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the UNIX gc is aware of our file set, so we are certain that
|
||||
* the io_uring can be safely unregistered on process exit, even if we have
|
||||
* loops in the file referencing. We account only files that can hold other
|
||||
* files because otherwise they can't form a loop and so are not interesting
|
||||
* for GC.
|
||||
*/
|
||||
int __io_scm_file_account(struct io_ring_ctx *ctx, struct file *file)
|
||||
{
|
||||
#if defined(CONFIG_UNIX)
|
||||
struct sock *sk = ctx->ring_sock->sk;
|
||||
struct sk_buff_head *head = &sk->sk_receive_queue;
|
||||
struct scm_fp_list *fpl;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (likely(!io_file_need_scm(file)))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* See if we can merge this file into an existing skb SCM_RIGHTS
|
||||
* file set. If there's no room, fall back to allocating a new skb
|
||||
* and filling it in.
|
||||
*/
|
||||
spin_lock_irq(&head->lock);
|
||||
skb = skb_peek(head);
|
||||
if (skb && UNIXCB(skb).fp->count < SCM_MAX_FD)
|
||||
__skb_unlink(skb, head);
|
||||
else
|
||||
skb = NULL;
|
||||
spin_unlock_irq(&head->lock);
|
||||
|
||||
if (!skb) {
|
||||
fpl = kzalloc(sizeof(*fpl), GFP_KERNEL);
|
||||
if (!fpl)
|
||||
return -ENOMEM;
|
||||
|
||||
skb = alloc_skb(0, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
kfree(fpl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fpl->user = get_uid(current_user());
|
||||
fpl->max = SCM_MAX_FD;
|
||||
fpl->count = 0;
|
||||
|
||||
UNIXCB(skb).fp = fpl;
|
||||
skb->sk = sk;
|
||||
skb->scm_io_uring = 1;
|
||||
skb->destructor = unix_destruct_scm;
|
||||
refcount_add(skb->truesize, &sk->sk_wmem_alloc);
|
||||
}
|
||||
|
||||
fpl = UNIXCB(skb).fp;
|
||||
fpl->fp[fpl->count++] = get_file(file);
|
||||
unix_inflight(fpl->user, file);
|
||||
skb_queue_head(head, skb);
|
||||
fput(file);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void io_rsrc_file_put(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc)
|
||||
{
|
||||
struct file *file = prsrc->file;
|
||||
#if defined(CONFIG_UNIX)
|
||||
struct sock *sock = ctx->ring_sock->sk;
|
||||
struct sk_buff_head list, *head = &sock->sk_receive_queue;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
if (!io_file_need_scm(file)) {
|
||||
fput(file);
|
||||
return;
|
||||
}
|
||||
|
||||
__skb_queue_head_init(&list);
|
||||
|
||||
/*
|
||||
* Find the skb that holds this file in its SCM_RIGHTS. When found,
|
||||
* remove this entry and rearrange the file array.
|
||||
*/
|
||||
skb = skb_dequeue(head);
|
||||
while (skb) {
|
||||
struct scm_fp_list *fp;
|
||||
|
||||
fp = UNIXCB(skb).fp;
|
||||
for (i = 0; i < fp->count; i++) {
|
||||
int left;
|
||||
|
||||
if (fp->fp[i] != file)
|
||||
continue;
|
||||
|
||||
unix_notinflight(fp->user, fp->fp[i]);
|
||||
left = fp->count - 1 - i;
|
||||
if (left) {
|
||||
memmove(&fp->fp[i], &fp->fp[i + 1],
|
||||
left * sizeof(struct file *));
|
||||
}
|
||||
fp->count--;
|
||||
if (!fp->count) {
|
||||
kfree_skb(skb);
|
||||
skb = NULL;
|
||||
} else {
|
||||
__skb_queue_tail(&list, skb);
|
||||
}
|
||||
fput(file);
|
||||
file = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!file)
|
||||
break;
|
||||
|
||||
__skb_queue_tail(&list, skb);
|
||||
|
||||
skb = skb_dequeue(head);
|
||||
}
|
||||
|
||||
if (skb_peek(&list)) {
|
||||
spin_lock_irq(&head->lock);
|
||||
while ((skb = __skb_dequeue(&list)) != NULL)
|
||||
__skb_queue_tail(head, skb);
|
||||
spin_unlock_irq(&head->lock);
|
||||
}
|
||||
#else
|
||||
fput(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
|
||||
@@ -986,21 +848,12 @@ int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Don't allow io_uring instances to be registered. If UNIX
|
||||
* isn't enabled, then this causes a reference cycle and this
|
||||
* instance can never get freed. If UNIX is enabled we'll
|
||||
* handle it just fine, but there's still no point in allowing
|
||||
* a ring fd as it doesn't support regular read/write anyway.
|
||||
* Don't allow io_uring instances to be registered.
|
||||
*/
|
||||
if (io_is_uring_fops(file)) {
|
||||
fput(file);
|
||||
goto fail;
|
||||
}
|
||||
ret = io_scm_file_account(ctx, file);
|
||||
if (ret) {
|
||||
fput(file);
|
||||
goto fail;
|
||||
}
|
||||
file_slot = io_fixed_file_slot(&ctx->file_table, i);
|
||||
io_fixed_file_set(file_slot, file);
|
||||
io_file_bitmap_set(&ctx->file_table, i);
|
||||
|
||||
@@ -77,21 +77,6 @@ int io_sqe_files_unregister(struct io_ring_ctx *ctx);
|
||||
int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
|
||||
unsigned nr_args, u64 __user *tags);
|
||||
|
||||
int __io_scm_file_account(struct io_ring_ctx *ctx, struct file *file);
|
||||
|
||||
static inline bool io_file_need_scm(struct file *filp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int io_scm_file_account(struct io_ring_ctx *ctx,
|
||||
struct file *file)
|
||||
{
|
||||
if (likely(!io_file_need_scm(file)))
|
||||
return 0;
|
||||
return __io_scm_file_account(ctx, file);
|
||||
}
|
||||
|
||||
int io_register_files_update(struct io_ring_ctx *ctx, void __user *arg,
|
||||
unsigned nr_args);
|
||||
int io_register_rsrc_update(struct io_ring_ctx *ctx, void __user *arg,
|
||||
|
||||
@@ -428,7 +428,7 @@ static void coredump_task_exit(struct task_struct *tsk)
|
||||
complete(&core_state->startup);
|
||||
|
||||
for (;;) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE|TASK_FREEZABLE);
|
||||
set_current_state(TASK_IDLE|TASK_FREEZABLE);
|
||||
if (!self.task) /* see coredump_finish() */
|
||||
break;
|
||||
schedule();
|
||||
|
||||
@@ -7663,6 +7663,12 @@ static int user_check_sched_setscheduler(struct task_struct *p,
|
||||
if (p->sched_reset_on_fork && !reset_on_fork)
|
||||
goto req_priv;
|
||||
|
||||
if (!capable(CAP_SYS_NICE)) {
|
||||
/* Can't change util-clamps */
|
||||
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
req_priv:
|
||||
|
||||
@@ -3165,6 +3165,12 @@ __rmqueue(struct zone *zone, unsigned int order, int migratetype,
|
||||
retry:
|
||||
page = __rmqueue_smallest(zone, order, migratetype);
|
||||
|
||||
/*
|
||||
* let normal GFP_MOVABLE has chance to try MIGRATE_CMA
|
||||
*/
|
||||
if (unlikely(!page) && (migratetype == MIGRATE_MOVABLE))
|
||||
trace_android_vh_rmqueue_cma_fallback(zone, order, &page);
|
||||
|
||||
if (unlikely(!page) && __rmqueue_fallback(zone, order, migratetype,
|
||||
alloc_flags))
|
||||
goto retry;
|
||||
@@ -4302,6 +4308,7 @@ static inline unsigned int gfp_to_alloc_flags_cma(gfp_t gfp_mask,
|
||||
#ifdef CONFIG_CMA
|
||||
if (gfp_migratetype(gfp_mask) == MIGRATE_MOVABLE && gfp_mask & __GFP_CMA)
|
||||
alloc_flags |= ALLOC_CMA;
|
||||
trace_android_vh_alloc_flags_cma_adjust(gfp_mask, &alloc_flags);
|
||||
#endif
|
||||
return alloc_flags;
|
||||
}
|
||||
|
||||
16
mm/vmscan.c
16
mm/vmscan.c
@@ -3237,6 +3237,7 @@ DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS);
|
||||
DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS);
|
||||
#define get_cap(cap) static_branch_unlikely(&lru_gen_caps[cap])
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(lru_gen_caps);
|
||||
|
||||
/******************************************************************************
|
||||
* shorthand helpers
|
||||
@@ -5480,6 +5481,7 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc)
|
||||
struct lru_gen_folio *lrugen = NULL;
|
||||
struct mem_cgroup *memcg;
|
||||
const struct hlist_nulls_node *pos;
|
||||
bool bypass = false;
|
||||
|
||||
bin = first_bin = get_random_u32_below(MEMCG_NR_BINS);
|
||||
restart:
|
||||
@@ -5506,6 +5508,10 @@ restart:
|
||||
continue;
|
||||
}
|
||||
|
||||
trace_android_vh_should_memcg_bypass(memcg, sc->priority, &bypass);
|
||||
if (bypass)
|
||||
continue;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
op = shrink_one(lruvec, sc);
|
||||
@@ -5593,7 +5599,11 @@ static void set_initial_priority(struct pglist_data *pgdat, struct scan_control
|
||||
/* round down reclaimable and round up sc->nr_to_reclaim */
|
||||
priority = fls_long(reclaimable) - 1 - fls_long(sc->nr_to_reclaim - 1);
|
||||
|
||||
sc->priority = clamp(priority, 0, DEF_PRIORITY);
|
||||
/*
|
||||
* The estimation is based on LRU pages only, so cap it to prevent
|
||||
* overshoots of shrinker objects by large margins.
|
||||
*/
|
||||
sc->priority = clamp(priority, DEF_PRIORITY / 2, DEF_PRIORITY);
|
||||
}
|
||||
|
||||
static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *sc)
|
||||
@@ -7397,6 +7407,7 @@ static bool kswapd_shrink_node(pg_data_t *pgdat,
|
||||
{
|
||||
struct zone *zone;
|
||||
int z;
|
||||
unsigned long nr_reclaimed = sc->nr_reclaimed;
|
||||
|
||||
/* Reclaim a number of pages proportional to the number of zones */
|
||||
sc->nr_to_reclaim = 0;
|
||||
@@ -7424,7 +7435,8 @@ static bool kswapd_shrink_node(pg_data_t *pgdat,
|
||||
if (sc->order && sc->nr_reclaimed >= compact_gap(sc->order))
|
||||
sc->order = 0;
|
||||
|
||||
return sc->nr_scanned >= sc->nr_to_reclaim;
|
||||
/* account for progress from mm_account_reclaimed_pages() */
|
||||
return max(sc->nr_scanned, sc->nr_reclaimed - nr_reclaimed) >= sc->nr_to_reclaim;
|
||||
}
|
||||
|
||||
/* Page allocator PCP high watermark is lowered if reclaim is active. */
|
||||
|
||||
@@ -195,7 +195,7 @@ static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction,
|
||||
return xa_mk_value(eviction);
|
||||
}
|
||||
|
||||
static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
|
||||
void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
|
||||
unsigned long *evictionp, bool *workingsetp)
|
||||
{
|
||||
unsigned long entry = xa_to_value(shadow);
|
||||
@@ -214,6 +214,7 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
|
||||
*evictionp = entry;
|
||||
*workingsetp = workingset;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unpack_shadow);
|
||||
|
||||
#ifdef CONFIG_LRU_GEN
|
||||
|
||||
|
||||
@@ -3632,6 +3632,9 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
|
||||
|
||||
len = skb->len;
|
||||
trace_net_dev_start_xmit(skb, dev);
|
||||
|
||||
trace_android_vh_dc_send_copy(skb, dev);
|
||||
|
||||
rc = netdev_start_xmit(skb, dev, txq, more);
|
||||
trace_net_dev_xmit(skb, rc, dev, len);
|
||||
|
||||
@@ -5331,6 +5334,7 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
|
||||
bool deliver_exact = false;
|
||||
int ret = NET_RX_DROP;
|
||||
__be16 type;
|
||||
int flag = 0;
|
||||
|
||||
net_timestamp_check(!READ_ONCE(netdev_tstamp_prequeue), skb);
|
||||
|
||||
@@ -5350,6 +5354,10 @@ another_round:
|
||||
|
||||
__this_cpu_inc(softnet_data.processed);
|
||||
|
||||
trace_android_vh_dc_receive(skb, &flag);
|
||||
if (flag != 0)
|
||||
return NET_RX_DROP;
|
||||
|
||||
if (static_branch_unlikely(&generic_xdp_needed_key)) {
|
||||
int ret2;
|
||||
|
||||
|
||||
@@ -289,8 +289,26 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
|
||||
return __udp_gso_segment_list(gso_skb, features, is_ipv6);
|
||||
if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) {
|
||||
/* Detect modified geometry and pass those to skb_segment. */
|
||||
if (skb_pagelen(gso_skb) - sizeof(*uh) == skb_shinfo(gso_skb)->gso_size)
|
||||
return __udp_gso_segment_list(gso_skb, features, is_ipv6);
|
||||
|
||||
/* Setup csum, as fraglist skips this in udp4_gro_receive. */
|
||||
gso_skb->csum_start = skb_transport_header(gso_skb) - gso_skb->head;
|
||||
gso_skb->csum_offset = offsetof(struct udphdr, check);
|
||||
gso_skb->ip_summed = CHECKSUM_PARTIAL;
|
||||
|
||||
uh = udp_hdr(gso_skb);
|
||||
if (is_ipv6)
|
||||
uh->check = ~udp_v6_check(gso_skb->len,
|
||||
&ipv6_hdr(gso_skb)->saddr,
|
||||
&ipv6_hdr(gso_skb)->daddr, 0);
|
||||
else
|
||||
uh->check = ~udp_v4_check(gso_skb->len,
|
||||
ip_hdr(gso_skb)->saddr,
|
||||
ip_hdr(gso_skb)->daddr, 0);
|
||||
}
|
||||
|
||||
skb_pull(gso_skb, sizeof(*uh));
|
||||
|
||||
|
||||
@@ -1044,6 +1044,7 @@ void cfg80211_connect_done(struct net_device *dev,
|
||||
cfg80211_hold_bss(
|
||||
bss_from_pub(params->links[link].bss));
|
||||
ev->cr.links[link].bss = params->links[link].bss;
|
||||
ev->cr.links[link].status = params->links[link].status;
|
||||
|
||||
if (params->links[link].addr) {
|
||||
ev->cr.links[link].addr = next;
|
||||
|
||||
Reference in New Issue
Block a user