Merge branch 'android12-5.10' into branch 'android12-5.10-lts'

Sync up with android12-5.10 for the following commits:

fb39cdb9ea ANDROID: export reclaim_pages
1f8f6d59a2 ANDROID: vendor_hook: Add hook to not be stuck ro rmap lock in kswapd or direct_reclaim
91bfc78bc0 ANDROID: Update symbol list for mtk
02df0b2661 ANDROID: GKI: rockchip: Add symbols for crypto
efdf581d14 ANDROID: GKI: rockchip: Add symbol pci_disable_link_state
504ce2d3a6 ANDROID: GKI: rockchip: Add symbols for sound
a6b6bc98b7 ANDROID: GKI: rockchip: Add symbols for video
f3a311b456 BACKPORT: f2fs: do not set compression bit if kernel doesn't support
b0988144b0 UPSTREAM: exfat: improve performance of exfat_free_cluster when using dirsync mount
00d3b8c0cc ANDROID: GKI: rockchip: Add symbols for drm dp
936f1e35d1 UPSTREAM: arm64: perf: Support new DT compatibles
ed931dc8ff UPSTREAM: arm64: perf: Simplify registration boilerplate
bb6c018ab6 UPSTREAM: arm64: perf: Support Denver and Carmel PMUs
d306fd9d47 UPSTREAM: arm64: perf: add support for Cortex-A78
09f78c3f7e ANDROID: GKI: rockchip: Update symbol for devfreq
e7ed66854e ANDROID: GKI: rockchip: Update symbols for drm
a3e70ff5bf ANDROID: GKI: Update symbols to symbol list
a09241c6dd UPSTREAM: ASoC: hdmi-codec: make hdmi_codec_controls static
9eda09e511 UPSTREAM: ASoC: hdmi-codec: Add a prepare hook
4ad97b395f UPSTREAM: ASoC: hdmi-codec: Add iec958 controls
c0c2f6962d UPSTREAM: ASoC: hdmi-codec: Rework to support more controls
4c6eb3db8a UPSTREAM: ALSA: iec958: Split status creation and fill
580d2e7c78 UPSTREAM: ALSA: doc: Clarify IEC958 controls iface
8b4bb1bca0 UPSTREAM: ASoC: hdmi-codec: remove unused spk_mask member
5a2c4a5d1e UPSTREAM: ASoC: hdmi-codec: remove useless initialization
49e502f0c0 UPSTREAM: ASoC: codec: hdmi-codec: Support IEC958 encoded PCM format
9bf69acb92 UPSTREAM: ASoC: hdmi-codec: Fix return value in hdmi_codec_set_jack()
056409c7dc UPSTREAM: ASoC: hdmi-codec: Add RX support
5e75deab3a UPSTREAM: ASoC: hdmi-codec: Get ELD in before reporting plugged event
d6207c39cb ANDROID: GKI: rockchip: Add symbols for display driver
1c3ed9d481 BACKPORT: KVM: x86/mmu: fix NULL pointer dereference on guest INVPCID
843d3cb41b BACKPORT: io_uring: always grab file table for deferred statx
784cc16aed BACKPORT: Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put
2b377175a3 ANDROID: add two func in mm/memcontrol.c
e56f8712cf ANDROID: vendor_hooks: protect multi-mapcount pages in kernel
3f775b9367 ANDROID: vendor_hooks: account page-mapcount
1d2287f56e FROMGIT: io_uring: Use original task for req identity in io_identity_cow()
e0c9da25b2 FROMLIST: binder: fix UAF of ref->proc caused by race condition
12f4322442 ANDROID: vendor_hooks: Guard cgroup struct with CONFIG_CGROUPS
6532784c78 ANDROID: vendor_hooks: add hooks for remove_vm_area.
c9a70dd592 ANDROID: GKI: allow mm vendor hooks header inclusion from header files
039080d064 ANDROID: Update symbol list of mediatek
9e8dedef1e ANDROID: sched: add vendor hook to PELT multiplier
573c7f061d ANDROID: Guard hooks with their CONFIG_ options
14f646cca5 ANDROID: fix kernelci issue for allnoconfig builds
4442801a43 ANDROID: sched: Introducing PELT multiplier
b2e5773ea4 FROMGIT: binder: fix redefinition of seq_file attributes
9c2a5eef8f Merge tag 'android12-5.10.117_r00' into 'android12-5.10'
5fa1e1affc ANDROID: GKI: pcie: Fix the broken dw_pcie structure
51b3e17071 UPSTREAM: PCI: dwc: Support multiple ATU memory regions
a8d7f6518e ANDROID: oplus: Update the ABI xml and symbol list
4536de1b70 ANDROID: vendor_hooks: add hooks in __alloc_pages_slowpath
d63c961c9d ANDROID: GKI: Update symbols to symbol list
41cbbe08f9 FROMGIT: arm64: fix oops in concurrently setting insn_emulation sysctls
c301d142e8 FROMGIT: usb: dwc3: core: Do not perform GCTL_CORE_SOFTRESET during bootup
8b19ed264b ANDROID: vendor_hooks:vendor hook for mmput
242b11e574 ANDROID: vendor_hooks:vendor hook for pidfd_open
0e1cb27700 ANDROID: vendor_hook: Add hook in shmem_writepage()
8ee37d0bcd BACKPORT: iommu/dma: Fix race condition during iova_domain initialization
321bf845e1 FROMGIT: usb: dwc3: core: Deprecate GCTL.CORESOFTRESET
c5eb0edfde FROMGIT: usb: dwc3: gadget: Prevent repeat pullup()
8de633b735 FROMGIT: Binder: add TF_UPDATE_TXN to replace outdated txn
e8fce59434 BACKPORT: FROMGIT: cgroup: Use separate src/dst nodes when preloading css_sets for migration
f26c566455 UPSTREAM: usb: gadget: f_uac2: allow changing interface name via configfs
98fa7f7dfd UPSTREAM: usb: gadget: f_uac1: allow changing interface name via configfs
29172165ca UPSTREAM: usb: gadget: f_uac1: Add suspend callback
ff5468c71e UPSTREAM: usb: gadget: f_uac2: Add suspend callback
31e6d620c1 UPSTREAM: usb: gadget: u_audio: Add suspend call
17643c1fdd UPSTREAM: usb: gadget: u_audio: Rate ctl notifies about current srate (0=stopped)
308955e3a6 UPSTREAM: usb: gadget: f_uac1: Support multiple sampling rates
ae03eadb42 UPSTREAM: usb: gadget: f_uac2: Support multiple sampling rates
bedc53fae4 UPSTREAM: usb: gadget:audio: Replace deprecated macro S_IRUGO
37e0d5eddb UPSTREAM: usb: gadget: u_audio: Add capture/playback srate getter
3251bb3250 UPSTREAM: usb: gadget: u_audio: Move dynamic srate from params to rtd
530916be97 UPSTREAM: usb: gadget: u_audio: Support multiple sampling rates
7f496d5a99 UPSTREAM: docs: ABI: fixed formatting in configfs-usb-gadget-uac2
2500cb53e6 UPSTREAM: usb: gadget: u_audio: Subdevice 0 for capture ctls
c386f34bd4 UPSTREAM: usb: gadget: u_audio: fix calculations for small bInterval
f74e3e2fe4 UPSTREAM: docs: ABI: fixed req_number desc in UAC1
02949bae5c UPSTREAM: docs: ABI: added missing num_requests param to UAC2
e1377ac38f UPSTREAM: usb:gadget: f_uac1: fixed sync playback
4b7c8905c5 UPSTREAM: usb: gadget: u_audio.c: Adding Playback Pitch ctl for sync playback
e29d2b5178 UPSTREAM: ABI: configfs-usb-gadget-uac2: fix a broken table
ec313ae88d UPSTREAM: ABI: configfs-usb-gadget-uac1: fix a broken table
bf46bbe087 UPSTREAM: usb: gadget: f_uac1: fixing inconsistent indenting
b9c4cbbf7a UPSTREAM: docs: usb: fix malformed table
a380b466e0 UPSTREAM: usb: gadget: f_uac1: add volume and mute support
e2c0816af2 BACKPORT: usb: gadget: f_uac2: add volume and mute support
8430eb0243 UPSTREAM: usb: gadget: u_audio: add bi-directional volume and mute support
257d21b184 UPSTREAM: usb: audio-v2: add ability to define feature unit descriptor
1002747429 ANDROID: mm: shmem: use reclaim_pages() to recalim pages from a list
6719763187 UPSTREAM: usb: gadget: f_uac1: disable IN/OUT ep if unused

And add the new symbols being tracked due to abi additions from the
android12-5.10 branch:

Leaf changes summary: 85 artifacts changed
Changed leaf types summary: 0 leaf type changed
Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 69 Added functions
Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 16 Added variables

69 Added functions:

  [A] 'function void __dev_kfree_skb_irq(sk_buff*, skb_free_reason)'
  [A] 'function int __page_mapcount(page*)'
  [A] 'function int __traceiter_android_vh_add_page_to_lrulist(void*, page*, bool, lru_list)'
  [A] 'function int __traceiter_android_vh_alloc_pages_slowpath_begin(void*, gfp_t, unsigned int, unsigned long int*)'
  [A] 'function int __traceiter_android_vh_alloc_pages_slowpath_end(void*, gfp_t, unsigned int, unsigned long int)'
  [A] 'function int __traceiter_android_vh_del_page_from_lrulist(void*, page*, bool, lru_list)'
  [A] 'function int __traceiter_android_vh_do_traversal_lruvec(void*, lruvec*)'
  [A] 'function int __traceiter_android_vh_mark_page_accessed(void*, page*)'
  [A] 'function int __traceiter_android_vh_mutex_unlock_slowpath_end(void*, mutex*, task_struct*)'
  [A] 'function int __traceiter_android_vh_page_should_be_protected(void*, page*, bool*)'
  [A] 'function int __traceiter_android_vh_rwsem_mark_wake_readers(void*, rw_semaphore*, rwsem_waiter*)'
  [A] 'function int __traceiter_android_vh_rwsem_set_owner(void*, rw_semaphore*)'
  [A] 'function int __traceiter_android_vh_rwsem_set_reader_owned(void*, rw_semaphore*)'
  [A] 'function int __traceiter_android_vh_rwsem_up_read_end(void*, rw_semaphore*)'
  [A] 'function int __traceiter_android_vh_rwsem_up_write_end(void*, rw_semaphore*)'
  [A] 'function int __traceiter_android_vh_sched_pelt_multiplier(void*, unsigned int, unsigned int, int*)'
  [A] 'function int __traceiter_android_vh_show_mapcount_pages(void*, void*)'
  [A] 'function int __traceiter_android_vh_update_page_mapcount(void*, page*, bool, bool, bool*, bool*)'
  [A] 'function int __v4l2_ctrl_handler_setup(v4l2_ctrl_handler*)'
  [A] 'function int crypto_ahash_final(ahash_request*)'
  [A] 'function crypto_akcipher* crypto_alloc_akcipher(const char*, u32, u32)'
  [A] 'function int crypto_register_akcipher(akcipher_alg*)'
  [A] 'function void crypto_unregister_akcipher(akcipher_alg*)'
  [A] 'function int des_expand_key(des_ctx*, const u8*, unsigned int)'
  [A] 'function void dev_pm_opp_unregister_set_opp_helper(opp_table*)'
  [A] 'function net_device* devm_alloc_etherdev_mqs(device*, int, unsigned int, unsigned int)'
  [A] 'function mii_bus* devm_mdiobus_alloc_size(device*, int)'
  [A] 'function int devm_of_mdiobus_register(device*, mii_bus*, device_node*)'
  [A] 'function int devm_register_netdev(device*, net_device*)'
  [A] 'function bool disable_hardirq(unsigned int)'
  [A] 'function void do_traversal_all_lruvec()'
  [A] 'function drm_connector_status drm_bridge_detect(drm_bridge*)'
  [A] 'function edid* drm_bridge_get_edid(drm_bridge*, drm_connector*)'
  [A] 'function int drm_bridge_get_modes(drm_bridge*, drm_connector*)'
  [A] 'function int drm_dp_get_phy_test_pattern(drm_dp_aux*, drm_dp_phy_test_params*)'
  [A] 'function int drm_dp_read_desc(drm_dp_aux*, drm_dp_desc*, bool)'
  [A] 'function int drm_dp_read_dpcd_caps(drm_dp_aux*, u8*)'
  [A] 'function int drm_dp_read_sink_count(drm_dp_aux*)'
  [A] 'function int drm_dp_set_phy_test_pattern(drm_dp_aux*, drm_dp_phy_test_params*, u8)'
  [A] 'function uint64_t drm_format_info_min_pitch(const drm_format_info*, int, unsigned int)'
  [A] 'function int drm_mm_reserve_node(drm_mm*, drm_mm_node*)'
  [A] 'function bool drm_probe_ddc(i2c_adapter*)'
  [A] 'function void drm_self_refresh_helper_cleanup(drm_crtc*)'
  [A] 'function int drm_self_refresh_helper_init(drm_crtc*)'
  [A] 'function int get_pelt_halflife()'
  [A] 'function ssize_t hdmi_avi_infoframe_pack_only(const hdmi_avi_infoframe*, void*, size_t)'
  [A] 'function ssize_t iio_read_const_attr(device*, device_attribute*, char*)'
  [A] 'function bool mipi_dsi_packet_format_is_short(u8)'
  [A] 'function platform_device* of_device_alloc(device_node*, const char*, device*)'
  [A] 'function lruvec* page_to_lruvec(page*, pg_data_t*)'
  [A] 'function int pci_disable_link_state(pci_dev*, int)'
  [A] 'function int regmap_test_bits(regmap*, unsigned int, unsigned int)'
  [A] 'function unsigned int regulator_get_linear_step(regulator*)'
  [A] 'function int regulator_suspend_enable(regulator_dev*, suspend_state_t)'
  [A] 'function int rsa_parse_priv_key(rsa_key*, void*, unsigned int)'
  [A] 'function int rsa_parse_pub_key(rsa_key*, void*, unsigned int)'
  [A] 'function int sg_nents(scatterlist*)'
  [A] 'function int snd_pcm_create_iec958_consumer_default(u8*, size_t)'
  [A] 'function int snd_pcm_fill_iec958_consumer(snd_pcm_runtime*, u8*, size_t)'
  [A] 'function int snd_pcm_fill_iec958_consumer_hw_params(snd_pcm_hw_params*, u8*, size_t)'
  [A] 'function int snd_soc_dapm_force_bias_level(snd_soc_dapm_context*, snd_soc_bias_level)'
  [A] 'function int snd_soc_jack_add_zones(snd_soc_jack*, int, snd_soc_jack_zone*)'
  [A] 'function int snd_soc_jack_get_type(snd_soc_jack*, int)'
  [A] 'function void tcpm_tcpc_reset(tcpm_port*)'
  [A] 'function int v4l2_enum_dv_timings_cap(v4l2_enum_dv_timings*, const v4l2_dv_timings_cap*, v4l2_check_dv_timings_fnc*, void*)'
  [A] 'function void v4l2_print_dv_timings(const char*, const char*, const v4l2_dv_timings*, bool)'
  [A] 'function int v4l2_src_change_event_subdev_subscribe(v4l2_subdev*, v4l2_fh*, v4l2_event_subscription*)'
  [A] 'function void v4l2_subdev_notify_event(v4l2_subdev*, const v4l2_event*)'
  [A] 'function bool v4l2_valid_dv_timings(const v4l2_dv_timings*, const v4l2_dv_timings_cap*, v4l2_check_dv_timings_fnc*, void*)'

16 Added variables:

  [A] 'tracepoint __tracepoint_android_vh_add_page_to_lrulist'
  [A] 'tracepoint __tracepoint_android_vh_alloc_pages_slowpath_begin'
  [A] 'tracepoint __tracepoint_android_vh_alloc_pages_slowpath_end'
  [A] 'tracepoint __tracepoint_android_vh_del_page_from_lrulist'
  [A] 'tracepoint __tracepoint_android_vh_do_traversal_lruvec'
  [A] 'tracepoint __tracepoint_android_vh_mark_page_accessed'
  [A] 'tracepoint __tracepoint_android_vh_mutex_unlock_slowpath_end'
  [A] 'tracepoint __tracepoint_android_vh_page_should_be_protected'
  [A] 'tracepoint __tracepoint_android_vh_rwsem_mark_wake_readers'
  [A] 'tracepoint __tracepoint_android_vh_rwsem_set_owner'
  [A] 'tracepoint __tracepoint_android_vh_rwsem_set_reader_owned'
  [A] 'tracepoint __tracepoint_android_vh_rwsem_up_read_end'
  [A] 'tracepoint __tracepoint_android_vh_rwsem_up_write_end'
  [A] 'tracepoint __tracepoint_android_vh_sched_pelt_multiplier'
  [A] 'tracepoint __tracepoint_android_vh_show_mapcount_pages'
  [A] 'tracepoint __tracepoint_android_vh_update_page_mapcount'

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I47eefe85b949d3f358da95a9b6553660b9be0791
This commit is contained in:
Greg Kroah-Hartman
2022-08-16 12:45:36 +02:00
76 changed files with 8856 additions and 4241 deletions

View File

@@ -4,13 +4,30 @@ KernelVersion: 4.14
Description: Description:
The attributes: The attributes:
========== =================================== ===================== =======================================
c_chmask capture channel mask c_chmask capture channel mask
c_srate capture sampling rate c_srate list of capture sampling rates (comma-separated)
c_ssize capture sample size (bytes) c_ssize capture sample size (bytes)
c_mute_present capture mute control enable
c_volume_present capture volume control enable
c_volume_min capture volume control min value
(in 1/256 dB)
c_volume_max capture volume control max value
(in 1/256 dB)
c_volume_res capture volume control resolution
(in 1/256 dB)
p_chmask playback channel mask p_chmask playback channel mask
p_srate playback sampling rate p_srate list of playback sampling rates (comma-separated)
p_ssize playback sample size (bytes) p_ssize playback sample size (bytes)
req_number the number of pre-allocated request p_mute_present playback mute control enable
p_volume_present playback volume control enable
p_volume_min playback volume control min value
(in 1/256 dB)
p_volume_max playback volume control max value
(in 1/256 dB)
p_volume_res playback volume control resolution
(in 1/256 dB)
req_number the number of pre-allocated requests
for both capture and playback for both capture and playback
========== =================================== function_name name of the interface
===================== =======================================

View File

@@ -4,13 +4,33 @@ KernelVersion: 3.18
Description: Description:
The attributes: The attributes:
========= ============================ ===================== =======================================
c_chmask capture channel mask c_chmask capture channel mask
c_srate capture sampling rate c_srate list of capture sampling rates (comma-separated)
c_ssize capture sample size (bytes) c_ssize capture sample size (bytes)
c_sync capture synchronization type (async/adaptive) c_sync capture synchronization type
(async/adaptive)
c_mute_present capture mute control enable
c_volume_present capture volume control enable
c_volume_min capture volume control min value
(in 1/256 dB)
c_volume_max capture volume control max value
(in 1/256 dB)
c_volume_res capture volume control resolution
(in 1/256 dB)
fb_max maximum extra bandwidth in async mode fb_max maximum extra bandwidth in async mode
p_chmask playback channel mask p_chmask playback channel mask
p_srate playback sampling rate p_srate list of playback sampling rates (comma-separated)
p_ssize playback sample size (bytes) p_ssize playback sample size (bytes)
========= ============================ p_mute_present playback mute control enable
p_volume_present playback volume control enable
p_volume_min playback volume control min value
(in 1/256 dB)
p_volume_max playback volume control max value
(in 1/256 dB)
p_volume_res playback volume control resolution
(in 1/256 dB)
req_number the number of pre-allocated requests
for both capture and playback
function_name name of the interface
===================== =======================================

View File

@@ -3508,14 +3508,15 @@ field must be set, though).
“IEC958 Playback Con Mask” is used to return the bit-mask for the IEC958 “IEC958 Playback Con Mask” is used to return the bit-mask for the IEC958
status bits of consumer mode. Similarly, “IEC958 Playback Pro Mask” status bits of consumer mode. Similarly, “IEC958 Playback Pro Mask”
returns the bitmask for professional mode. They are read-only controls, returns the bitmask for professional mode. They are read-only controls.
and are defined as MIXER controls (iface =
``SNDRV_CTL_ELEM_IFACE_MIXER``).
Meanwhile, “IEC958 Playback Default” control is defined for getting and Meanwhile, “IEC958 Playback Default” control is defined for getting and
setting the current default IEC958 bits. Note that this one is usually setting the current default IEC958 bits.
defined as a PCM control (iface = ``SNDRV_CTL_ELEM_IFACE_PCM``),
although in some places it's defined as a MIXER control. Due to historical reasons, both variants of the Playback Mask and the
Playback Default controls can be implemented on either a
``SNDRV_CTL_ELEM_IFACE_PCM`` or a ``SNDRV_CTL_ELEM_IFACE_MIXER`` iface.
Drivers should expose the mask and default on the same iface though.
In addition, you can define the control switches to enable/disable or to In addition, you can define the control switches to enable/disable or to
set the raw bit mode. The implementation will depend on the chip, but set the raw bit mode. The implementation will depend on the chip, but

View File

@@ -724,18 +724,29 @@ Function-specific configfs interface
The function name to use when creating the function directory is "uac2". The function name to use when creating the function directory is "uac2".
The uac2 function provides these attributes in its function directory: The uac2 function provides these attributes in its function directory:
=============== ==================================================== ================ ====================================================
c_chmask capture channel mask c_chmask capture channel mask
c_srate capture sampling rate c_srate list of capture sampling rates (comma-separated)
c_ssize capture sample size (bytes) c_ssize capture sample size (bytes)
c_sync capture synchronization type (async/adaptive) c_sync capture synchronization type (async/adaptive)
c_mute_present capture mute control enable
c_volume_present capture volume control enable
c_volume_min capture volume control min value (in 1/256 dB)
c_volume_max capture volume control max value (in 1/256 dB)
c_volume_res capture volume control resolution (in 1/256 dB)
fb_max maximum extra bandwidth in async mode fb_max maximum extra bandwidth in async mode
p_chmask playback channel mask p_chmask playback channel mask
p_srate playback sampling rate p_srate list of playback sampling rates (comma-separated)
p_ssize playback sample size (bytes) p_ssize playback sample size (bytes)
p_mute_present playback mute control enable
p_volume_present playback volume control enable
p_volume_min playback volume control min value (in 1/256 dB)
p_volume_max playback volume control max value (in 1/256 dB)
p_volume_res playback volume control resolution (in 1/256 dB)
req_number the number of pre-allocated request for both capture req_number the number of pre-allocated request for both capture
and playback and playback
=============== ==================================================== function_name name of the interface
================ ====================================================
The attributes have sane default values. The attributes have sane default values.
@@ -905,16 +916,27 @@ Function-specific configfs interface
The function name to use when creating the function directory is "uac1". The function name to use when creating the function directory is "uac1".
The uac1 function provides these attributes in its function directory: The uac1 function provides these attributes in its function directory:
========== ==================================================== ================ ====================================================
c_chmask capture channel mask c_chmask capture channel mask
c_srate capture sampling rate c_srate list of capture sampling rates (comma-separated)
c_ssize capture sample size (bytes) c_ssize capture sample size (bytes)
c_mute_present capture mute control enable
c_volume_present capture volume control enable
c_volume_min capture volume control min value (in 1/256 dB)
c_volume_max capture volume control max value (in 1/256 dB)
c_volume_res capture volume control resolution (in 1/256 dB)
p_chmask playback channel mask p_chmask playback channel mask
p_srate playback sampling rate p_srate list of playback sampling rates (comma-separated)
p_ssize playback sample size (bytes) p_ssize playback sample size (bytes)
req_number the number of pre-allocated request for both capture p_mute_present playback mute control enable
p_volume_present playback volume control enable
p_volume_min playback volume control min value (in 1/256 dB)
p_volume_max playback volume control max value (in 1/256 dB)
p_volume_res playback volume control resolution (in 1/256 dB)
req_number the number of pre-allocated requests for both capture
and playback and playback
========== ==================================================== function_name name of the interface
================ ====================================================
The attributes have sane default values. The attributes have sane default values.

File diff suppressed because it is too large Load Diff

View File

@@ -371,7 +371,10 @@
device_unregister device_unregister
_dev_info _dev_info
__dev_kfree_skb_any __dev_kfree_skb_any
__dev_kfree_skb_irq
devm_add_action
__devm_alloc_percpu __devm_alloc_percpu
devm_alloc_etherdev_mqs
devm_blk_ksm_init devm_blk_ksm_init
devm_clk_bulk_get devm_clk_bulk_get
devm_clk_bulk_get_optional devm_clk_bulk_get_optional
@@ -412,11 +415,13 @@
devm_led_classdev_register_ext devm_led_classdev_register_ext
devm_led_classdev_unregister devm_led_classdev_unregister
devm_mbox_controller_register devm_mbox_controller_register
devm_mdiobus_alloc_size
devm_memremap devm_memremap
devm_mfd_add_devices devm_mfd_add_devices
devm_nvmem_cell_get devm_nvmem_cell_get
devm_nvmem_device_get devm_nvmem_device_get
devm_nvmem_register devm_nvmem_register
devm_of_mdiobus_register
devm_of_phy_get_by_index devm_of_phy_get_by_index
__devm_of_phy_provider_register __devm_of_phy_provider_register
devm_of_platform_populate devm_of_platform_populate
@@ -433,6 +438,7 @@
devm_power_supply_register devm_power_supply_register
devm_rc_allocate_device devm_rc_allocate_device
devm_rc_register_device devm_rc_register_device
devm_register_netdev
devm_regmap_add_irq_chip devm_regmap_add_irq_chip
devm_regmap_field_alloc devm_regmap_field_alloc
devm_regmap_field_bulk_alloc devm_regmap_field_bulk_alloc
@@ -584,6 +590,7 @@
down_write down_write
d_path d_path
dput dput
dql_completed
drain_workqueue drain_workqueue
driver_create_file driver_create_file
driver_remove_file driver_remove_file
@@ -809,7 +816,13 @@
genlmsg_put genlmsg_put
genl_register_family genl_register_family
genl_unregister_family genl_unregister_family
__genphy_config_aneg
genphy_read_abilities
genphy_read_mmd_unsupported
genphy_read_status
genphy_resume genphy_resume
genphy_suspend
genphy_write_mmd_unsupported
gen_pool_add_owner gen_pool_add_owner
gen_pool_alloc_algo_owner gen_pool_alloc_algo_owner
gen_pool_avail gen_pool_avail
@@ -835,6 +848,7 @@
get_kernel_pages get_kernel_pages
get_net_ns_by_fd get_net_ns_by_fd
get_net_ns_by_pid get_net_ns_by_pid
get_pelt_halflife
get_pid_task get_pid_task
get_random_bytes get_random_bytes
get_random_u32 get_random_u32
@@ -957,11 +971,13 @@
init_uts_ns init_uts_ns
init_wait_entry init_wait_entry
__init_waitqueue_head __init_waitqueue_head
input_alloc_absinfo
input_allocate_device input_allocate_device
input_event input_event
input_free_device input_free_device
input_mt_init_slots input_mt_init_slots
input_mt_report_slot_state input_mt_report_slot_state
input_mt_sync_frame
input_register_device input_register_device
input_set_abs_params input_set_abs_params
input_set_capability input_set_capability
@@ -1169,8 +1185,12 @@
mbox_send_message mbox_send_message
mdiobus_alloc_size mdiobus_alloc_size
mdiobus_free mdiobus_free
__mdiobus_read
mdiobus_read
__mdiobus_register __mdiobus_register
mdiobus_unregister mdiobus_unregister
__mdiobus_write
mdiobus_write
media_create_intf_link media_create_intf_link
media_create_pad_link media_create_pad_link
media_device_cleanup media_device_cleanup
@@ -1270,10 +1290,12 @@
mutex_lock_killable mutex_lock_killable
mutex_trylock mutex_trylock
mutex_unlock mutex_unlock
napi_complete_done
napi_disable napi_disable
napi_gro_flush napi_gro_flush
napi_gro_receive napi_gro_receive
__napi_schedule __napi_schedule
__napi_schedule_irqoff
napi_schedule_prep napi_schedule_prep
__ndelay __ndelay
nd_tbl nd_tbl
@@ -1292,6 +1314,7 @@
netif_receive_skb_list netif_receive_skb_list
netif_rx netif_rx
netif_rx_ni netif_rx_ni
netif_schedule_queue
netif_tx_stop_all_queues netif_tx_stop_all_queues
netif_tx_wake_queue netif_tx_wake_queue
netlink_broadcast netlink_broadcast
@@ -1372,6 +1395,7 @@
of_get_next_child of_get_next_child
of_get_next_parent of_get_next_parent
of_get_parent of_get_parent
of_get_phy_mode
of_get_property of_get_property
of_get_regulator_init_data of_get_regulator_init_data
of_graph_get_next_endpoint of_graph_get_next_endpoint
@@ -1392,6 +1416,7 @@
of_parse_phandle_with_fixed_args of_parse_phandle_with_fixed_args
of_phandle_iterator_init of_phandle_iterator_init
of_phandle_iterator_next of_phandle_iterator_next
of_phy_connect
of_phy_simple_xlate of_phy_simple_xlate
of_platform_depopulate of_platform_depopulate
of_platform_device_create of_platform_device_create
@@ -1459,19 +1484,29 @@
phy_connect phy_connect
phy_disconnect phy_disconnect
phy_do_ioctl_running phy_do_ioctl_running
phy_drivers_register
phy_drivers_unregister
phy_ethtool_get_link_ksettings phy_ethtool_get_link_ksettings
phy_ethtool_nway_reset phy_ethtool_nway_reset
phy_ethtool_set_link_ksettings phy_ethtool_set_link_ksettings
phy_exit phy_exit
phy_get phy_get
phy_init phy_init
phy_mii_ioctl
__phy_modify
phy_modify
phy_modify_paged_changed
phy_power_off phy_power_off
phy_power_on phy_power_on
phy_print_status phy_print_status
phy_put phy_put
phy_read_paged
phy_restore_page
phy_select_page
phy_set_mode_ext phy_set_mode_ext
phy_start phy_start
phy_stop phy_stop
phy_write_paged
pid_task pid_task
pinconf_generic_parse_dt_config pinconf_generic_parse_dt_config
pinctrl_dev_get_drvdata pinctrl_dev_get_drvdata
@@ -1660,6 +1695,7 @@
regmap_raw_read regmap_raw_read
regmap_raw_write regmap_raw_write
regmap_read regmap_read
regmap_test_bits
regmap_update_bits_base regmap_update_bits_base
regmap_write regmap_write
regulator_count_voltages regulator_count_voltages
@@ -2091,6 +2127,8 @@
timer_unstable_counter_workaround timer_unstable_counter_workaround
topology_set_thermal_pressure topology_set_thermal_pressure
_totalram_pages _totalram_pages
touchscreen_parse_properties
touchscreen_report_pos
__trace_bprintk __trace_bprintk
__trace_bputs __trace_bputs
trace_event_buffer_commit trace_event_buffer_commit
@@ -2153,6 +2191,7 @@
__traceiter_android_vh_rwsem_init __traceiter_android_vh_rwsem_init
__traceiter_android_vh_rwsem_wake __traceiter_android_vh_rwsem_wake
__traceiter_android_vh_rwsem_write_finished __traceiter_android_vh_rwsem_write_finished
__traceiter_android_vh_sched_pelt_multiplier
__traceiter_android_vh_scheduler_tick __traceiter_android_vh_scheduler_tick
__traceiter_android_vh_selinux_avc_insert __traceiter_android_vh_selinux_avc_insert
__traceiter_android_vh_selinux_avc_lookup __traceiter_android_vh_selinux_avc_lookup
@@ -2237,6 +2276,7 @@
__tracepoint_android_vh_rwsem_init __tracepoint_android_vh_rwsem_init
__tracepoint_android_vh_rwsem_wake __tracepoint_android_vh_rwsem_wake
__tracepoint_android_vh_rwsem_write_finished __tracepoint_android_vh_rwsem_write_finished
__tracepoint_android_vh_sched_pelt_multiplier
__tracepoint_android_vh_scheduler_tick __tracepoint_android_vh_scheduler_tick
__tracepoint_android_vh_selinux_avc_insert __tracepoint_android_vh_selinux_avc_insert
__tracepoint_android_vh_selinux_avc_lookup __tracepoint_android_vh_selinux_avc_lookup
@@ -2790,10 +2830,13 @@
fwnode_graph_parse_endpoint fwnode_graph_parse_endpoint
fwnode_property_get_reference_args fwnode_property_get_reference_args
fwnode_property_read_u64_array fwnode_property_read_u64_array
gen_pool_avail
gen_pool_dma_alloc_align gen_pool_dma_alloc_align
gen_pool_has_addr gen_pool_has_addr
gen_pool_size
getboottime64 getboottime64
get_governor_parent_kobj get_governor_parent_kobj
get_pelt_halflife
get_task_exe_file get_task_exe_file
get_vaddr_frames get_vaddr_frames
get_zeroed_page get_zeroed_page
@@ -3070,6 +3113,7 @@
__traceiter_android_vh_rwsem_init __traceiter_android_vh_rwsem_init
__traceiter_android_vh_rwsem_wake __traceiter_android_vh_rwsem_wake
__traceiter_android_vh_rwsem_write_finished __traceiter_android_vh_rwsem_write_finished
__traceiter_android_vh_sched_pelt_multiplier
__traceiter_android_vh_scmi_timeout_sync __traceiter_android_vh_scmi_timeout_sync
__traceiter_android_vh_show_resume_epoch_val __traceiter_android_vh_show_resume_epoch_val
__traceiter_android_vh_show_suspend_epoch_val __traceiter_android_vh_show_suspend_epoch_val
@@ -3123,6 +3167,7 @@
__tracepoint_android_vh_rwsem_init __tracepoint_android_vh_rwsem_init
__tracepoint_android_vh_rwsem_wake __tracepoint_android_vh_rwsem_wake
__tracepoint_android_vh_rwsem_write_finished __tracepoint_android_vh_rwsem_write_finished
__tracepoint_android_vh_sched_pelt_multiplier
__tracepoint_android_vh_scmi_timeout_sync __tracepoint_android_vh_scmi_timeout_sync
__tracepoint_android_vh_show_resume_epoch_val __tracepoint_android_vh_show_resume_epoch_val
__tracepoint_android_vh_show_suspend_epoch_val __tracepoint_android_vh_show_suspend_epoch_val
@@ -3193,6 +3238,7 @@
usb_otg_state_string usb_otg_state_string
usb_phy_set_charger_current usb_phy_set_charger_current
usb_remove_phy usb_remove_phy
usb_role_switch_set_role
v4l2_async_notifier_add_subdev v4l2_async_notifier_add_subdev
v4l2_async_notifier_cleanup v4l2_async_notifier_cleanup
v4l2_async_subdev_notifier_register v4l2_async_subdev_notifier_register

View File

@@ -681,6 +681,7 @@
dma_unmap_sg_attrs dma_unmap_sg_attrs
do_exit do_exit
do_wait_intr_irq do_wait_intr_irq
do_traversal_all_lruvec
down down
down_interruptible down_interruptible
down_read down_read
@@ -1802,10 +1803,12 @@
page_endio page_endio
__page_file_index __page_file_index
__page_file_mapping __page_file_mapping
__page_mapcount
page_get_link page_get_link
page_mapping page_mapping
__page_pinner_migration_failed __page_pinner_migration_failed
page_symlink page_symlink
page_to_lruvec
panic panic
panic_notifier_list panic_notifier_list
panic_timeout panic_timeout
@@ -2802,6 +2805,7 @@
__traceiter_android_vh_ipi_stop __traceiter_android_vh_ipi_stop
__traceiter_android_vh_ipv6_gen_linklocal_addr __traceiter_android_vh_ipv6_gen_linklocal_addr
__traceiter_android_vh_jiffies_update __traceiter_android_vh_jiffies_update
__traceiter_android_vh_killed_process
__traceiter_android_vh_kmalloc_slab __traceiter_android_vh_kmalloc_slab
__traceiter_android_vh_logbuf __traceiter_android_vh_logbuf
__traceiter_android_vh_mem_cgroup_alloc __traceiter_android_vh_mem_cgroup_alloc
@@ -2810,19 +2814,33 @@
__traceiter_android_vh_mem_cgroup_free __traceiter_android_vh_mem_cgroup_free
__traceiter_android_vh_mem_cgroup_id_remove __traceiter_android_vh_mem_cgroup_id_remove
__traceiter_android_vh_meminfo_proc_show __traceiter_android_vh_meminfo_proc_show
__traceiter_android_vh_alloc_pages_slowpath_begin
__traceiter_android_vh_alloc_pages_slowpath_end
__traceiter_android_vh_mutex_unlock_slowpath __traceiter_android_vh_mutex_unlock_slowpath
__traceiter_android_vh_mutex_unlock_slowpath_end
__traceiter_android_vh_mutex_wait_finish __traceiter_android_vh_mutex_wait_finish
__traceiter_android_vh_mutex_wait_start __traceiter_android_vh_mutex_wait_start
__traceiter_android_vh_override_creds __traceiter_android_vh_override_creds
__traceiter_android_vh_page_referenced_check_bypass __traceiter_android_vh_page_referenced_check_bypass
__traceiter_android_vh_page_should_be_protected
__traceiter_android_vh_mark_page_accessed
__traceiter_android_vh_show_mapcount_pages
__traceiter_android_vh_do_traversal_lruvec
__traceiter_android_vh_update_page_mapcount
__traceiter_android_vh_add_page_to_lrulist
__traceiter_android_vh_del_page_from_lrulist
__traceiter_android_vh_pcplist_add_cma_pages_bypass __traceiter_android_vh_pcplist_add_cma_pages_bypass
__traceiter_android_vh_prepare_update_load_avg_se __traceiter_android_vh_prepare_update_load_avg_se
__traceiter_android_vh_printk_hotplug __traceiter_android_vh_printk_hotplug
__traceiter_android_vh_process_killed __traceiter_android_vh_process_killed
__traceiter_android_vh_killed_process
__traceiter_android_vh_revert_creds __traceiter_android_vh_revert_creds
__traceiter_android_vh_rmqueue __traceiter_android_vh_rmqueue
__traceiter_android_vh_rwsem_init __traceiter_android_vh_rwsem_init
__traceiter_android_vh_rwsem_mark_wake_readers
__traceiter_android_vh_rwsem_set_owner
__traceiter_android_vh_rwsem_set_reader_owned
__traceiter_android_vh_rwsem_up_read_end
__traceiter_android_vh_rwsem_up_write_end
__traceiter_android_vh_rwsem_wake __traceiter_android_vh_rwsem_wake
__traceiter_android_vh_rwsem_wake_finish __traceiter_android_vh_rwsem_wake_finish
__traceiter_android_vh_rwsem_write_finished __traceiter_android_vh_rwsem_write_finished
@@ -3010,6 +3028,7 @@
__tracepoint_android_vh_ipi_stop __tracepoint_android_vh_ipi_stop
__tracepoint_android_vh_ipv6_gen_linklocal_addr __tracepoint_android_vh_ipv6_gen_linklocal_addr
__tracepoint_android_vh_jiffies_update __tracepoint_android_vh_jiffies_update
__tracepoint_android_vh_killed_process
__tracepoint_android_vh_kmalloc_slab __tracepoint_android_vh_kmalloc_slab
__tracepoint_android_vh_logbuf __tracepoint_android_vh_logbuf
__tracepoint_android_vh_mem_cgroup_alloc __tracepoint_android_vh_mem_cgroup_alloc
@@ -3018,19 +3037,33 @@
__tracepoint_android_vh_mem_cgroup_free __tracepoint_android_vh_mem_cgroup_free
__tracepoint_android_vh_mem_cgroup_id_remove __tracepoint_android_vh_mem_cgroup_id_remove
__tracepoint_android_vh_meminfo_proc_show __tracepoint_android_vh_meminfo_proc_show
__tracepoint_android_vh_alloc_pages_slowpath_begin
__tracepoint_android_vh_alloc_pages_slowpath_end
__tracepoint_android_vh_mutex_unlock_slowpath __tracepoint_android_vh_mutex_unlock_slowpath
__tracepoint_android_vh_mutex_unlock_slowpath_end
__tracepoint_android_vh_mutex_wait_finish __tracepoint_android_vh_mutex_wait_finish
__tracepoint_android_vh_mutex_wait_start __tracepoint_android_vh_mutex_wait_start
__tracepoint_android_vh_override_creds __tracepoint_android_vh_override_creds
__tracepoint_android_vh_page_referenced_check_bypass __tracepoint_android_vh_page_referenced_check_bypass
__tracepoint_android_vh_page_should_be_protected
__tracepoint_android_vh_mark_page_accessed
__tracepoint_android_vh_show_mapcount_pages
__tracepoint_android_vh_do_traversal_lruvec
__tracepoint_android_vh_update_page_mapcount
__tracepoint_android_vh_add_page_to_lrulist
__tracepoint_android_vh_del_page_from_lrulist
__tracepoint_android_vh_pcplist_add_cma_pages_bypass __tracepoint_android_vh_pcplist_add_cma_pages_bypass
__tracepoint_android_vh_prepare_update_load_avg_se __tracepoint_android_vh_prepare_update_load_avg_se
__tracepoint_android_vh_printk_hotplug __tracepoint_android_vh_printk_hotplug
__tracepoint_android_vh_process_killed __tracepoint_android_vh_process_killed
__tracepoint_android_vh_killed_process
__tracepoint_android_vh_revert_creds __tracepoint_android_vh_revert_creds
__tracepoint_android_vh_rmqueue __tracepoint_android_vh_rmqueue
__tracepoint_android_vh_rwsem_init __tracepoint_android_vh_rwsem_init
__tracepoint_android_vh_rwsem_mark_wake_readers
__tracepoint_android_vh_rwsem_set_owner
__tracepoint_android_vh_rwsem_set_reader_owned
__tracepoint_android_vh_rwsem_up_read_end
__tracepoint_android_vh_rwsem_up_write_end
__tracepoint_android_vh_rwsem_wake __tracepoint_android_vh_rwsem_wake
__tracepoint_android_vh_rwsem_wake_finish __tracepoint_android_vh_rwsem_wake_finish
__tracepoint_android_vh_rwsem_write_finished __tracepoint_android_vh_rwsem_write_finished

File diff suppressed because it is too large Load Diff

View File

@@ -59,6 +59,7 @@ struct insn_emulation {
static LIST_HEAD(insn_emulation); static LIST_HEAD(insn_emulation);
static int nr_insn_emulated __initdata; static int nr_insn_emulated __initdata;
static DEFINE_RAW_SPINLOCK(insn_emulation_lock); static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
static DEFINE_MUTEX(insn_emulation_mutex);
static void register_emulation_hooks(struct insn_emulation_ops *ops) static void register_emulation_hooks(struct insn_emulation_ops *ops)
{ {
@@ -207,10 +208,10 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
loff_t *ppos) loff_t *ppos)
{ {
int ret = 0; int ret = 0;
struct insn_emulation *insn = (struct insn_emulation *) table->data; struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode);
enum insn_emulation_mode prev_mode = insn->current_mode; enum insn_emulation_mode prev_mode = insn->current_mode;
table->data = &insn->current_mode; mutex_lock(&insn_emulation_mutex);
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (ret || !write || prev_mode == insn->current_mode) if (ret || !write || prev_mode == insn->current_mode)
@@ -223,7 +224,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
update_insn_emulation_mode(insn, INSN_UNDEF); update_insn_emulation_mode(insn, INSN_UNDEF);
} }
ret: ret:
table->data = insn; mutex_unlock(&insn_emulation_mutex);
return ret; return ret;
} }
@@ -247,7 +248,7 @@ static void __init register_insn_emulation_sysctl(void)
sysctl->maxlen = sizeof(int); sysctl->maxlen = sizeof(int);
sysctl->procname = insn->ops->name; sysctl->procname = insn->ops->name;
sysctl->data = insn; sysctl->data = &insn->current_mode;
sysctl->extra1 = &insn->min; sysctl->extra1 = &insn->min;
sysctl->extra2 = &insn->max; sysctl->extra2 = &insn->max;
sysctl->proc_handler = emulation_proc_handler; sysctl->proc_handler = emulation_proc_handler;

View File

@@ -1116,17 +1116,32 @@ static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name,
return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL); return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL);
} }
static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu) #define PMUV3_INIT_SIMPLE(name) \
{ static int name##_pmu_init(struct arm_pmu *cpu_pmu) \
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_pmuv3", { \
armv8_pmuv3_map_event); return armv8_pmu_init_nogroups(cpu_pmu, #name, armv8_pmuv3_map_event);\
} }
static int armv8_a34_pmu_init(struct arm_pmu *cpu_pmu) PMUV3_INIT_SIMPLE(armv8_pmuv3)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a34", PMUV3_INIT_SIMPLE(armv8_cortex_a34)
armv8_pmuv3_map_event); PMUV3_INIT_SIMPLE(armv8_cortex_a55)
} PMUV3_INIT_SIMPLE(armv8_cortex_a65)
PMUV3_INIT_SIMPLE(armv8_cortex_a75)
PMUV3_INIT_SIMPLE(armv8_cortex_a76)
PMUV3_INIT_SIMPLE(armv8_cortex_a77)
PMUV3_INIT_SIMPLE(armv8_cortex_a78)
PMUV3_INIT_SIMPLE(armv9_cortex_a510)
PMUV3_INIT_SIMPLE(armv9_cortex_a710)
PMUV3_INIT_SIMPLE(armv8_cortex_x1)
PMUV3_INIT_SIMPLE(armv9_cortex_x2)
PMUV3_INIT_SIMPLE(armv8_neoverse_e1)
PMUV3_INIT_SIMPLE(armv8_neoverse_n1)
PMUV3_INIT_SIMPLE(armv9_neoverse_n2)
PMUV3_INIT_SIMPLE(armv8_neoverse_v1)
PMUV3_INIT_SIMPLE(armv8_nvidia_carmel)
PMUV3_INIT_SIMPLE(armv8_nvidia_denver)
static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu) static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu)
{ {
@@ -1140,24 +1155,12 @@ static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
armv8_a53_map_event); armv8_a53_map_event);
} }
static int armv8_a55_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a55",
armv8_pmuv3_map_event);
}
static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu) static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57", return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57",
armv8_a57_map_event); armv8_a57_map_event);
} }
static int armv8_a65_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a65",
armv8_pmuv3_map_event);
}
static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu) static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72", return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72",
@@ -1170,36 +1173,6 @@ static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu)
armv8_a73_map_event); armv8_a73_map_event);
} }
static int armv8_a75_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a75",
armv8_pmuv3_map_event);
}
static int armv8_a76_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a76",
armv8_pmuv3_map_event);
}
static int armv8_a77_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a77",
armv8_pmuv3_map_event);
}
static int armv8_e1_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_e1",
armv8_pmuv3_map_event);
}
static int armv8_n1_pmu_init(struct arm_pmu *cpu_pmu)
{
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_n1",
armv8_pmuv3_map_event);
}
static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu) static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder", return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder",
@@ -1213,22 +1186,31 @@ static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu)
} }
static const struct of_device_id armv8_pmu_of_device_ids[] = { static const struct of_device_id armv8_pmu_of_device_ids[] = {
{.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_init}, {.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_pmu_init},
{.compatible = "arm,cortex-a34-pmu", .data = armv8_a34_pmu_init}, {.compatible = "arm,cortex-a34-pmu", .data = armv8_cortex_a34_pmu_init},
{.compatible = "arm,cortex-a35-pmu", .data = armv8_a35_pmu_init}, {.compatible = "arm,cortex-a35-pmu", .data = armv8_a35_pmu_init},
{.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init}, {.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init},
{.compatible = "arm,cortex-a55-pmu", .data = armv8_a55_pmu_init}, {.compatible = "arm,cortex-a55-pmu", .data = armv8_cortex_a55_pmu_init},
{.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init}, {.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init},
{.compatible = "arm,cortex-a65-pmu", .data = armv8_a65_pmu_init}, {.compatible = "arm,cortex-a65-pmu", .data = armv8_cortex_a65_pmu_init},
{.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init}, {.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init},
{.compatible = "arm,cortex-a73-pmu", .data = armv8_a73_pmu_init}, {.compatible = "arm,cortex-a73-pmu", .data = armv8_a73_pmu_init},
{.compatible = "arm,cortex-a75-pmu", .data = armv8_a75_pmu_init}, {.compatible = "arm,cortex-a75-pmu", .data = armv8_cortex_a75_pmu_init},
{.compatible = "arm,cortex-a76-pmu", .data = armv8_a76_pmu_init}, {.compatible = "arm,cortex-a76-pmu", .data = armv8_cortex_a76_pmu_init},
{.compatible = "arm,cortex-a77-pmu", .data = armv8_a77_pmu_init}, {.compatible = "arm,cortex-a77-pmu", .data = armv8_cortex_a77_pmu_init},
{.compatible = "arm,neoverse-e1-pmu", .data = armv8_e1_pmu_init}, {.compatible = "arm,cortex-a78-pmu", .data = armv8_cortex_a78_pmu_init},
{.compatible = "arm,neoverse-n1-pmu", .data = armv8_n1_pmu_init}, {.compatible = "arm,cortex-a510-pmu", .data = armv9_cortex_a510_pmu_init},
{.compatible = "arm,cortex-a710-pmu", .data = armv9_cortex_a710_pmu_init},
{.compatible = "arm,cortex-x1-pmu", .data = armv8_cortex_x1_pmu_init},
{.compatible = "arm,cortex-x2-pmu", .data = armv9_cortex_x2_pmu_init},
{.compatible = "arm,neoverse-e1-pmu", .data = armv8_neoverse_e1_pmu_init},
{.compatible = "arm,neoverse-n1-pmu", .data = armv8_neoverse_n1_pmu_init},
{.compatible = "arm,neoverse-n2-pmu", .data = armv9_neoverse_n2_pmu_init},
{.compatible = "arm,neoverse-v1-pmu", .data = armv8_neoverse_v1_pmu_init},
{.compatible = "cavium,thunder-pmu", .data = armv8_thunder_pmu_init}, {.compatible = "cavium,thunder-pmu", .data = armv8_thunder_pmu_init},
{.compatible = "brcm,vulcan-pmu", .data = armv8_vulcan_pmu_init}, {.compatible = "brcm,vulcan-pmu", .data = armv8_vulcan_pmu_init},
{.compatible = "nvidia,carmel-pmu", .data = armv8_nvidia_carmel_pmu_init},
{.compatible = "nvidia,denver-pmu", .data = armv8_nvidia_denver_pmu_init},
{}, {},
}; };
@@ -1251,7 +1233,7 @@ static int __init armv8_pmu_driver_init(void)
if (acpi_disabled) if (acpi_disabled)
return platform_driver_register(&armv8_pmu_driver); return platform_driver_register(&armv8_pmu_driver);
else else
return arm_pmu_acpi_probe(armv8_pmuv3_init); return arm_pmu_acpi_probe(armv8_pmuv3_pmu_init);
} }
device_initcall(armv8_pmu_driver_init) device_initcall(armv8_pmu_driver_init)

View File

@@ -173,8 +173,32 @@ static inline void binder_stats_created(enum binder_stat_types type)
atomic_inc(&binder_stats.obj_created[type]); atomic_inc(&binder_stats.obj_created[type]);
} }
struct binder_transaction_log binder_transaction_log; struct binder_transaction_log_entry {
struct binder_transaction_log binder_transaction_log_failed; int debug_id;
int debug_id_done;
int call_type;
int from_proc;
int from_thread;
int target_handle;
int to_proc;
int to_thread;
int to_node;
int data_size;
int offsets_size;
int return_error_line;
uint32_t return_error;
uint32_t return_error_param;
char context_name[BINDERFS_MAX_NAME + 1];
};
struct binder_transaction_log {
atomic_t cur;
bool full;
struct binder_transaction_log_entry entry[32];
};
static struct binder_transaction_log binder_transaction_log;
static struct binder_transaction_log binder_transaction_log_failed;
static struct binder_transaction_log_entry *binder_transaction_log_add( static struct binder_transaction_log_entry *binder_transaction_log_add(
struct binder_transaction_log *log) struct binder_transaction_log *log)
@@ -1480,6 +1504,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc,
} }
ret = binder_inc_ref_olocked(ref, strong, target_list); ret = binder_inc_ref_olocked(ref, strong, target_list);
*rdata = ref->data; *rdata = ref->data;
if (ret && ref == new_ref) {
/*
* Cleanup the failed reference here as the target
* could now be dead and have already released its
* references by now. Calling on the new reference
* with strong=0 and a tmp_refs will not decrement
* the node. The new_ref gets kfree'd below.
*/
binder_cleanup_ref_olocked(new_ref);
ref = NULL;
}
binder_proc_unlock(proc); binder_proc_unlock(proc);
if (new_ref && ref != new_ref) if (new_ref && ref != new_ref)
/* /*
@@ -2464,6 +2500,56 @@ static int binder_fixup_parent(struct binder_transaction *t,
return 0; return 0;
} }
/**
* binder_can_update_transaction() - Can a txn be superseded by an updated one?
* @t1: the pending async txn in the frozen process
* @t2: the new async txn to supersede the outdated pending one
*
* Return: true if t2 can supersede t1
* false if t2 can not supersede t1
*/
static bool binder_can_update_transaction(struct binder_transaction *t1,
struct binder_transaction *t2)
{
if ((t1->flags & t2->flags & (TF_ONE_WAY | TF_UPDATE_TXN)) !=
(TF_ONE_WAY | TF_UPDATE_TXN) || !t1->to_proc || !t2->to_proc)
return false;
if (t1->to_proc->tsk == t2->to_proc->tsk && t1->code == t2->code &&
t1->flags == t2->flags && t1->buffer->pid == t2->buffer->pid &&
t1->buffer->target_node->ptr == t2->buffer->target_node->ptr &&
t1->buffer->target_node->cookie == t2->buffer->target_node->cookie)
return true;
return false;
}
/**
* binder_find_outdated_transaction_ilocked() - Find the outdated transaction
* @t: new async transaction
* @target_list: list to find outdated transaction
*
* Return: the outdated transaction if found
* NULL if no outdated transacton can be found
*
* Requires the proc->inner_lock to be held.
*/
static struct binder_transaction *
binder_find_outdated_transaction_ilocked(struct binder_transaction *t,
struct list_head *target_list)
{
struct binder_work *w;
list_for_each_entry(w, target_list, entry) {
struct binder_transaction *t_queued;
if (w->type != BINDER_WORK_TRANSACTION)
continue;
t_queued = container_of(w, struct binder_transaction, work);
if (binder_can_update_transaction(t_queued, t))
return t_queued;
}
return NULL;
}
/** /**
* binder_proc_transaction() - sends a transaction to a process and wakes it up * binder_proc_transaction() - sends a transaction to a process and wakes it up
* @t: transaction to send * @t: transaction to send
@@ -2491,6 +2577,7 @@ static int binder_proc_transaction(struct binder_transaction *t,
bool oneway = !!(t->flags & TF_ONE_WAY); bool oneway = !!(t->flags & TF_ONE_WAY);
bool pending_async = false; bool pending_async = false;
bool skip = false; bool skip = false;
struct binder_transaction *t_outdated = NULL;
BUG_ON(!node); BUG_ON(!node);
binder_node_lock(node); binder_node_lock(node);
@@ -2534,6 +2621,17 @@ static int binder_proc_transaction(struct binder_transaction *t,
} else if (!pending_async) { } else if (!pending_async) {
binder_enqueue_work_ilocked(&t->work, &proc->todo); binder_enqueue_work_ilocked(&t->work, &proc->todo);
} else { } else {
if ((t->flags & TF_UPDATE_TXN) && proc->is_frozen) {
t_outdated = binder_find_outdated_transaction_ilocked(t,
&node->async_todo);
if (t_outdated) {
binder_debug(BINDER_DEBUG_TRANSACTION,
"txn %d supersedes %d\n",
t->debug_id, t_outdated->debug_id);
list_del_init(&t_outdated->work.entry);
proc->outstanding_txns--;
}
}
binder_enqueue_work_ilocked(&t->work, &node->async_todo); binder_enqueue_work_ilocked(&t->work, &node->async_todo);
} }
@@ -2547,6 +2645,22 @@ static int binder_proc_transaction(struct binder_transaction *t,
binder_inner_proc_unlock(proc); binder_inner_proc_unlock(proc);
binder_node_unlock(node); binder_node_unlock(node);
/*
* To reduce potential contention, free the outdated transaction and
* buffer after releasing the locks.
*/
if (t_outdated) {
struct binder_buffer *buffer = t_outdated->buffer;
t_outdated->buffer = NULL;
buffer->transaction = NULL;
trace_binder_transaction_update_buffer_release(buffer);
binder_transaction_buffer_release(proc, NULL, buffer, 0, 0);
binder_alloc_free_buf(&proc->alloc, buffer);
kfree(t_outdated);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
return 0; return 0;
} }
@@ -5950,8 +6064,7 @@ static void print_binder_proc_stats(struct seq_file *m,
print_binder_stats(m, " ", &proc->stats); print_binder_stats(m, " ", &proc->stats);
} }
static int state_show(struct seq_file *m, void *unused)
int binder_state_show(struct seq_file *m, void *unused)
{ {
struct binder_proc *proc; struct binder_proc *proc;
struct binder_node *node; struct binder_node *node;
@@ -5990,7 +6103,7 @@ int binder_state_show(struct seq_file *m, void *unused)
return 0; return 0;
} }
int binder_stats_show(struct seq_file *m, void *unused) static int stats_show(struct seq_file *m, void *unused)
{ {
struct binder_proc *proc; struct binder_proc *proc;
@@ -6006,7 +6119,7 @@ int binder_stats_show(struct seq_file *m, void *unused)
return 0; return 0;
} }
int binder_transactions_show(struct seq_file *m, void *unused) static int transactions_show(struct seq_file *m, void *unused)
{ {
struct binder_proc *proc; struct binder_proc *proc;
@@ -6062,7 +6175,7 @@ static void print_binder_transaction_log_entry(struct seq_file *m,
"\n" : " (incomplete)\n"); "\n" : " (incomplete)\n");
} }
int binder_transaction_log_show(struct seq_file *m, void *unused) static int transaction_log_show(struct seq_file *m, void *unused)
{ {
struct binder_transaction_log *log = m->private; struct binder_transaction_log *log = m->private;
unsigned int log_cur = atomic_read(&log->cur); unsigned int log_cur = atomic_read(&log->cur);
@@ -6094,6 +6207,45 @@ const struct file_operations binder_fops = {
.release = binder_release, .release = binder_release,
}; };
DEFINE_SHOW_ATTRIBUTE(state);
DEFINE_SHOW_ATTRIBUTE(stats);
DEFINE_SHOW_ATTRIBUTE(transactions);
DEFINE_SHOW_ATTRIBUTE(transaction_log);
const struct binder_debugfs_entry binder_debugfs_entries[] = {
{
.name = "state",
.mode = 0444,
.fops = &state_fops,
.data = NULL,
},
{
.name = "stats",
.mode = 0444,
.fops = &stats_fops,
.data = NULL,
},
{
.name = "transactions",
.mode = 0444,
.fops = &transactions_fops,
.data = NULL,
},
{
.name = "transaction_log",
.mode = 0444,
.fops = &transaction_log_fops,
.data = &binder_transaction_log,
},
{
.name = "failed_transaction_log",
.mode = 0444,
.fops = &transaction_log_fops,
.data = &binder_transaction_log_failed,
},
{} /* terminator */
};
static int __init init_binder_device(const char *name) static int __init init_binder_device(const char *name)
{ {
int ret; int ret;
@@ -6139,36 +6291,18 @@ static int __init binder_init(void)
atomic_set(&binder_transaction_log_failed.cur, ~0U); atomic_set(&binder_transaction_log_failed.cur, ~0U);
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root) if (binder_debugfs_dir_entry_root) {
const struct binder_debugfs_entry *db_entry;
binder_for_each_debugfs_entry(db_entry)
debugfs_create_file(db_entry->name,
db_entry->mode,
binder_debugfs_dir_entry_root,
db_entry->data,
db_entry->fops);
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
binder_debugfs_dir_entry_root); binder_debugfs_dir_entry_root);
if (binder_debugfs_dir_entry_root) {
debugfs_create_file("state",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_state_fops);
debugfs_create_file("stats",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_stats_fops);
debugfs_create_file("transactions",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_fops);
debugfs_create_file("transaction_log",
0444,
binder_debugfs_dir_entry_root,
&binder_transaction_log,
&binder_transaction_log_fops);
debugfs_create_file("failed_transaction_log",
0444,
binder_debugfs_dir_entry_root,
&binder_transaction_log_failed,
&binder_transaction_log_fops);
} }
if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) && if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) &&

View File

@@ -107,41 +107,19 @@ static inline int __init init_binderfs(void)
} }
#endif #endif
int binder_stats_show(struct seq_file *m, void *unused); struct binder_debugfs_entry {
DEFINE_SHOW_ATTRIBUTE(binder_stats); const char *name;
umode_t mode;
int binder_state_show(struct seq_file *m, void *unused); const struct file_operations *fops;
DEFINE_SHOW_ATTRIBUTE(binder_state); void *data;
int binder_transactions_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_transactions);
int binder_transaction_log_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_transaction_log);
struct binder_transaction_log_entry {
int debug_id;
int debug_id_done;
int call_type;
int from_proc;
int from_thread;
int target_handle;
int to_proc;
int to_thread;
int to_node;
int data_size;
int offsets_size;
int return_error_line;
uint32_t return_error;
uint32_t return_error_param;
char context_name[BINDERFS_MAX_NAME + 1];
}; };
struct binder_transaction_log { extern const struct binder_debugfs_entry binder_debugfs_entries[];
atomic_t cur;
bool full; #define binder_for_each_debugfs_entry(entry) \
struct binder_transaction_log_entry entry[32]; for ((entry) = binder_debugfs_entries; \
}; (entry)->name; \
(entry)++)
enum binder_stat_types { enum binder_stat_types {
BINDER_STAT_PROC, BINDER_STAT_PROC,
@@ -620,6 +598,4 @@ struct binder_object {
}; };
}; };
extern struct binder_transaction_log binder_transaction_log;
extern struct binder_transaction_log binder_transaction_log_failed;
#endif /* _LINUX_BINDER_INTERNAL_H */ #endif /* _LINUX_BINDER_INTERNAL_H */

View File

@@ -306,6 +306,10 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release,
TP_PROTO(struct binder_buffer *buffer), TP_PROTO(struct binder_buffer *buffer),
TP_ARGS(buffer)); TP_ARGS(buffer));
DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release,
TP_PROTO(struct binder_buffer *buffer),
TP_ARGS(buffer));
TRACE_EVENT(binder_update_page_range, TRACE_EVENT(binder_update_page_range,
TP_PROTO(struct binder_alloc *alloc, bool allocate, TP_PROTO(struct binder_alloc *alloc, bool allocate,
void __user *start, void __user *end), void __user *start, void __user *end),

View File

@@ -584,6 +584,7 @@ out:
static int init_binder_logs(struct super_block *sb) static int init_binder_logs(struct super_block *sb)
{ {
struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir;
const struct binder_debugfs_entry *db_entry;
struct binderfs_info *info; struct binderfs_info *info;
int ret = 0; int ret = 0;
@@ -594,43 +595,15 @@ static int init_binder_logs(struct super_block *sb)
goto out; goto out;
} }
dentry = binderfs_create_file(binder_logs_root_dir, "stats", binder_for_each_debugfs_entry(db_entry) {
&binder_stats_fops, NULL);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir, "state",
&binder_state_fops, NULL);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir, "transactions",
&binder_transactions_fops, NULL);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir, dentry = binderfs_create_file(binder_logs_root_dir,
"transaction_log", db_entry->name,
&binder_transaction_log_fops, db_entry->fops,
&binder_transaction_log); db_entry->data);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry); ret = PTR_ERR(dentry);
goto out; goto out;
} }
dentry = binderfs_create_file(binder_logs_root_dir,
"failed_transaction_log",
&binder_transaction_log_fops,
&binder_transaction_log_failed);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
} }
proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc");

View File

@@ -271,7 +271,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_exit_mm);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_from_fragment_pool); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_from_fragment_pool);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_exclude_reserved_zone); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_exclude_reserved_zone);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_include_reserved_zone); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_include_reserved_zone);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_begin);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_end);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mem); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mem);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mapcount_pages);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_traversal_lruvec);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpci_override_toggling); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpci_override_toggling);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_chk_contaminant); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_chk_contaminant);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_get_vbus); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_get_vbus);
@@ -300,6 +304,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_logbuf_pr_cont);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_tune_scan_type); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_tune_scan_type);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_tune_swappiness); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_tune_swappiness);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_shrink_slab_bypass); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_shrink_slab_bypass);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_handle_failed_page_trylock);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_trylock_set);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_trylock_clear);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_trylock_get_result);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_page_trylock);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_referenced_check_bypass); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_referenced_check_bypass);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_drain_all_pages_bypass); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_drain_all_pages_bypass);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_cma_drain_all_pages_bypass); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_cma_drain_all_pages_bypass);
@@ -336,6 +345,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_attach_sd);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sdhci_get_cd); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sdhci_get_cd);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_gpio_cd_irqt); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_gpio_cd_irqt);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_vmalloc_stack); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_vmalloc_stack);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_remove_vmalloc_stack);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_stack_hash); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_stack_hash);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_track_hash); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_track_hash);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_vmpressure); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_vmpressure);
@@ -390,6 +400,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_tcp_recvmsg_stat);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_kmalloc_slab); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_kmalloc_slab);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmap_region); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmap_region);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_update_page_mapcount);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_add_page_to_lrulist);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_del_page_from_lrulist);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_should_be_protected);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mark_page_accessed);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_to_unmap_one); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_to_unmap_one);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_id_remove); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_id_remove);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_css_offline); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_css_offline);
@@ -430,3 +445,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_init_swap_info_struct);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_si_swapinfo); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_si_swapinfo);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_si); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_si);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_free_pages); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_free_pages);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_set_shmem_page_flag);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_pidfd_open);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmput);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_pelt_multiplier);

View File

@@ -50,6 +50,11 @@ struct iommu_dma_cookie {
struct iommu_domain *fq_domain; struct iommu_domain *fq_domain;
}; };
struct iommu_dma_cookie_ext {
struct iommu_dma_cookie cookie;
struct mutex mutex;
};
static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie)
{ {
if (cookie->type == IOMMU_DMA_IOVA_COOKIE) if (cookie->type == IOMMU_DMA_IOVA_COOKIE)
@@ -59,14 +64,15 @@ static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie)
static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type)
{ {
struct iommu_dma_cookie *cookie; struct iommu_dma_cookie_ext *cookie;
cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (cookie) { if (cookie) {
INIT_LIST_HEAD(&cookie->msi_page_list); INIT_LIST_HEAD(&cookie->cookie.msi_page_list);
cookie->type = type; cookie->cookie.type = type;
mutex_init(&cookie->mutex);
} }
return cookie; return &cookie->cookie;
} }
/** /**
@@ -305,9 +311,11 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
u64 size, struct device *dev) u64 size, struct device *dev)
{ {
struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iommu_dma_cookie_ext *cookie_ext;
unsigned long order, base_pfn; unsigned long order, base_pfn;
struct iova_domain *iovad; struct iova_domain *iovad;
int attr; int attr;
int ret;
if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE)
return -EINVAL; return -EINVAL;
@@ -331,14 +339,18 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
} }
/* start_pfn is always nonzero for an already-initialised domain */ /* start_pfn is always nonzero for an already-initialised domain */
cookie_ext = container_of(cookie, struct iommu_dma_cookie_ext, cookie);
mutex_lock(&cookie_ext->mutex);
if (iovad->start_pfn) { if (iovad->start_pfn) {
if (1UL << order != iovad->granule || if (1UL << order != iovad->granule ||
base_pfn != iovad->start_pfn) { base_pfn != iovad->start_pfn) {
pr_warn("Incompatible range for DMA domain\n"); pr_warn("Incompatible range for DMA domain\n");
return -EFAULT; ret = -EFAULT;
goto done_unlock;
} }
return 0; ret = 0;
goto done_unlock;
} }
init_iova_domain(iovad, 1UL << order, base_pfn); init_iova_domain(iovad, 1UL << order, base_pfn);
@@ -352,10 +364,16 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
cookie->fq_domain = domain; cookie->fq_domain = domain;
} }
if (!dev) if (!dev) {
return 0; ret = 0;
goto done_unlock;
}
return iova_reserve_iommu_regions(dev, domain); ret = iova_reserve_iommu_regions(dev, domain);
done_unlock:
mutex_unlock(&cookie_ext->mutex);
return ret;
} }
static int iommu_dma_deferred_attach(struct device *dev, static int iommu_dma_deferred_attach(struct device *dev,

View File

@@ -466,9 +466,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
type = PCIE_ATU_TYPE_CFG1; type = PCIE_ATU_TYPE_CFG1;
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
type, pp->cfg0_base,
busdev, pp->cfg0_size);
return pp->va_cfg0_base + where; return pp->va_cfg0_base + where;
} }
@@ -482,9 +480,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_read(bus, devfn, where, size, val); ret = pci_generic_config_read(bus, devfn, where, size, val);
if (!ret && pci->num_viewport <= 2) if (!ret && (pci->iatu_unroll_enabled & DWC_IATU_IOCFG_SHARED))
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size); pp->io_bus_addr, pp->io_size);
return ret; return ret;
@@ -499,9 +496,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_write(bus, devfn, where, size, val); ret = pci_generic_config_write(bus, devfn, where, size, val);
if (!ret && pci->num_viewport <= 2) if (!ret && (pci->iatu_unroll_enabled & DWC_IATU_IOCFG_SHARED))
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size); pp->io_bus_addr, pp->io_size);
return ret; return ret;
@@ -588,21 +584,35 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
* ATU, so we should not program the ATU here. * ATU, so we should not program the ATU here.
*/ */
if (pp->bridge->child_ops == &dw_child_pcie_ops) { if (pp->bridge->child_ops == &dw_child_pcie_ops) {
struct resource_entry *tmp, *entry = NULL; int atu_idx = 0;
struct resource_entry *entry;
/* Get last memory resource entry */ /* Get last memory resource entry */
resource_list_for_each_entry(tmp, &pp->bridge->windows) resource_list_for_each_entry(entry, &pp->bridge->windows) {
if (resource_type(tmp->res) == IORESOURCE_MEM) if (resource_type(entry->res) != IORESOURCE_MEM)
entry = tmp; continue;
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, if (pci->num_viewport <= ++atu_idx)
break;
dw_pcie_prog_outbound_atu(pci, atu_idx,
PCIE_ATU_TYPE_MEM, entry->res->start, PCIE_ATU_TYPE_MEM, entry->res->start,
entry->res->start - entry->offset, entry->res->start - entry->offset,
resource_size(entry->res)); resource_size(entry->res));
if (pci->num_viewport > 2) }
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
if (pp->io_size) {
if (pci->num_viewport > ++atu_idx)
dw_pcie_prog_outbound_atu(pci, atu_idx,
PCIE_ATU_TYPE_IO, pp->io_base, PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size); pp->io_bus_addr, pp->io_size);
else
pci->iatu_unroll_enabled |= DWC_IATU_IOCFG_SHARED;
}
if (pci->num_viewport <= atu_idx)
dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
pci->num_viewport);
} }
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);

View File

@@ -274,7 +274,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
if (pci->ops->cpu_addr_fixup) if (pci->ops->cpu_addr_fixup)
cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
if (pci->iatu_unroll_enabled) { if (pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN) {
dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type, dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
cpu_addr, pci_addr, size); cpu_addr, pci_addr, size);
return; return;
@@ -394,7 +394,7 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type; int type;
u32 retries, val; u32 retries, val;
if (pci->iatu_unroll_enabled) if (pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN)
return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar, return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
cpu_addr, as_type); cpu_addr, as_type);
@@ -554,14 +554,15 @@ void dw_pcie_setup(struct dw_pcie *pci)
if (pci->version >= 0x480A || (!pci->version && if (pci->version >= 0x480A || (!pci->version &&
dw_pcie_iatu_unroll_enabled(pci))) { dw_pcie_iatu_unroll_enabled(pci))) {
pci->iatu_unroll_enabled = true; pci->iatu_unroll_enabled |= DWC_IATU_UNROLL_EN;
if (!pci->atu_base) if (!pci->atu_base)
pci->atu_base = pci->atu_base =
devm_platform_ioremap_resource_byname(pdev, "atu"); devm_platform_ioremap_resource_byname(pdev, "atu");
if (IS_ERR(pci->atu_base)) if (IS_ERR(pci->atu_base))
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
} }
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? dev_dbg(pci->dev, "iATU unroll: %s\n",
pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN ?
"enabled" : "disabled"); "enabled" : "disabled");
if (pci->link_gen > 0) if (pci->link_gen > 0)

View File

@@ -80,9 +80,6 @@
#define PCIE_ATU_VIEWPORT 0x900 #define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND BIT(31) #define PCIE_ATU_REGION_INBOUND BIT(31)
#define PCIE_ATU_REGION_OUTBOUND 0 #define PCIE_ATU_REGION_OUTBOUND 0
#define PCIE_ATU_REGION_INDEX2 0x2
#define PCIE_ATU_REGION_INDEX1 0x1
#define PCIE_ATU_REGION_INDEX0 0x0
#define PCIE_ATU_CR1 0x904 #define PCIE_ATU_CR1 0x904
#define PCIE_ATU_TYPE_MEM 0x0 #define PCIE_ATU_TYPE_MEM 0x0
#define PCIE_ATU_TYPE_IO 0x2 #define PCIE_ATU_TYPE_IO 0x2
@@ -259,6 +256,8 @@ struct dw_pcie_ops {
void (*stop_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie);
}; };
#define DWC_IATU_UNROLL_EN BIT(0)
#define DWC_IATU_IOCFG_SHARED BIT(1)
struct dw_pcie { struct dw_pcie {
struct device *dev; struct device *dev;
void __iomem *dbi_base; void __iomem *dbi_base;

View File

@@ -156,8 +156,13 @@ static void __dwc3_set_mode(struct work_struct *work)
break; break;
} }
/* For DRD host or device mode only */ /*
if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { * When current_dr_role is not set, there's no role switching.
* Only perform GCTL.CoreSoftReset when there's DRD role switching.
*/
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg |= DWC3_GCTL_CORESOFTRESET; reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_writel(dwc->regs, DWC3_GCTL, reg);

View File

@@ -2471,6 +2471,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
int ret; int ret;
is_on = !!is_on; is_on = !!is_on;
if (dwc->pullups_connected == is_on)
return 0;
vdwc->softconnect = is_on; vdwc->softconnect = is_on;
/* /*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -12,11 +12,14 @@
* Jaswinder Singh (jaswinder.singh@linaro.org) * Jaswinder Singh (jaswinder.singh@linaro.org)
*/ */
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/control.h> #include <sound/control.h>
#include <sound/tlv.h>
#include <linux/usb/audio.h>
#include "u_audio.h" #include "u_audio.h"
@@ -24,6 +27,14 @@
#define PRD_SIZE_MAX PAGE_SIZE #define PRD_SIZE_MAX PAGE_SIZE
#define MIN_PERIODS 4 #define MIN_PERIODS 4
enum {
UAC_FBACK_CTRL,
UAC_P_PITCH_CTRL,
UAC_MUTE_CTRL,
UAC_VOLUME_CTRL,
UAC_RATE_CTRL,
};
/* Runtime data params for one stream */ /* Runtime data params for one stream */
struct uac_rtd_params { struct uac_rtd_params {
struct snd_uac_chip *uac; /* parent chip */ struct snd_uac_chip *uac; /* parent chip */
@@ -43,6 +54,21 @@ struct uac_rtd_params {
struct usb_request *req_fback; /* Feedback endpoint request */ struct usb_request *req_fback; /* Feedback endpoint request */
bool fb_ep_enabled; /* if the ep is enabled */ bool fb_ep_enabled; /* if the ep is enabled */
/* Volume/Mute controls and their state */
int fu_id; /* Feature Unit ID */
struct snd_kcontrol *snd_kctl_volume;
struct snd_kcontrol *snd_kctl_mute;
s16 volume_min, volume_max, volume_res;
s16 volume;
int mute;
struct snd_kcontrol *snd_kctl_rate; /* read-only current rate */
int srate; /* selected samplerate */
int active; /* playback/capture running */
spinlock_t lock; /* lock for control transfers */
}; };
struct snd_uac_chip { struct snd_uac_chip {
@@ -54,13 +80,9 @@ struct snd_uac_chip {
struct snd_card *card; struct snd_card *card;
struct snd_pcm *pcm; struct snd_pcm *pcm;
/* timekeeping for the playback endpoint */
unsigned int p_interval;
unsigned int p_residue;
/* pre-calculated values for playback iso completion */ /* pre-calculated values for playback iso completion */
unsigned int p_pktsize; unsigned long long p_residue_mil;
unsigned int p_pktsize_residue; unsigned int p_interval;
unsigned int p_framesize; unsigned int p_framesize;
}; };
@@ -133,6 +155,9 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct uac_rtd_params *prm = req->context; struct uac_rtd_params *prm = req->context;
struct snd_uac_chip *uac = prm->uac; struct snd_uac_chip *uac = prm->uac;
unsigned int frames, p_pktsize;
unsigned long long pitched_rate_mil, p_pktsize_residue_mil,
residue_frames_mil, div_result;
/* i/f shutting down */ /* i/f shutting down */
if (!prm->ep_enabled) { if (!prm->ep_enabled) {
@@ -172,19 +197,44 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
* If there is a residue from this division, add it to the * If there is a residue from this division, add it to the
* residue accumulator. * residue accumulator.
*/ */
req->length = uac->p_pktsize; unsigned long long p_interval_mil = uac->p_interval * 1000000ULL;
uac->p_residue += uac->p_pktsize_residue;
pitched_rate_mil = (unsigned long long) prm->srate * prm->pitch;
div_result = pitched_rate_mil;
do_div(div_result, uac->p_interval);
do_div(div_result, 1000000);
frames = (unsigned int) div_result;
pr_debug("p_srate %d, pitch %d, interval_mil %llu, frames %d\n",
prm->srate, prm->pitch, p_interval_mil, frames);
p_pktsize = min_t(unsigned int,
uac->p_framesize * frames,
ep->maxpacket);
if (p_pktsize < ep->maxpacket) {
residue_frames_mil = pitched_rate_mil - frames * p_interval_mil;
p_pktsize_residue_mil = uac->p_framesize * residue_frames_mil;
} else
p_pktsize_residue_mil = 0;
req->length = p_pktsize;
uac->p_residue_mil += p_pktsize_residue_mil;
/* /*
* Whenever there are more bytes in the accumulator than we * Whenever there are more bytes in the accumulator p_residue_mil than we
* need to add one more sample frame, increase this packet's * need to add one more sample frame, increase this packet's
* size and decrease the accumulator. * size and decrease the accumulator.
*/ */
if (uac->p_residue / uac->p_interval >= uac->p_framesize) { div_result = uac->p_residue_mil;
do_div(div_result, uac->p_interval);
do_div(div_result, 1000000);
if ((unsigned int) div_result >= uac->p_framesize) {
req->length += uac->p_framesize; req->length += uac->p_framesize;
uac->p_residue -= uac->p_framesize * uac->p_residue_mil -= uac->p_framesize * p_interval_mil;
uac->p_interval; pr_debug("increased req length to %d\n", req->length);
} }
pr_debug("remains uac->p_residue_mil %llu\n", uac->p_residue_mil);
req->actual = req->length; req->actual = req->length;
} }
@@ -233,7 +283,6 @@ static void u_audio_iso_fback_complete(struct usb_ep *ep,
struct uac_rtd_params *prm = req->context; struct uac_rtd_params *prm = req->context;
struct snd_uac_chip *uac = prm->uac; struct snd_uac_chip *uac = prm->uac;
struct g_audio *audio_dev = uac->audio_dev; struct g_audio *audio_dev = uac->audio_dev;
struct uac_params *params = &audio_dev->params;
int status = req->status; int status = req->status;
/* i/f shutting down */ /* i/f shutting down */
@@ -255,7 +304,7 @@ static void u_audio_iso_fback_complete(struct usb_ep *ep,
__func__, status, req->actual, req->length); __func__, status, req->actual, req->length);
u_audio_set_fback_frequency(audio_dev->gadget->speed, audio_dev->out_ep, u_audio_set_fback_frequency(audio_dev->gadget->speed, audio_dev->out_ep,
params->c_srate, prm->pitch, prm->srate, prm->pitch,
req->buf); req->buf);
if (usb_ep_queue(ep, req, GFP_ATOMIC)) if (usb_ep_queue(ep, req, GFP_ATOMIC))
@@ -339,36 +388,33 @@ static int uac_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct g_audio *audio_dev; struct g_audio *audio_dev;
struct uac_params *params; struct uac_params *params;
struct uac_rtd_params *prm;
int p_ssize, c_ssize; int p_ssize, c_ssize;
int p_srate, c_srate;
int p_chmask, c_chmask; int p_chmask, c_chmask;
audio_dev = uac->audio_dev; audio_dev = uac->audio_dev;
params = &audio_dev->params; params = &audio_dev->params;
p_ssize = params->p_ssize; p_ssize = params->p_ssize;
c_ssize = params->c_ssize; c_ssize = params->c_ssize;
p_srate = params->p_srate;
c_srate = params->c_srate;
p_chmask = params->p_chmask; p_chmask = params->p_chmask;
c_chmask = params->c_chmask; c_chmask = params->c_chmask;
uac->p_residue = 0; uac->p_residue_mil = 0;
runtime->hw = uac_pcm_hardware; runtime->hw = uac_pcm_hardware;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min = p_srate;
runtime->hw.formats = uac_ssize_to_fmt(p_ssize); runtime->hw.formats = uac_ssize_to_fmt(p_ssize);
runtime->hw.channels_min = num_channels(p_chmask); runtime->hw.channels_min = num_channels(p_chmask);
runtime->hw.period_bytes_min = 2 * uac->p_prm.max_psize prm = &uac->p_prm;
/ runtime->hw.periods_min;
} else { } else {
runtime->hw.rate_min = c_srate;
runtime->hw.formats = uac_ssize_to_fmt(c_ssize); runtime->hw.formats = uac_ssize_to_fmt(c_ssize);
runtime->hw.channels_min = num_channels(c_chmask); runtime->hw.channels_min = num_channels(c_chmask);
runtime->hw.period_bytes_min = 2 * uac->c_prm.max_psize prm = &uac->c_prm;
/ runtime->hw.periods_min;
} }
runtime->hw.period_bytes_min = 2 * prm->max_psize
/ runtime->hw.periods_min;
runtime->hw.rate_min = prm->srate;
runtime->hw.rate_max = runtime->hw.rate_min; runtime->hw.rate_max = runtime->hw.rate_min;
runtime->hw.channels_max = runtime->hw.channels_min; runtime->hw.channels_max = runtime->hw.channels_min;
@@ -445,6 +491,99 @@ static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep)
dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__); dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
} }
static void set_active(struct uac_rtd_params *prm, bool active)
{
// notifying through the Rate ctrl
struct snd_kcontrol *kctl = prm->snd_kctl_rate;
unsigned long flags;
spin_lock_irqsave(&prm->lock, flags);
if (prm->active != active) {
prm->active = active;
snd_ctl_notify(prm->uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
&kctl->id);
}
spin_unlock_irqrestore(&prm->lock, flags);
}
int u_audio_set_capture_srate(struct g_audio *audio_dev, int srate)
{
struct uac_params *params = &audio_dev->params;
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
int i;
unsigned long flags;
dev_dbg(&audio_dev->gadget->dev, "%s: srate %d\n", __func__, srate);
prm = &uac->c_prm;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (params->c_srates[i] == srate) {
spin_lock_irqsave(&prm->lock, flags);
prm->srate = srate;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
if (params->c_srates[i] == 0)
break;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(u_audio_set_capture_srate);
int u_audio_get_capture_srate(struct g_audio *audio_dev, u32 *val)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
unsigned long flags;
prm = &uac->c_prm;
spin_lock_irqsave(&prm->lock, flags);
*val = prm->srate;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_get_capture_srate);
int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate)
{
struct uac_params *params = &audio_dev->params;
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
int i;
unsigned long flags;
dev_dbg(&audio_dev->gadget->dev, "%s: srate %d\n", __func__, srate);
prm = &uac->p_prm;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (params->p_srates[i] == srate) {
spin_lock_irqsave(&prm->lock, flags);
prm->srate = srate;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
if (params->p_srates[i] == 0)
break;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(u_audio_set_playback_srate);
int u_audio_get_playback_srate(struct g_audio *audio_dev, u32 *val)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
unsigned long flags;
prm = &uac->p_prm;
spin_lock_irqsave(&prm->lock, flags);
*val = prm->srate;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_get_playback_srate);
int u_audio_start_capture(struct g_audio *audio_dev) int u_audio_start_capture(struct g_audio *audio_dev)
{ {
struct snd_uac_chip *uac = audio_dev->uac; struct snd_uac_chip *uac = audio_dev->uac;
@@ -456,8 +595,9 @@ int u_audio_start_capture(struct g_audio *audio_dev)
struct uac_params *params = &audio_dev->params; struct uac_params *params = &audio_dev->params;
int req_len, i; int req_len, i;
ep = audio_dev->out_ep;
prm = &uac->c_prm; prm = &uac->c_prm;
dev_dbg(dev, "start capture with rate %d\n", prm->srate);
ep = audio_dev->out_ep;
config_ep_by_speed(gadget, &audio_dev->func, ep); config_ep_by_speed(gadget, &audio_dev->func, ep);
req_len = ep->maxpacket; req_len = ep->maxpacket;
@@ -483,6 +623,8 @@ int u_audio_start_capture(struct g_audio *audio_dev)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
} }
set_active(&uac->c_prm, true);
ep_fback = audio_dev->in_ep_fback; ep_fback = audio_dev->in_ep_fback;
if (!ep_fback) if (!ep_fback)
return 0; return 0;
@@ -514,7 +656,7 @@ int u_audio_start_capture(struct g_audio *audio_dev)
*/ */
prm->pitch = 1000000; prm->pitch = 1000000;
u_audio_set_fback_frequency(audio_dev->gadget->speed, ep, u_audio_set_fback_frequency(audio_dev->gadget->speed, ep,
params->c_srate, prm->pitch, prm->srate, prm->pitch,
req_fback->buf); req_fback->buf);
if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC)) if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC))
@@ -528,6 +670,7 @@ void u_audio_stop_capture(struct g_audio *audio_dev)
{ {
struct snd_uac_chip *uac = audio_dev->uac; struct snd_uac_chip *uac = audio_dev->uac;
set_active(&uac->c_prm, false);
if (audio_dev->in_ep_fback) if (audio_dev->in_ep_fback)
free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback); free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);
free_ep(&uac->c_prm, audio_dev->out_ep); free_ep(&uac->c_prm, audio_dev->out_ep);
@@ -546,12 +689,18 @@ int u_audio_start_playback(struct g_audio *audio_dev)
unsigned int factor; unsigned int factor;
const struct usb_endpoint_descriptor *ep_desc; const struct usb_endpoint_descriptor *ep_desc;
int req_len, i; int req_len, i;
unsigned int p_pktsize;
ep = audio_dev->in_ep;
prm = &uac->p_prm; prm = &uac->p_prm;
dev_dbg(dev, "start playback with rate %d\n", prm->srate);
ep = audio_dev->in_ep;
config_ep_by_speed(gadget, &audio_dev->func, ep); config_ep_by_speed(gadget, &audio_dev->func, ep);
ep_desc = ep->desc; ep_desc = ep->desc;
/*
* Always start with original frequency
*/
prm->pitch = 1000000;
/* pre-calculate the playback endpoint's interval */ /* pre-calculate the playback endpoint's interval */
if (gadget->speed == USB_SPEED_FULL) if (gadget->speed == USB_SPEED_FULL)
@@ -563,19 +712,13 @@ int u_audio_start_playback(struct g_audio *audio_dev)
uac->p_framesize = params->p_ssize * uac->p_framesize = params->p_ssize *
num_channels(params->p_chmask); num_channels(params->p_chmask);
uac->p_interval = factor / (1 << (ep_desc->bInterval - 1)); uac->p_interval = factor / (1 << (ep_desc->bInterval - 1));
uac->p_pktsize = min_t(unsigned int, p_pktsize = min_t(unsigned int,
uac->p_framesize * uac->p_framesize *
(params->p_srate / uac->p_interval), (prm->srate / uac->p_interval),
ep->maxpacket); ep->maxpacket);
if (uac->p_pktsize < ep->maxpacket) req_len = p_pktsize;
uac->p_pktsize_residue = uac->p_framesize * uac->p_residue_mil = 0;
(params->p_srate % uac->p_interval);
else
uac->p_pktsize_residue = 0;
req_len = uac->p_pktsize;
uac->p_residue = 0;
prm->ep_enabled = true; prm->ep_enabled = true;
usb_ep_enable(ep); usb_ep_enable(ep);
@@ -599,6 +742,8 @@ int u_audio_start_playback(struct g_audio *audio_dev)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
} }
set_active(&uac->p_prm, true);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(u_audio_start_playback); EXPORT_SYMBOL_GPL(u_audio_start_playback);
@@ -607,10 +752,117 @@ void u_audio_stop_playback(struct g_audio *audio_dev)
{ {
struct snd_uac_chip *uac = audio_dev->uac; struct snd_uac_chip *uac = audio_dev->uac;
set_active(&uac->p_prm, false);
free_ep(&uac->p_prm, audio_dev->in_ep); free_ep(&uac->p_prm, audio_dev->in_ep);
} }
EXPORT_SYMBOL_GPL(u_audio_stop_playback); EXPORT_SYMBOL_GPL(u_audio_stop_playback);
void u_audio_suspend(struct g_audio *audio_dev)
{
struct snd_uac_chip *uac = audio_dev->uac;
set_active(&uac->p_prm, false);
set_active(&uac->c_prm, false);
}
EXPORT_SYMBOL_GPL(u_audio_suspend);
int u_audio_get_volume(struct g_audio *audio_dev, int playback, s16 *val)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
unsigned long flags;
if (playback)
prm = &uac->p_prm;
else
prm = &uac->c_prm;
spin_lock_irqsave(&prm->lock, flags);
*val = prm->volume;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_get_volume);
int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
unsigned long flags;
int change = 0;
if (playback)
prm = &uac->p_prm;
else
prm = &uac->c_prm;
spin_lock_irqsave(&prm->lock, flags);
val = clamp(val, prm->volume_min, prm->volume_max);
if (prm->volume != val) {
prm->volume = val;
change = 1;
}
spin_unlock_irqrestore(&prm->lock, flags);
if (change)
snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
&prm->snd_kctl_volume->id);
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_set_volume);
int u_audio_get_mute(struct g_audio *audio_dev, int playback, int *val)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
unsigned long flags;
if (playback)
prm = &uac->p_prm;
else
prm = &uac->c_prm;
spin_lock_irqsave(&prm->lock, flags);
*val = prm->mute;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_get_mute);
int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct uac_rtd_params *prm;
unsigned long flags;
int change = 0;
int mute;
if (playback)
prm = &uac->p_prm;
else
prm = &uac->c_prm;
mute = val ? 1 : 0;
spin_lock_irqsave(&prm->lock, flags);
if (prm->mute != mute) {
prm->mute = mute;
change = 1;
}
spin_unlock_irqrestore(&prm->lock, flags);
if (change)
snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
&prm->snd_kctl_mute->id);
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_set_mute);
static int u_audio_pitch_info(struct snd_kcontrol *kcontrol, static int u_audio_pitch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo) struct snd_ctl_elem_info *uinfo)
{ {
@@ -670,14 +922,234 @@ static int u_audio_pitch_put(struct snd_kcontrol *kcontrol,
return change; return change;
} }
static const struct snd_kcontrol_new u_audio_controls[] = { static int u_audio_mute_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{ {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
uinfo->value.integer.step = 1;
return 0;
}
static int u_audio_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
unsigned long flags;
spin_lock_irqsave(&prm->lock, flags);
ucontrol->value.integer.value[0] = !prm->mute;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
static int u_audio_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
struct snd_uac_chip *uac = prm->uac;
struct g_audio *audio_dev = uac->audio_dev;
unsigned int val;
unsigned long flags;
int change = 0;
val = !ucontrol->value.integer.value[0];
spin_lock_irqsave(&prm->lock, flags);
if (val != prm->mute) {
prm->mute = val;
change = 1;
}
spin_unlock_irqrestore(&prm->lock, flags);
if (change && audio_dev->notify)
audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_MUTE);
return change;
}
/*
* TLV callback for mixer volume controls
*/
static int u_audio_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
DECLARE_TLV_DB_MINMAX(scale, 0, 0);
if (size < sizeof(scale))
return -ENOMEM;
/* UAC volume resolution is 1/256 dB, TLV is 1/100 dB */
scale[2] = (prm->volume_min * 100) / 256;
scale[3] = (prm->volume_max * 100) / 256;
if (copy_to_user(_tlv, scale, sizeof(scale)))
return -EFAULT;
return 0;
}
static int u_audio_volume_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max =
(prm->volume_max - prm->volume_min + prm->volume_res - 1)
/ prm->volume_res;
uinfo->value.integer.step = 1;
return 0;
}
static int u_audio_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
unsigned long flags;
spin_lock_irqsave(&prm->lock, flags);
ucontrol->value.integer.value[0] =
(prm->volume - prm->volume_min) / prm->volume_res;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
static int u_audio_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
struct snd_uac_chip *uac = prm->uac;
struct g_audio *audio_dev = uac->audio_dev;
unsigned int val;
s16 volume;
unsigned long flags;
int change = 0;
val = ucontrol->value.integer.value[0];
spin_lock_irqsave(&prm->lock, flags);
volume = (val * prm->volume_res) + prm->volume_min;
volume = clamp(volume, prm->volume_min, prm->volume_max);
if (volume != prm->volume) {
prm->volume = volume;
change = 1;
}
spin_unlock_irqrestore(&prm->lock, flags);
if (change && audio_dev->notify)
audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_VOLUME);
return change;
}
static int get_max_srate(const int *srates)
{
int i, max_srate = 0;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (srates[i] == 0)
break;
if (srates[i] > max_srate)
max_srate = srates[i];
}
return max_srate;
}
static int get_min_srate(const int *srates)
{
int i, min_srate = INT_MAX;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (srates[i] == 0)
break;
if (srates[i] < min_srate)
min_srate = srates[i];
}
return min_srate;
}
static int u_audio_rate_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
const int *srates;
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
struct snd_uac_chip *uac = prm->uac;
struct g_audio *audio_dev = uac->audio_dev;
struct uac_params *params = &audio_dev->params;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
if (prm == &uac->c_prm)
srates = params->c_srates;
else
srates = params->p_srates;
uinfo->value.integer.min = get_min_srate(srates);
uinfo->value.integer.max = get_max_srate(srates);
return 0;
}
static int u_audio_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
unsigned long flags;
spin_lock_irqsave(&prm->lock, flags);
if (prm->active)
ucontrol->value.integer.value[0] = prm->srate;
else
/* not active: reporting zero rate */
ucontrol->value.integer.value[0] = 0;
spin_unlock_irqrestore(&prm->lock, flags);
return 0;
}
static struct snd_kcontrol_new u_audio_controls[] = {
[UAC_FBACK_CTRL] {
.iface = SNDRV_CTL_ELEM_IFACE_PCM, .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Capture Pitch 1000000", .name = "Capture Pitch 1000000",
.info = u_audio_pitch_info, .info = u_audio_pitch_info,
.get = u_audio_pitch_get, .get = u_audio_pitch_get,
.put = u_audio_pitch_put, .put = u_audio_pitch_put,
}, },
[UAC_P_PITCH_CTRL] {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Playback Pitch 1000000",
.info = u_audio_pitch_info,
.get = u_audio_pitch_get,
.put = u_audio_pitch_put,
},
[UAC_MUTE_CTRL] {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "", /* will be filled later */
.info = u_audio_mute_info,
.get = u_audio_mute_get,
.put = u_audio_mute_put,
},
[UAC_VOLUME_CTRL] {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "", /* will be filled later */
.info = u_audio_volume_info,
.get = u_audio_volume_get,
.put = u_audio_volume_put,
},
[UAC_RATE_CTRL] {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "", /* will be filled later */
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = u_audio_rate_info,
.get = u_audio_rate_get,
},
}; };
int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
@@ -689,7 +1161,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
struct uac_params *params; struct uac_params *params;
int p_chmask, c_chmask; int p_chmask, c_chmask;
int err; int i, err;
if (!g_audio) if (!g_audio)
return -EINVAL; return -EINVAL;
@@ -707,8 +1179,10 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
if (c_chmask) { if (c_chmask) {
struct uac_rtd_params *prm = &uac->c_prm; struct uac_rtd_params *prm = &uac->c_prm;
spin_lock_init(&prm->lock);
uac->c_prm.uac = uac; uac->c_prm.uac = uac;
prm->max_psize = g_audio->out_ep_maxpsize; prm->max_psize = g_audio->out_ep_maxpsize;
prm->srate = params->c_srates[0];
prm->reqs = kcalloc(params->req_number, prm->reqs = kcalloc(params->req_number,
sizeof(struct usb_request *), sizeof(struct usb_request *),
@@ -730,8 +1204,10 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
if (p_chmask) { if (p_chmask) {
struct uac_rtd_params *prm = &uac->p_prm; struct uac_rtd_params *prm = &uac->p_prm;
spin_lock_init(&prm->lock);
uac->p_prm.uac = uac; uac->p_prm.uac = uac;
prm->max_psize = g_audio->in_ep_maxpsize; prm->max_psize = g_audio->in_ep_maxpsize;
prm->srate = params->p_srates[0];
prm->reqs = kcalloc(params->req_number, prm->reqs = kcalloc(params->req_number,
sizeof(struct usb_request *), sizeof(struct usb_request *),
@@ -774,10 +1250,18 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
if (c_chmask && g_audio->in_ep_fback) { /*
* Create mixer and controls
* Create only if it's required on USB side
*/
if ((c_chmask && g_audio->in_ep_fback)
|| (p_chmask && params->p_fu.id)
|| (c_chmask && params->c_fu.id))
strscpy(card->mixername, card_name, sizeof(card->driver)); strscpy(card->mixername, card_name, sizeof(card->driver));
kctl = snd_ctl_new1(&u_audio_controls[0], &uac->c_prm); if (c_chmask && g_audio->in_ep_fback) {
kctl = snd_ctl_new1(&u_audio_controls[UAC_FBACK_CTRL],
&uac->c_prm);
if (!kctl) { if (!kctl) {
err = -ENOMEM; err = -ENOMEM;
goto snd_fail; goto snd_fail;
@@ -791,6 +1275,117 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
goto snd_fail; goto snd_fail;
} }
if (p_chmask) {
kctl = snd_ctl_new1(&u_audio_controls[UAC_P_PITCH_CTRL],
&uac->p_prm);
if (!kctl) {
err = -ENOMEM;
goto snd_fail;
}
kctl->id.device = pcm->device;
kctl->id.subdevice = 0;
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
}
for (i = 0; i <= SNDRV_PCM_STREAM_LAST; i++) {
struct uac_rtd_params *prm;
struct uac_fu_params *fu;
char ctrl_name[24];
char *direction;
if (!pcm->streams[i].substream_count)
continue;
if (i == SNDRV_PCM_STREAM_PLAYBACK) {
prm = &uac->p_prm;
fu = &params->p_fu;
direction = "Playback";
} else {
prm = &uac->c_prm;
fu = &params->c_fu;
direction = "Capture";
}
prm->fu_id = fu->id;
if (fu->mute_present) {
snprintf(ctrl_name, sizeof(ctrl_name),
"PCM %s Switch", direction);
u_audio_controls[UAC_MUTE_CTRL].name = ctrl_name;
kctl = snd_ctl_new1(&u_audio_controls[UAC_MUTE_CTRL],
prm);
if (!kctl) {
err = -ENOMEM;
goto snd_fail;
}
kctl->id.device = pcm->device;
kctl->id.subdevice = 0;
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
prm->snd_kctl_mute = kctl;
prm->mute = 0;
}
if (fu->volume_present) {
snprintf(ctrl_name, sizeof(ctrl_name),
"PCM %s Volume", direction);
u_audio_controls[UAC_VOLUME_CTRL].name = ctrl_name;
kctl = snd_ctl_new1(&u_audio_controls[UAC_VOLUME_CTRL],
prm);
if (!kctl) {
err = -ENOMEM;
goto snd_fail;
}
kctl->id.device = pcm->device;
kctl->id.subdevice = 0;
kctl->tlv.c = u_audio_volume_tlv;
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
prm->snd_kctl_volume = kctl;
prm->volume = fu->volume_max;
prm->volume_max = fu->volume_max;
prm->volume_min = fu->volume_min;
prm->volume_res = fu->volume_res;
}
/* Add rate control */
snprintf(ctrl_name, sizeof(ctrl_name),
"%s Rate", direction);
u_audio_controls[UAC_RATE_CTRL].name = ctrl_name;
kctl = snd_ctl_new1(&u_audio_controls[UAC_RATE_CTRL], prm);
if (!kctl) {
err = -ENOMEM;
goto snd_fail;
}
kctl->id.device = pcm->device;
kctl->id.subdevice = 0;
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
prm->snd_kctl_rate = kctl;
}
strscpy(card->driver, card_name, sizeof(card->driver)); strscpy(card->driver, card_name, sizeof(card->driver));
strscpy(card->shortname, card_name, sizeof(card->shortname)); strscpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id); sprintf(card->longname, "%s %i", card_name, card->dev->id);

View File

@@ -10,25 +10,48 @@
#define __U_AUDIO_H #define __U_AUDIO_H
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include "uac_common.h"
/* /*
* Same maximum frequency deviation on the slower side as in * Same maximum frequency deviation on the slower side as in
* sound/usb/endpoint.c. Value is expressed in per-mil deviation. * sound/usb/endpoint.c. Value is expressed in per-mil deviation.
* The maximum deviation on the faster side will be provided as
* parameter, as it impacts the endpoint required bandwidth.
*/ */
#define FBACK_SLOW_MAX 250 #define FBACK_SLOW_MAX 250
/*
* Maximum frequency deviation on the faster side, default value for UAC1/2.
* Value is expressed in per-mil deviation.
* UAC2 provides the value as a parameter as it impacts the endpoint required
* bandwidth.
*/
#define FBACK_FAST_MAX 5
/* Feature Unit parameters */
struct uac_fu_params {
int id; /* Feature Unit ID */
bool mute_present; /* mute control enable */
bool volume_present; /* volume control enable */
s16 volume_min; /* min volume in 1/256 dB */
s16 volume_max; /* max volume in 1/256 dB */
s16 volume_res; /* volume resolution in 1/256 dB */
};
struct uac_params { struct uac_params {
/* playback */ /* playback */
int p_chmask; /* channel mask */ int p_chmask; /* channel mask */
int p_srate; /* rate in Hz */ int p_srates[UAC_MAX_RATES]; /* available rates in Hz (0 terminated list) */
int p_ssize; /* sample size */ int p_ssize; /* sample size */
struct uac_fu_params p_fu; /* Feature Unit parameters */
/* capture */ /* capture */
int c_chmask; /* channel mask */ int c_chmask; /* channel mask */
int c_srate; /* rate in Hz */ int c_srates[UAC_MAX_RATES]; /* available rates in Hz (0 terminated list) */
int c_ssize; /* sample size */ int c_ssize; /* sample size */
struct uac_fu_params c_fu; /* Feature Unit parameters */
/* rates are dynamic, in uac_rtd_params */
int req_number; /* number of preallocated requests */ int req_number; /* number of preallocated requests */
int fb_max; /* upper frequency drift feedback limit per-mil */ int fb_max; /* upper frequency drift feedback limit per-mil */
@@ -49,6 +72,9 @@ struct g_audio {
/* Max packet size for all out_ep possible speeds */ /* Max packet size for all out_ep possible speeds */
unsigned int out_ep_maxpsize; unsigned int out_ep_maxpsize;
/* Notify UAC driver about control change */
int (*notify)(struct g_audio *g_audio, int unit_id, int cs);
/* The ALSA Sound Card it represents on the USB-Client side */ /* The ALSA Sound Card it represents on the USB-Client side */
struct snd_uac_chip *uac; struct snd_uac_chip *uac;
@@ -94,4 +120,16 @@ void u_audio_stop_capture(struct g_audio *g_audio);
int u_audio_start_playback(struct g_audio *g_audio); int u_audio_start_playback(struct g_audio *g_audio);
void u_audio_stop_playback(struct g_audio *g_audio); void u_audio_stop_playback(struct g_audio *g_audio);
int u_audio_get_capture_srate(struct g_audio *audio_dev, u32 *val);
int u_audio_set_capture_srate(struct g_audio *audio_dev, int srate);
int u_audio_get_playback_srate(struct g_audio *audio_dev, u32 *val);
int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate);
int u_audio_get_volume(struct g_audio *g_audio, int playback, s16 *val);
int u_audio_set_volume(struct g_audio *g_audio, int playback, s16 val);
int u_audio_get_mute(struct g_audio *g_audio, int playback, int *val);
int u_audio_set_mute(struct g_audio *g_audio, int playback, int val);
void u_audio_suspend(struct g_audio *g_audio);
#endif /* __U_AUDIO_H */ #endif /* __U_AUDIO_H */

View File

@@ -9,6 +9,7 @@
#define __U_UAC1_H #define __U_UAC1_H
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include "uac_common.h"
#define UAC1_OUT_EP_MAX_PACKET_SIZE 200 #define UAC1_OUT_EP_MAX_PACKET_SIZE 200
#define UAC1_DEF_CCHMASK 0x3 #define UAC1_DEF_CCHMASK 0x3
@@ -18,19 +19,41 @@
#define UAC1_DEF_PSRATE 48000 #define UAC1_DEF_PSRATE 48000
#define UAC1_DEF_PSSIZE 2 #define UAC1_DEF_PSSIZE 2
#define UAC1_DEF_REQ_NUM 2 #define UAC1_DEF_REQ_NUM 2
#define UAC1_DEF_INT_REQ_NUM 10
#define UAC1_DEF_MUTE_PRESENT 1
#define UAC1_DEF_VOLUME_PRESENT 1
#define UAC1_DEF_MIN_DB (-100*256) /* -100 dB */
#define UAC1_DEF_MAX_DB 0 /* 0 dB */
#define UAC1_DEF_RES_DB (1*256) /* 1 dB */
struct f_uac1_opts { struct f_uac1_opts {
struct usb_function_instance func_inst; struct usb_function_instance func_inst;
int c_chmask; int c_chmask;
int c_srate; int c_srates[UAC_MAX_RATES];
int c_ssize; int c_ssize;
int p_chmask; int p_chmask;
int p_srate; int p_srates[UAC_MAX_RATES];
int p_ssize; int p_ssize;
bool p_mute_present;
bool p_volume_present;
s16 p_volume_min;
s16 p_volume_max;
s16 p_volume_res;
bool c_mute_present;
bool c_volume_present;
s16 c_volume_min;
s16 c_volume_max;
s16 c_volume_res;
int req_number; int req_number;
unsigned bound:1; unsigned bound:1;
char function_name[32];
struct mutex lock; struct mutex lock;
int refcnt; int refcnt;
}; };

View File

@@ -14,6 +14,7 @@
#define U_UAC2_H #define U_UAC2_H
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include "uac_common.h"
#define UAC2_DEF_PCHMASK 0x3 #define UAC2_DEF_PCHMASK 0x3
#define UAC2_DEF_PSRATE 48000 #define UAC2_DEF_PSRATE 48000
@@ -22,22 +23,44 @@
#define UAC2_DEF_CSRATE 64000 #define UAC2_DEF_CSRATE 64000
#define UAC2_DEF_CSSIZE 2 #define UAC2_DEF_CSSIZE 2
#define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC #define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC
#define UAC2_DEF_MUTE_PRESENT 1
#define UAC2_DEF_VOLUME_PRESENT 1
#define UAC2_DEF_MIN_DB (-100*256) /* -100 dB */
#define UAC2_DEF_MAX_DB 0 /* 0 dB */
#define UAC2_DEF_RES_DB (1*256) /* 1 dB */
#define UAC2_DEF_REQ_NUM 2 #define UAC2_DEF_REQ_NUM 2
#define UAC2_DEF_FB_MAX 5 #define UAC2_DEF_INT_REQ_NUM 10
struct f_uac2_opts { struct f_uac2_opts {
struct usb_function_instance func_inst; struct usb_function_instance func_inst;
int p_chmask; int p_chmask;
int p_srate; int p_srates[UAC_MAX_RATES];
int p_ssize; int p_ssize;
int c_chmask; int c_chmask;
int c_srate; int c_srates[UAC_MAX_RATES];
int c_ssize; int c_ssize;
int c_sync; int c_sync;
bool p_mute_present;
bool p_volume_present;
s16 p_volume_min;
s16 p_volume_max;
s16 p_volume_res;
bool c_mute_present;
bool c_volume_present;
s16 c_volume_min;
s16 c_volume_max;
s16 c_volume_res;
int req_number; int req_number;
int fb_max; int fb_max;
bool bound; bool bound;
char function_name[32];
struct mutex lock; struct mutex lock;
int refcnt; int refcnt;
}; };

View File

@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
*/
#ifndef UAC_COMMON_H
#define UAC_COMMON_H
#define UAC_MAX_RATES 10 /* maximum number of rates configurable by f_uac1/2 */
#endif

View File

@@ -22,32 +22,34 @@ USB_GADGET_COMPOSITE_OPTIONS();
/* Playback(USB-IN) Default Stereo - Fl/Fr */ /* Playback(USB-IN) Default Stereo - Fl/Fr */
static int p_chmask = UAC2_DEF_PCHMASK; static int p_chmask = UAC2_DEF_PCHMASK;
module_param(p_chmask, uint, S_IRUGO); module_param(p_chmask, uint, 0444);
MODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
/* Playback Default 48 KHz */ /* Playback Default 48 KHz */
static int p_srate = UAC2_DEF_PSRATE; static int p_srates[UAC_MAX_RATES] = {UAC2_DEF_PSRATE};
module_param(p_srate, uint, S_IRUGO); static int p_srates_cnt = 1;
MODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); module_param_array_named(p_srate, p_srates, uint, &p_srates_cnt, 0444);
MODULE_PARM_DESC(p_srate, "Playback Sampling Rates (array)");
/* Playback Default 16bits/sample */ /* Playback Default 16bits/sample */
static int p_ssize = UAC2_DEF_PSSIZE; static int p_ssize = UAC2_DEF_PSSIZE;
module_param(p_ssize, uint, S_IRUGO); module_param(p_ssize, uint, 0444);
MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
/* Capture(USB-OUT) Default Stereo - Fl/Fr */ /* Capture(USB-OUT) Default Stereo - Fl/Fr */
static int c_chmask = UAC2_DEF_CCHMASK; static int c_chmask = UAC2_DEF_CCHMASK;
module_param(c_chmask, uint, S_IRUGO); module_param(c_chmask, uint, 0444);
MODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
/* Capture Default 64 KHz */ /* Capture Default 64 KHz */
static int c_srate = UAC2_DEF_CSRATE; static int c_srates[UAC_MAX_RATES] = {UAC2_DEF_CSRATE};
module_param(c_srate, uint, S_IRUGO); static int c_srates_cnt = 1;
MODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); module_param_array_named(c_srate, c_srates, uint, &c_srates_cnt, 0444);
MODULE_PARM_DESC(c_srate, "Capture Sampling Rates (array)");
/* Capture Default 16bits/sample */ /* Capture Default 16bits/sample */
static int c_ssize = UAC2_DEF_CSSIZE; static int c_ssize = UAC2_DEF_CSSIZE;
module_param(c_ssize, uint, S_IRUGO); module_param(c_ssize, uint, 0444);
MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
#else #else
#ifndef CONFIG_GADGET_UAC1_LEGACY #ifndef CONFIG_GADGET_UAC1_LEGACY
@@ -55,58 +57,60 @@ MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
/* Playback(USB-IN) Default Stereo - Fl/Fr */ /* Playback(USB-IN) Default Stereo - Fl/Fr */
static int p_chmask = UAC1_DEF_PCHMASK; static int p_chmask = UAC1_DEF_PCHMASK;
module_param(p_chmask, uint, S_IRUGO); module_param(p_chmask, uint, 0444);
MODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
/* Playback Default 48 KHz */ /* Playback Default 48 KHz */
static int p_srate = UAC1_DEF_PSRATE; static int p_srates[UAC_MAX_RATES] = {UAC1_DEF_PSRATE};
module_param(p_srate, uint, S_IRUGO); static int p_srates_cnt = 1;
MODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); module_param_array_named(p_srate, p_srates, uint, &p_srates_cnt, 0444);
MODULE_PARM_DESC(p_srate, "Playback Sampling Rates (array)");
/* Playback Default 16bits/sample */ /* Playback Default 16bits/sample */
static int p_ssize = UAC1_DEF_PSSIZE; static int p_ssize = UAC1_DEF_PSSIZE;
module_param(p_ssize, uint, S_IRUGO); module_param(p_ssize, uint, 0444);
MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
/* Capture(USB-OUT) Default Stereo - Fl/Fr */ /* Capture(USB-OUT) Default Stereo - Fl/Fr */
static int c_chmask = UAC1_DEF_CCHMASK; static int c_chmask = UAC1_DEF_CCHMASK;
module_param(c_chmask, uint, S_IRUGO); module_param(c_chmask, uint, 0444);
MODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
/* Capture Default 48 KHz */ /* Capture Default 48 KHz */
static int c_srate = UAC1_DEF_CSRATE; static int c_srates[UAC_MAX_RATES] = {UAC1_DEF_CSRATE};
module_param(c_srate, uint, S_IRUGO); static int c_srates_cnt = 1;
MODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); module_param_array_named(c_srate, c_srates, uint, &c_srates_cnt, 0444);
MODULE_PARM_DESC(c_srate, "Capture Sampling Rates (array)");
/* Capture Default 16bits/sample */ /* Capture Default 16bits/sample */
static int c_ssize = UAC1_DEF_CSSIZE; static int c_ssize = UAC1_DEF_CSSIZE;
module_param(c_ssize, uint, S_IRUGO); module_param(c_ssize, uint, 0444);
MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
#else /* CONFIG_GADGET_UAC1_LEGACY */ #else /* CONFIG_GADGET_UAC1_LEGACY */
#include "u_uac1_legacy.h" #include "u_uac1_legacy.h"
static char *fn_play = FILE_PCM_PLAYBACK; static char *fn_play = FILE_PCM_PLAYBACK;
module_param(fn_play, charp, S_IRUGO); module_param(fn_play, charp, 0444);
MODULE_PARM_DESC(fn_play, "Playback PCM device file name"); MODULE_PARM_DESC(fn_play, "Playback PCM device file name");
static char *fn_cap = FILE_PCM_CAPTURE; static char *fn_cap = FILE_PCM_CAPTURE;
module_param(fn_cap, charp, S_IRUGO); module_param(fn_cap, charp, 0444);
MODULE_PARM_DESC(fn_cap, "Capture PCM device file name"); MODULE_PARM_DESC(fn_cap, "Capture PCM device file name");
static char *fn_cntl = FILE_CONTROL; static char *fn_cntl = FILE_CONTROL;
module_param(fn_cntl, charp, S_IRUGO); module_param(fn_cntl, charp, 0444);
MODULE_PARM_DESC(fn_cntl, "Control device file name"); MODULE_PARM_DESC(fn_cntl, "Control device file name");
static int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE; static int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE;
module_param(req_buf_size, int, S_IRUGO); module_param(req_buf_size, int, 0444);
MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
static int req_count = UAC1_REQ_COUNT; static int req_count = UAC1_REQ_COUNT;
module_param(req_count, int, S_IRUGO); module_param(req_count, int, 0444);
MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count"); MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
static int audio_buf_size = UAC1_AUDIO_BUF_SIZE; static int audio_buf_size = UAC1_AUDIO_BUF_SIZE;
module_param(audio_buf_size, int, S_IRUGO); module_param(audio_buf_size, int, 0444);
MODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
#endif /* CONFIG_GADGET_UAC1_LEGACY */ #endif /* CONFIG_GADGET_UAC1_LEGACY */
#endif #endif
@@ -237,9 +241,11 @@ static int audio_bind(struct usb_composite_dev *cdev)
{ {
#ifndef CONFIG_GADGET_UAC1 #ifndef CONFIG_GADGET_UAC1
struct f_uac2_opts *uac2_opts; struct f_uac2_opts *uac2_opts;
int i;
#else #else
#ifndef CONFIG_GADGET_UAC1_LEGACY #ifndef CONFIG_GADGET_UAC1_LEGACY
struct f_uac1_opts *uac1_opts; struct f_uac1_opts *uac1_opts;
int i;
#else #else
struct f_uac1_legacy_opts *uac1_opts; struct f_uac1_legacy_opts *uac1_opts;
#endif #endif
@@ -263,20 +269,32 @@ static int audio_bind(struct usb_composite_dev *cdev)
#ifndef CONFIG_GADGET_UAC1 #ifndef CONFIG_GADGET_UAC1
uac2_opts = container_of(fi_uac2, struct f_uac2_opts, func_inst); uac2_opts = container_of(fi_uac2, struct f_uac2_opts, func_inst);
uac2_opts->p_chmask = p_chmask; uac2_opts->p_chmask = p_chmask;
uac2_opts->p_srate = p_srate;
for (i = 0; i < p_srates_cnt; ++i)
uac2_opts->p_srates[i] = p_srates[i];
uac2_opts->p_ssize = p_ssize; uac2_opts->p_ssize = p_ssize;
uac2_opts->c_chmask = c_chmask; uac2_opts->c_chmask = c_chmask;
uac2_opts->c_srate = c_srate;
for (i = 0; i < c_srates_cnt; ++i)
uac2_opts->c_srates[i] = c_srates[i];
uac2_opts->c_ssize = c_ssize; uac2_opts->c_ssize = c_ssize;
uac2_opts->req_number = UAC2_DEF_REQ_NUM; uac2_opts->req_number = UAC2_DEF_REQ_NUM;
#else #else
#ifndef CONFIG_GADGET_UAC1_LEGACY #ifndef CONFIG_GADGET_UAC1_LEGACY
uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst); uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
uac1_opts->p_chmask = p_chmask; uac1_opts->p_chmask = p_chmask;
uac1_opts->p_srate = p_srate;
for (i = 0; i < p_srates_cnt; ++i)
uac1_opts->p_srates[i] = p_srates[i];
uac1_opts->p_ssize = p_ssize; uac1_opts->p_ssize = p_ssize;
uac1_opts->c_chmask = c_chmask; uac1_opts->c_chmask = c_chmask;
uac1_opts->c_srate = c_srate;
for (i = 0; i < c_srates_cnt; ++i)
uac1_opts->c_srates[i] = c_srates[i];
uac1_opts->c_ssize = c_ssize; uac1_opts->c_ssize = c_ssize;
uac1_opts->req_number = UAC1_DEF_REQ_NUM; uac1_opts->req_number = UAC1_DEF_REQ_NUM;
#else /* CONFIG_GADGET_UAC1_LEGACY */ #else /* CONFIG_GADGET_UAC1_LEGACY */

View File

@@ -160,7 +160,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync)
return 0; return 0;
} }
void exfat_clear_bitmap(struct inode *inode, unsigned int clu) void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
{ {
int i, b; int i, b;
unsigned int ent_idx; unsigned int ent_idx;
@@ -176,7 +176,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
clear_bit_le(b, sbi->vol_amap[i]->b_data); clear_bit_le(b, sbi->vol_amap[i]->b_data);
exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); exfat_update_bh(sbi->vol_amap[i], sync);
if (opts->discard) { if (opts->discard) {
int ret_discard; int ret_discard;

View File

@@ -416,7 +416,7 @@ int exfat_count_num_clusters(struct super_block *sb,
int exfat_load_bitmap(struct super_block *sb); int exfat_load_bitmap(struct super_block *sb);
void exfat_free_bitmap(struct exfat_sb_info *sbi); void exfat_free_bitmap(struct exfat_sb_info *sbi);
int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync); int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync);
void exfat_clear_bitmap(struct inode *inode, unsigned int clu); void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync);
unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu); unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu);
int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count); int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);

View File

@@ -149,6 +149,7 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
unsigned int clu; unsigned int clu;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
int cur_cmap_i, next_cmap_i;
/* invalid cluster number */ /* invalid cluster number */
if (p_chain->dir == EXFAT_FREE_CLUSTER || if (p_chain->dir == EXFAT_FREE_CLUSTER ||
@@ -168,21 +169,53 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
clu = p_chain->dir; clu = p_chain->dir;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { cur_cmap_i = next_cmap_i =
do { BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu));
exfat_clear_bitmap(inode, clu);
clu++;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
unsigned int last_cluster = p_chain->dir + p_chain->size - 1;
do {
bool sync = false;
if (clu < last_cluster)
next_cmap_i =
BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu+1));
/* flush bitmap only if index would be changed or for last cluster */
if (clu == last_cluster || cur_cmap_i != next_cmap_i) {
sync = true;
cur_cmap_i = next_cmap_i;
}
exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
clu++;
num_clusters++; num_clusters++;
} while (num_clusters < p_chain->size); } while (num_clusters < p_chain->size);
} else { } else {
do { do {
exfat_clear_bitmap(inode, clu); bool sync = false;
unsigned int n_clu = clu;
int err = exfat_get_next_cluster(sb, &n_clu);
if (exfat_get_next_cluster(sb, &clu)) if (err || n_clu == EXFAT_EOF_CLUSTER)
goto dec_used_clus; sync = true;
else
next_cmap_i =
BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(n_clu));
if (cur_cmap_i != next_cmap_i) {
sync = true;
cur_cmap_i = next_cmap_i;
}
exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
clu = n_clu;
num_clusters++; num_clusters++;
if (err)
goto dec_used_clus;
} while (clu != EXFAT_EOF_CLUSTER); } while (clu != EXFAT_EOF_CLUSTER);
} }

View File

@@ -4217,8 +4217,9 @@ static inline void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi,
#define inc_compr_inode_stat(inode) do { } while (0) #define inc_compr_inode_stat(inode) do { } while (0)
#endif #endif
static inline void set_compress_context(struct inode *inode) static inline int set_compress_context(struct inode *inode)
{ {
#ifdef CONFIG_F2FS_FS_COMPRESSION
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
F2FS_I(inode)->i_compress_algorithm = F2FS_I(inode)->i_compress_algorithm =
@@ -4240,6 +4241,10 @@ static inline void set_compress_context(struct inode *inode)
stat_inc_compr_inode(inode); stat_inc_compr_inode(inode);
inc_compr_inode_stat(inode); inc_compr_inode_stat(inode);
f2fs_mark_inode_dirty_sync(inode, true); f2fs_mark_inode_dirty_sync(inode, true);
return 0;
#else
return -EOPNOTSUPP;
#endif
} }
static inline bool f2fs_disable_compressed_file(struct inode *inode) static inline bool f2fs_disable_compressed_file(struct inode *inode)

View File

@@ -1855,8 +1855,8 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
return -EINVAL; return -EINVAL;
if (S_ISREG(inode->i_mode) && inode->i_size) if (S_ISREG(inode->i_mode) && inode->i_size)
return -EINVAL; return -EINVAL;
if (set_compress_context(inode))
set_compress_context(inode); return -EOPNOTSUPP;
} }
} }
if ((iflags ^ masked_flags) & F2FS_NOCOMP_FL) { if ((iflags ^ masked_flags) & F2FS_NOCOMP_FL) {

View File

@@ -282,6 +282,13 @@ struct css_set {
struct rcu_head rcu_head; struct rcu_head rcu_head;
}; };
struct ext_css_set {
struct css_set cset;
struct list_head mg_src_preload_node;
struct list_head mg_dst_preload_node;
};
struct cgroup_base_stat { struct cgroup_base_stat {
struct task_cputime cputime; struct task_cputime cputime;
}; };

View File

@@ -72,7 +72,8 @@ struct css_task_iter {
}; };
extern struct cgroup_root cgrp_dfl_root; extern struct cgroup_root cgrp_dfl_root;
extern struct css_set init_css_set; extern struct ext_css_set init_ext_css_set;
#define init_css_set init_ext_css_set.cset
#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys;
#include <linux/cgroup_subsys.h> #include <linux/cgroup_subsys.h>

View File

@@ -345,6 +345,9 @@ struct mem_cgroup {
extern struct mem_cgroup *root_mem_cgroup; extern struct mem_cgroup *root_mem_cgroup;
struct lruvec *page_to_lruvec(struct page *page, pg_data_t *pgdat);
void do_traversal_all_lruvec(void);
static __always_inline bool memcg_stat_item_in_bytes(int idx) static __always_inline bool memcg_stat_item_in_bytes(int idx)
{ {
if (idx == MEMCG_PERCPU_B) if (idx == MEMCG_PERCPU_B)
@@ -969,6 +972,15 @@ void split_page_memcg(struct page *head, unsigned int nr);
struct mem_cgroup; struct mem_cgroup;
static inline struct lruvec *page_to_lruvec(struct page *page, pg_data_t *pgdat)
{
return NULL;
}
static inline void do_traversal_all_lruvec(void)
{
}
static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg) static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
{ {
return true; return true;

View File

@@ -3363,7 +3363,6 @@ unsigned long wp_shared_mapping_range(struct address_space *mapping,
extern int sysctl_nr_trim_pages; extern int sysctl_nr_trim_pages;
extern bool pte_map_lock_addr(struct vm_fault *vmf, unsigned long addr); extern bool pte_map_lock_addr(struct vm_fault *vmf, unsigned long addr);
extern int reclaim_shmem_address_space(struct address_space *mapping); extern int reclaim_shmem_address_space(struct address_space *mapping);
extern int reclaim_pages_from_list(struct list_head *page_list);
/** /**
* seal_check_future_write - Check for F_SEAL_FUTURE_WRITE flag and handle it * seal_check_future_write - Check for F_SEAL_FUTURE_WRITE flag and handle it

View File

@@ -4,6 +4,10 @@
#include <linux/huge_mm.h> #include <linux/huge_mm.h>
#include <linux/swap.h> #include <linux/swap.h>
#ifndef __GENKSYMS__
#define PROTECT_TRACE_INCLUDE_PATH
#include <trace/hooks/mm.h>
#endif
/** /**
* page_is_file_lru - should the page be on a file LRU or anon LRU? * page_is_file_lru - should the page be on a file LRU or anon LRU?
@@ -48,6 +52,7 @@ static __always_inline void update_lru_size(struct lruvec *lruvec,
static __always_inline void add_page_to_lru_list(struct page *page, static __always_inline void add_page_to_lru_list(struct page *page,
struct lruvec *lruvec, enum lru_list lru) struct lruvec *lruvec, enum lru_list lru)
{ {
trace_android_vh_add_page_to_lrulist(page, false, lru);
update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
list_add(&page->lru, &lruvec->lists[lru]); list_add(&page->lru, &lruvec->lists[lru]);
} }
@@ -55,6 +60,7 @@ static __always_inline void add_page_to_lru_list(struct page *page,
static __always_inline void add_page_to_lru_list_tail(struct page *page, static __always_inline void add_page_to_lru_list_tail(struct page *page,
struct lruvec *lruvec, enum lru_list lru) struct lruvec *lruvec, enum lru_list lru)
{ {
trace_android_vh_add_page_to_lrulist(page, false, lru);
update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page));
list_add_tail(&page->lru, &lruvec->lists[lru]); list_add_tail(&page->lru, &lruvec->lists[lru]);
} }
@@ -62,6 +68,7 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page,
static __always_inline void del_page_from_lru_list(struct page *page, static __always_inline void del_page_from_lru_list(struct page *page,
struct lruvec *lruvec, enum lru_list lru) struct lruvec *lruvec, enum lru_list lru)
{ {
trace_android_vh_del_page_from_lrulist(page, false, lru);
list_del(&page->lru); list_del(&page->lru);
update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page)); update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page));
} }

View File

@@ -11,6 +11,10 @@
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#ifndef __GENKSYMS__
#define PROTECT_TRACE_INCLUDE_PATH
#include <trace/hooks/mm.h>
#endif
/* /*
* The anon_vma heads a list of private "related" vmas, to scan if * The anon_vma heads a list of private "related" vmas, to scan if
@@ -194,6 +198,11 @@ void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *,
static inline void page_dup_rmap(struct page *page, bool compound) static inline void page_dup_rmap(struct page *page, bool compound)
{ {
bool success = false;
if (!compound)
trace_android_vh_update_page_mapcount(page, true, compound, NULL, &success);
if (!success)
atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount); atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount);
} }

View File

@@ -92,6 +92,13 @@ int sysctl_numa_balancing(struct ctl_table *table, int write, void *buffer,
int sysctl_schedstats(struct ctl_table *table, int write, void *buffer, int sysctl_schedstats(struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos); size_t *lenp, loff_t *ppos);
#ifdef CONFIG_SMP
extern unsigned int sysctl_sched_pelt_multiplier;
int sched_pelt_multiplier(struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos);
#endif
#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) #if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
extern unsigned int sysctl_sched_energy_aware; extern unsigned int sysctl_sched_energy_aware;
int sched_energy_aware_handler(struct ctl_table *table, int write, int sched_energy_aware_handler(struct ctl_table *table, int write,

View File

@@ -156,6 +156,20 @@ struct uac2_feature_unit_descriptor {
__u8 bmaControls[]; /* variable length */ __u8 bmaControls[]; /* variable length */
} __attribute__((packed)); } __attribute__((packed));
#define UAC2_DT_FEATURE_UNIT_SIZE(ch) (6 + ((ch) + 1) * 4)
/* As above, but more useful for defining your own descriptors: */
#define DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR(ch) \
struct uac2_feature_unit_descriptor_##ch { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubtype; \
__u8 bUnitID; \
__u8 bSourceID; \
__le32 bmaControls[ch + 1]; \
__u8 iFeature; \
} __packed
/* 4.7.2.10 Effect Unit Descriptor */ /* 4.7.2.10 Effect Unit Descriptor */
struct uac2_effect_unit_descriptor { struct uac2_effect_unit_descriptor {

View File

@@ -34,6 +34,11 @@ struct hdmi_codec_daifmt {
unsigned int frame_clk_inv:1; unsigned int frame_clk_inv:1;
unsigned int bit_clk_master:1; unsigned int bit_clk_master:1;
unsigned int frame_clk_master:1; unsigned int frame_clk_master:1;
/* bit_fmt could be standard PCM format or
* IEC958 encoded format. ALSA IEC958 plugin will pass
* IEC958_SUBFRAME format to the underneath driver.
*/
snd_pcm_format_t bit_fmt;
}; };
/* /*
@@ -60,12 +65,22 @@ struct hdmi_codec_ops {
/* /*
* Configures HDMI-encoder for audio stream. * Configures HDMI-encoder for audio stream.
* Mandatory * Having either prepare or hw_params is mandatory.
*/ */
int (*hw_params)(struct device *dev, void *data, int (*hw_params)(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt, struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms); struct hdmi_codec_params *hparms);
/*
* Configures HDMI-encoder for audio stream. Can be called
* multiple times for each setup.
*
* Having either prepare or hw_params is mandatory.
*/
int (*prepare)(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms);
/* /*
* Shuts down the audio stream. * Shuts down the audio stream.
* Mandatory * Mandatory

View File

@@ -4,6 +4,14 @@
#include <linux/types.h> #include <linux/types.h>
int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len);
int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len);
int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len);
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len); size_t len);

View File

@@ -11,19 +11,23 @@
* Following tracepoints are not exported in tracefs and provide a * Following tracepoints are not exported in tracefs and provide a
* mechanism for vendor modules to hook and extend functionality * mechanism for vendor modules to hook and extend functionality
*/ */
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_ANDROID_BINDER_IPC)
struct binder_alloc; struct binder_alloc;
struct binder_proc; struct binder_proc;
struct binder_thread; struct binder_thread;
struct binder_transaction; struct binder_transaction;
struct task_struct;
struct seq_file;
struct binder_transaction_data; struct binder_transaction_data;
#else #else
/* struct binder_alloc */ /* struct binder_alloc */
#include <../drivers/android/binder_alloc.h> #include <../drivers/android/binder_alloc.h>
/* struct binder_proc, struct binder_thread, struct binder_transaction */ /* struct binder_proc, struct binder_thread, struct binder_transaction */
#include <../drivers/android/binder_internal.h> #include <../drivers/android/binder_internal.h>
#endif
#ifdef __GENKSYMS__
struct task_struct;
struct seq_file;
#else
/* struct task_struct */ /* struct task_struct */
#include <linux/sched.h> #include <linux/sched.h>
/* struct seq_file */ /* struct seq_file */
@@ -31,6 +35,7 @@ struct binder_transaction_data;
/* struct binder_transaction_data */ /* struct binder_transaction_data */
#include <uapi/linux/android/binder.h> #include <uapi/linux/android/binder.h>
#endif /* __GENKSYMS__ */ #endif /* __GENKSYMS__ */
DECLARE_HOOK(android_vh_binder_transaction_init, DECLARE_HOOK(android_vh_binder_transaction_init,
TP_PROTO(struct binder_transaction *t), TP_PROTO(struct binder_transaction *t),
TP_ARGS(t)); TP_ARGS(t));

View File

@@ -10,7 +10,7 @@
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#include <trace/hooks/vendor_hooks.h> #include <trace/hooks/vendor_hooks.h>
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !defined(CONFIG_BLOCK)
struct blk_mq_tags; struct blk_mq_tags;
struct blk_mq_alloc_data; struct blk_mq_alloc_data;
struct blk_mq_tag_set; struct blk_mq_tag_set;

View File

@@ -9,12 +9,16 @@
#include <trace/hooks/vendor_hooks.h> #include <trace/hooks/vendor_hooks.h>
struct cgroup_taskset; struct cgroup_taskset;
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_CGROUPS)
struct cgroup_subsys; struct cgroup_subsys;
struct task_struct;
#else #else
/* struct cgroup_subsys */ /* struct cgroup_subsys */
#include <linux/cgroup-defs.h> #include <linux/cgroup-defs.h>
#endif
#ifdef __GENKSYMS__
struct task_struct;
#else
/* struct task_struct */ /* struct task_struct */
#include <linux/sched.h> #include <linux/sched.h>
#endif /* __GENKSYMS__ */ #endif /* __GENKSYMS__ */

View File

@@ -10,7 +10,7 @@
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#include <trace/hooks/vendor_hooks.h> #include <trace/hooks/vendor_hooks.h>
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_PRINTK)
struct printk_record; struct printk_record;
struct printk_ringbuffer; struct printk_ringbuffer;
#else #else

View File

@@ -1,4 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
#ifdef PROTECT_TRACE_INCLUDE_PATH
#undef PROTECT_TRACE_INCLUDE_PATH
#include <trace/hooks/save_incpath.h>
#include <trace/hooks/mm.h>
#include <trace/hooks/restore_incpath.h>
#else /* PROTECT_TRACE_INCLUDE_PATH */
#undef TRACE_SYSTEM #undef TRACE_SYSTEM
#define TRACE_SYSTEM mm #define TRACE_SYSTEM mm
@@ -13,6 +22,7 @@
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#include <trace/hooks/vendor_hooks.h> #include <trace/hooks/vendor_hooks.h>
#include <linux/rwsem.h>
#ifdef __GENKSYMS__ #ifdef __GENKSYMS__
struct slabinfo; struct slabinfo;
@@ -87,6 +97,12 @@ DECLARE_HOOK(android_vh_include_reserved_zone,
DECLARE_HOOK(android_vh_show_mem, DECLARE_HOOK(android_vh_show_mem,
TP_PROTO(unsigned int filter, nodemask_t *nodemask), TP_PROTO(unsigned int filter, nodemask_t *nodemask),
TP_ARGS(filter, nodemask)); TP_ARGS(filter, nodemask));
DECLARE_HOOK(android_vh_alloc_pages_slowpath_begin,
TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long *pdata),
TP_ARGS(gfp_mask, order, pdata));
DECLARE_HOOK(android_vh_alloc_pages_slowpath_end,
TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long data),
TP_ARGS(gfp_mask, order, data));
struct dirty_throttle_control; struct dirty_throttle_control;
DECLARE_HOOK(android_vh_mm_dirty_limits, DECLARE_HOOK(android_vh_mm_dirty_limits,
TP_PROTO(struct dirty_throttle_control *const gdtc, bool strictlimit, TP_PROTO(struct dirty_throttle_control *const gdtc, bool strictlimit,
@@ -133,11 +149,37 @@ DECLARE_HOOK(android_vh_mmap_region,
DECLARE_HOOK(android_vh_try_to_unmap_one, DECLARE_HOOK(android_vh_try_to_unmap_one,
TP_PROTO(struct vm_area_struct *vma, struct page *page, unsigned long addr, bool ret), TP_PROTO(struct vm_area_struct *vma, struct page *page, unsigned long addr, bool ret),
TP_ARGS(vma, page, addr, ret)); TP_ARGS(vma, page, addr, ret));
DECLARE_HOOK(android_vh_do_page_trylock,
TP_PROTO(struct page *page, struct rw_semaphore *sem,
bool *got_lock, bool *success),
TP_ARGS(page, sem, got_lock, success));
DECLARE_HOOK(android_vh_drain_all_pages_bypass, DECLARE_HOOK(android_vh_drain_all_pages_bypass,
TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long alloc_flags, TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long alloc_flags,
int migratetype, unsigned long did_some_progress, int migratetype, unsigned long did_some_progress,
bool *bypass), bool *bypass),
TP_ARGS(gfp_mask, order, alloc_flags, migratetype, did_some_progress, bypass)); TP_ARGS(gfp_mask, order, alloc_flags, migratetype, did_some_progress, bypass));
DECLARE_HOOK(android_vh_update_page_mapcount,
TP_PROTO(struct page *page, bool inc_size, bool compound,
bool *first_mapping, bool *success),
TP_ARGS(page, inc_size, compound, first_mapping, success));
DECLARE_HOOK(android_vh_add_page_to_lrulist,
TP_PROTO(struct page *page, bool compound, enum lru_list lru),
TP_ARGS(page, compound, lru));
DECLARE_HOOK(android_vh_del_page_from_lrulist,
TP_PROTO(struct page *page, bool compound, enum lru_list lru),
TP_ARGS(page, compound, lru));
DECLARE_HOOK(android_vh_show_mapcount_pages,
TP_PROTO(void *unused),
TP_ARGS(unused));
DECLARE_HOOK(android_vh_do_traversal_lruvec,
TP_PROTO(struct lruvec *lruvec),
TP_ARGS(lruvec));
DECLARE_HOOK(android_vh_page_should_be_protected,
TP_PROTO(struct page *page, bool *should_protect),
TP_ARGS(page, should_protect));
DECLARE_HOOK(android_vh_mark_page_accessed,
TP_PROTO(struct page *page),
TP_ARGS(page));
DECLARE_HOOK(android_vh_cma_drain_all_pages_bypass, DECLARE_HOOK(android_vh_cma_drain_all_pages_bypass,
TP_PROTO(unsigned int migratetype, bool *bypass), TP_PROTO(unsigned int migratetype, bool *bypass),
TP_ARGS(migratetype, bypass)); TP_ARGS(migratetype, bypass));
@@ -215,9 +257,17 @@ DECLARE_HOOK(android_vh_alloc_si,
DECLARE_HOOK(android_vh_free_pages, DECLARE_HOOK(android_vh_free_pages,
TP_PROTO(struct page *page, unsigned int order), TP_PROTO(struct page *page, unsigned int order),
TP_ARGS(page, order)); TP_ARGS(page, order));
DECLARE_HOOK(android_vh_set_shmem_page_flag,
TP_PROTO(struct page *page),
TP_ARGS(page));
DECLARE_HOOK(android_vh_remove_vmalloc_stack,
TP_PROTO(struct vm_struct *vm),
TP_ARGS(vm));
/* macro versions of hooks are no longer required */ /* macro versions of hooks are no longer required */
#endif /* _TRACE_HOOK_MM_H */ #endif /* _TRACE_HOOK_MM_H */
/* This part must be outside protection */ /* This part must be outside protection */
#include <trace/define_trace.h> #include <trace/define_trace.h>
#endif /* PROTECT_TRACE_INCLUDE_PATH */

View File

@@ -10,13 +10,17 @@
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#include <trace/hooks/vendor_hooks.h> #include <trace/hooks/vendor_hooks.h>
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_MMC_SDHCI)
struct sdhci_host; struct sdhci_host;
struct mmc_card;
struct mmc_host;
#else #else
/* struct sdhci_host */ /* struct sdhci_host */
#include <../drivers/mmc/host/sdhci.h> #include <../drivers/mmc/host/sdhci.h>
#endif
#ifdef __GENKSYMS__
struct mmc_card;
struct mmc_host;
#else
/* struct mmc_card */ /* struct mmc_card */
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
/* struct mmc_host */ /* struct mmc_host */

View File

@@ -12,7 +12,7 @@
#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS)
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !defined(CONFIG_PSI)
struct psi_group; struct psi_group;
struct psi_trigger; struct psi_trigger;
#else #else

View File

@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Include this file from a header declaring vendor hooks to preserve and later
* restore TRACE_INCLUDE_PATH value. Typical usage:
*
* #ifdef PROTECT_TRACE_INCLUDE_PATH
* #undef PROTECT_TRACE_INCLUDE_PATH
*
* #include <trace/hooks/save_incpath.h>
* #include <vendor hooks header>
* #include <trace/hooks/restore_incpath.h>
*
* #else
*
* <vendor hook definitions>
*
* #endif
*
* The header that includes vendor hooks header file should define
* PROTECT_TRACE_INCLUDE_PATH before including the vendor hook file like this:
*
* #define PROTECT_TRACE_INCLUDE_PATH
* #include <vendor hooks header>
*/
#ifdef STORED_TRACE_INCLUDE_PATH
# undef TRACE_INCLUDE_PATH
# define TRACE_INCLUDE_PATH STORED_TRACE_INCLUDE_PATH
# undef STORED_TRACE_INCLUDE_PATH
#else
# undef TRACE_INCLUDE_PATH
#endif

View File

@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Include this file from a header declaring vendor hooks to preserve and later
* restore TRACE_INCLUDE_PATH value. Typical usage:
*
* #ifdef PROTECT_TRACE_INCLUDE_PATH
* #undef PROTECT_TRACE_INCLUDE_PATH
*
* #include <trace/hooks/save_incpath.h>
* #include <vendor hooks header>
* #include <trace/hooks/restore_incpath.h>
*
* #else
*
* <vendor hook definitions>
*
* #endif
*
* The header that includes vendor hooks header file should define
* PROTECT_TRACE_INCLUDE_PATH before including the vendor hook file like this:
*
* #define PROTECT_TRACE_INCLUDE_PATH
* #include <vendor hooks header>
*/
#ifdef TRACE_INCLUDE_PATH
#define STORED_TRACE_INCLUDE_PATH TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_PATH
#endif

View File

@@ -391,6 +391,17 @@ DECLARE_HOOK(android_vh_setscheduler_uclamp,
TP_PROTO(struct task_struct *tsk, int clamp_id, unsigned int value), TP_PROTO(struct task_struct *tsk, int clamp_id, unsigned int value),
TP_ARGS(tsk, clamp_id, value)); TP_ARGS(tsk, clamp_id, value));
DECLARE_HOOK(android_vh_pidfd_open,
TP_PROTO(struct pid *p),
TP_ARGS(p));
DECLARE_HOOK(android_vh_mmput,
TP_PROTO(void *unused),
TP_ARGS(unused));
DECLARE_HOOK(android_vh_sched_pelt_multiplier,
TP_PROTO(unsigned int old, unsigned int cur, int *ret),
TP_ARGS(old, cur, ret));
/* macro versions of hooks are no longer required */ /* macro versions of hooks are no longer required */
#endif /* _TRACE_HOOK_SCHED_H */ #endif /* _TRACE_HOOK_SCHED_H */

View File

@@ -6,12 +6,13 @@
#define _TRACE_HOOK_TYPEC_H #define _TRACE_HOOK_TYPEC_H
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#include <linux/usb/pd.h> #include <linux/usb/pd.h>
#include <linux/usb/tcpm.h>
#include <trace/hooks/vendor_hooks.h> #include <trace/hooks/vendor_hooks.h>
/* /*
* Following tracepoints are not exported in tracefs and provide a * Following tracepoints are not exported in tracefs and provide a
* mechanism for vendor modules to hook and extend functionality * mechanism for vendor modules to hook and extend functionality
*/ */
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_TYPEC_TCPCI)
struct tcpci_data; struct tcpci_data;
#else #else
/* struct tcpci_data */ /* struct tcpci_data */

View File

@@ -10,7 +10,7 @@
* Following tracepoints are not exported in tracefs and provide a * Following tracepoints are not exported in tracefs and provide a
* mechanism for vendor modules to hook and extend functionality * mechanism for vendor modules to hook and extend functionality
*/ */
#ifdef __GENKSYMS__ #if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_SCSI_UFSHCD)
struct ufs_hba; struct ufs_hba;
struct ufshcd_lrb; struct ufshcd_lrb;
struct uic_command; struct uic_command;

View File

@@ -28,6 +28,18 @@ DECLARE_RESTRICTED_HOOK(android_rvh_set_balance_anon_file_reclaim,
DECLARE_HOOK(android_vh_page_referenced_check_bypass, DECLARE_HOOK(android_vh_page_referenced_check_bypass,
TP_PROTO(struct page *page, unsigned long nr_to_scan, int lru, bool *bypass), TP_PROTO(struct page *page, unsigned long nr_to_scan, int lru, bool *bypass),
TP_ARGS(page, nr_to_scan, lru, bypass)); TP_ARGS(page, nr_to_scan, lru, bypass));
DECLARE_HOOK(android_vh_page_trylock_get_result,
TP_PROTO(struct page *page, bool *trylock_fail),
TP_ARGS(page, trylock_fail));
DECLARE_HOOK(android_vh_handle_failed_page_trylock,
TP_PROTO(struct list_head *page_list),
TP_ARGS(page_list));
DECLARE_HOOK(android_vh_page_trylock_set,
TP_PROTO(struct page *page),
TP_ARGS(page));
DECLARE_HOOK(android_vh_page_trylock_clear,
TP_PROTO(struct page *page),
TP_ARGS(page));
DECLARE_HOOK(android_vh_shrink_node_memcgs, DECLARE_HOOK(android_vh_shrink_node_memcgs,
TP_PROTO(struct mem_cgroup *memcg, bool *skip), TP_PROTO(struct mem_cgroup *memcg, bool *skip),
TP_ARGS(memcg, skip)); TP_ARGS(memcg, skip));

View File

@@ -319,6 +319,7 @@ enum transaction_flags {
TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */
TF_UPDATE_TXN = 0x40, /* update the outdated pending async txn */
}; };
struct binder_transaction_data { struct binder_transaction_data {

View File

@@ -746,7 +746,8 @@ EXPORT_SYMBOL_GPL(of_css);
* reference-counted, to improve performance when child cgroups * reference-counted, to improve performance when child cgroups
* haven't been created. * haven't been created.
*/ */
struct css_set init_css_set = { struct ext_css_set init_ext_css_set = {
.cset = {
.refcount = REFCOUNT_INIT(1), .refcount = REFCOUNT_INIT(1),
.dom_cset = &init_css_set, .dom_cset = &init_css_set,
.tasks = LIST_HEAD_INIT(init_css_set.tasks), .tasks = LIST_HEAD_INIT(init_css_set.tasks),
@@ -757,7 +758,6 @@ struct css_set init_css_set = {
.cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links), .cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links),
.mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node), .mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node),
.mg_node = LIST_HEAD_INIT(init_css_set.mg_node), .mg_node = LIST_HEAD_INIT(init_css_set.mg_node),
/* /*
* The following field is re-initialized when this cset gets linked * The following field is re-initialized when this cset gets linked
* in cgroup_init(). However, let's initialize the field * in cgroup_init(). However, let's initialize the field
@@ -765,6 +765,9 @@ struct css_set init_css_set = {
* early during boot. * early during boot.
*/ */
.dfl_cgrp = &cgrp_dfl_root.cgrp, .dfl_cgrp = &cgrp_dfl_root.cgrp,
},
.mg_src_preload_node = LIST_HEAD_INIT(init_ext_css_set.mg_src_preload_node),
.mg_dst_preload_node = LIST_HEAD_INIT(init_ext_css_set.mg_dst_preload_node),
}; };
static int css_set_count = 1; /* 1 for init_css_set */ static int css_set_count = 1; /* 1 for init_css_set */
@@ -1191,6 +1194,7 @@ static struct css_set *find_css_set(struct css_set *old_cset,
struct cgroup *cgrp) struct cgroup *cgrp)
{ {
struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT] = { }; struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT] = { };
struct ext_css_set *ext_cset;
struct css_set *cset; struct css_set *cset;
struct list_head tmp_links; struct list_head tmp_links;
struct cgrp_cset_link *link; struct cgrp_cset_link *link;
@@ -1211,9 +1215,10 @@ static struct css_set *find_css_set(struct css_set *old_cset,
if (cset) if (cset)
return cset; return cset;
cset = kzalloc(sizeof(*cset), GFP_KERNEL); ext_cset = kzalloc(sizeof(*ext_cset), GFP_KERNEL);
if (!cset) if (!ext_cset)
return NULL; return NULL;
cset = &ext_cset->cset;
/* Allocate all the cgrp_cset_link objects that we'll need */ /* Allocate all the cgrp_cset_link objects that we'll need */
if (allocate_cgrp_cset_links(cgroup_root_count, &tmp_links) < 0) { if (allocate_cgrp_cset_links(cgroup_root_count, &tmp_links) < 0) {
@@ -1231,6 +1236,8 @@ static struct css_set *find_css_set(struct css_set *old_cset,
INIT_HLIST_NODE(&cset->hlist); INIT_HLIST_NODE(&cset->hlist);
INIT_LIST_HEAD(&cset->cgrp_links); INIT_LIST_HEAD(&cset->cgrp_links);
INIT_LIST_HEAD(&cset->mg_preload_node); INIT_LIST_HEAD(&cset->mg_preload_node);
INIT_LIST_HEAD(&ext_cset->mg_src_preload_node);
INIT_LIST_HEAD(&ext_cset->mg_dst_preload_node);
INIT_LIST_HEAD(&cset->mg_node); INIT_LIST_HEAD(&cset->mg_node);
/* Copy the set of subsystem state objects generated in /* Copy the set of subsystem state objects generated in
@@ -2578,22 +2585,28 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
*/ */
void cgroup_migrate_finish(struct cgroup_mgctx *mgctx) void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
{ {
LIST_HEAD(preloaded); struct ext_css_set *cset, *tmp_cset;
struct css_set *cset, *tmp_cset;
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
spin_lock_irq(&css_set_lock); spin_lock_irq(&css_set_lock);
list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded); list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded); mg_src_preload_node) {
cset->cset.mg_src_cgrp = NULL;
cset->cset.mg_dst_cgrp = NULL;
cset->cset.mg_dst_cset = NULL;
list_del_init(&cset->mg_src_preload_node);
put_css_set_locked(&cset->cset);
}
list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) { list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
cset->mg_src_cgrp = NULL; mg_dst_preload_node) {
cset->mg_dst_cgrp = NULL; cset->cset.mg_src_cgrp = NULL;
cset->mg_dst_cset = NULL; cset->cset.mg_dst_cgrp = NULL;
list_del_init(&cset->mg_preload_node); cset->cset.mg_dst_cset = NULL;
put_css_set_locked(cset); list_del_init(&cset->mg_dst_preload_node);
put_css_set_locked(&cset->cset);
} }
spin_unlock_irq(&css_set_lock); spin_unlock_irq(&css_set_lock);
@@ -2620,6 +2633,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
struct cgroup_mgctx *mgctx) struct cgroup_mgctx *mgctx)
{ {
struct cgroup *src_cgrp; struct cgroup *src_cgrp;
struct ext_css_set *ext_src_cset;
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
lockdep_assert_held(&css_set_lock); lockdep_assert_held(&css_set_lock);
@@ -2633,8 +2647,9 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
return; return;
src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root); src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
ext_src_cset = container_of(src_cset, struct ext_css_set, cset);
if (!list_empty(&src_cset->mg_preload_node)) if (!list_empty(&ext_src_cset->mg_src_preload_node))
return; return;
WARN_ON(src_cset->mg_src_cgrp); WARN_ON(src_cset->mg_src_cgrp);
@@ -2645,7 +2660,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
src_cset->mg_src_cgrp = src_cgrp; src_cset->mg_src_cgrp = src_cgrp;
src_cset->mg_dst_cgrp = dst_cgrp; src_cset->mg_dst_cgrp = dst_cgrp;
get_css_set(src_cset); get_css_set(src_cset);
list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets); list_add_tail(&ext_src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets);
} }
/** /**
@@ -2664,20 +2679,23 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
*/ */
int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
{ {
struct css_set *src_cset, *tmp_cset; struct ext_css_set *ext_src_set, *tmp_cset;
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
/* look up the dst cset for each src cset and link it to src */ /* look up the dst cset for each src cset and link it to src */
list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets, list_for_each_entry_safe(ext_src_set, tmp_cset, &mgctx->preloaded_src_csets,
mg_preload_node) { mg_src_preload_node) {
struct css_set *src_cset = &ext_src_set->cset;
struct css_set *dst_cset; struct css_set *dst_cset;
struct ext_css_set *ext_dst_cset;
struct cgroup_subsys *ss; struct cgroup_subsys *ss;
int ssid; int ssid;
dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp); dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp);
if (!dst_cset) if (!dst_cset)
return -ENOMEM; return -ENOMEM;
ext_dst_cset = container_of(dst_cset, struct ext_css_set, cset);
WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset); WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset);
@@ -2689,7 +2707,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
if (src_cset == dst_cset) { if (src_cset == dst_cset) {
src_cset->mg_src_cgrp = NULL; src_cset->mg_src_cgrp = NULL;
src_cset->mg_dst_cgrp = NULL; src_cset->mg_dst_cgrp = NULL;
list_del_init(&src_cset->mg_preload_node); list_del_init(&ext_src_set->mg_src_preload_node);
put_css_set(src_cset); put_css_set(src_cset);
put_css_set(dst_cset); put_css_set(dst_cset);
continue; continue;
@@ -2697,8 +2715,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
src_cset->mg_dst_cset = dst_cset; src_cset->mg_dst_cset = dst_cset;
if (list_empty(&dst_cset->mg_preload_node)) if (list_empty(&ext_dst_cset->mg_dst_preload_node))
list_add_tail(&dst_cset->mg_preload_node, list_add_tail(&ext_dst_cset->mg_dst_preload_node,
&mgctx->preloaded_dst_csets); &mgctx->preloaded_dst_csets);
else else
put_css_set(dst_cset); put_css_set(dst_cset);
@@ -2926,7 +2944,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
DEFINE_CGROUP_MGCTX(mgctx); DEFINE_CGROUP_MGCTX(mgctx);
struct cgroup_subsys_state *d_css; struct cgroup_subsys_state *d_css;
struct cgroup *dsct; struct cgroup *dsct;
struct css_set *src_cset; struct ext_css_set *ext_src_set;
int ret; int ret;
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
@@ -2949,11 +2967,12 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
goto out_finish; goto out_finish;
spin_lock_irq(&css_set_lock); spin_lock_irq(&css_set_lock);
list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) { list_for_each_entry(ext_src_set, &mgctx.preloaded_src_csets,
mg_src_preload_node) {
struct task_struct *task, *ntask; struct task_struct *task, *ntask;
/* all tasks in src_csets need to be migrated */ /* all tasks in src_csets need to be migrated */
list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list) list_for_each_entry_safe(task, ntask, &ext_src_set->cset.tasks, cg_list)
cgroup_migrate_add_task(task, &mgctx); cgroup_migrate_add_task(task, &mgctx);
} }
spin_unlock_irq(&css_set_lock); spin_unlock_irq(&css_set_lock);

View File

@@ -1150,9 +1150,11 @@ void mmput(struct mm_struct *mm)
{ {
might_sleep(); might_sleep();
if (atomic_dec_and_test(&mm->mm_users)) if (atomic_dec_and_test(&mm->mm_users)) {
trace_android_vh_mmput(NULL);
__mmput(mm); __mmput(mm);
} }
}
EXPORT_SYMBOL_GPL(mmput); EXPORT_SYMBOL_GPL(mmput);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU

View File

@@ -45,6 +45,9 @@
#include <net/sock.h> #include <net/sock.h>
#include <uapi/linux/pidfd.h> #include <uapi/linux/pidfd.h>
#undef CREATE_TRACE_POINTS
#include <trace/hooks/sched.h>
struct pid init_struct_pid = { struct pid init_struct_pid = {
.count = REFCOUNT_INIT(1), .count = REFCOUNT_INIT(1),
.tasks = { .tasks = {
@@ -602,6 +605,7 @@ SYSCALL_DEFINE2(pidfd_open, pid_t, pid, unsigned int, flags)
else else
fd = -EINVAL; fd = -EINVAL;
trace_android_vh_pidfd_open(p);
put_pid(p); put_pid(p);
return fd; return fd;
} }

View File

@@ -4788,7 +4788,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
cfs_rq->throttle_count--; cfs_rq->throttle_count--;
if (!cfs_rq->throttle_count) { if (!cfs_rq->throttle_count) {
cfs_rq->throttled_clock_pelt_time += rq_clock_pelt(rq) - cfs_rq->throttled_clock_pelt_time += rq_clock_task_mult(rq) -
cfs_rq->throttled_clock_pelt; cfs_rq->throttled_clock_pelt;
/* Add cfs_rq with already running entity in the list */ /* Add cfs_rq with already running entity in the list */
@@ -4806,7 +4806,7 @@ static int tg_throttle_down(struct task_group *tg, void *data)
/* group is entering throttled state, stop time */ /* group is entering throttled state, stop time */
if (!cfs_rq->throttle_count) { if (!cfs_rq->throttle_count) {
cfs_rq->throttled_clock_pelt = rq_clock_pelt(rq); cfs_rq->throttled_clock_pelt = rq_clock_task_mult(rq);
list_del_leaf_cfs_rq(cfs_rq); list_del_leaf_cfs_rq(cfs_rq);
} }
cfs_rq->throttle_count++; cfs_rq->throttle_count++;
@@ -5224,7 +5224,7 @@ static void sync_throttle(struct task_group *tg, int cpu)
pcfs_rq = tg->parent->cfs_rq[cpu]; pcfs_rq = tg->parent->cfs_rq[cpu];
cfs_rq->throttle_count = pcfs_rq->throttle_count; cfs_rq->throttle_count = pcfs_rq->throttle_count;
cfs_rq->throttled_clock_pelt = rq_clock_pelt(cpu_rq(cpu)); cfs_rq->throttled_clock_pelt = rq_clock_task_mult(cpu_rq(cpu));
} }
/* conditionally throttle active cfs_rq's from put_prev_entity() */ /* conditionally throttle active cfs_rq's from put_prev_entity() */

View File

@@ -531,3 +531,50 @@ int update_irq_load_avg(struct rq *rq, u64 running)
return ret; return ret;
} }
#endif #endif
#include <trace/hooks/sched.h>
DEFINE_PER_CPU(u64, clock_task_mult);
unsigned int sysctl_sched_pelt_multiplier = 1;
__read_mostly unsigned int sched_pelt_lshift;
int sched_pelt_multiplier(struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos)
{
static DEFINE_MUTEX(mutex);
unsigned int old;
int ret;
mutex_lock(&mutex);
old = sysctl_sched_pelt_multiplier;
ret = proc_dointvec(table, write, buffer, lenp, ppos);
if (ret)
goto undo;
if (!write)
goto done;
trace_android_vh_sched_pelt_multiplier(old, sysctl_sched_pelt_multiplier, &ret);
if (ret)
goto undo;
switch (sysctl_sched_pelt_multiplier) {
case 1:
fallthrough;
case 2:
fallthrough;
case 4:
WRITE_ONCE(sched_pelt_lshift,
sysctl_sched_pelt_multiplier >> 1);
goto done;
default:
ret = -EINVAL;
}
undo:
sysctl_sched_pelt_multiplier = old;
done:
mutex_unlock(&mutex);
return ret;
}

View File

@@ -61,6 +61,8 @@ static inline void cfs_se_util_change(struct sched_avg *avg)
WRITE_ONCE(avg->util_est.enqueued, enqueued); WRITE_ONCE(avg->util_est.enqueued, enqueued);
} }
extern unsigned int sched_pelt_lshift;
/* /*
* The clock_pelt scales the time to reflect the effective amount of * The clock_pelt scales the time to reflect the effective amount of
* computation done during the running delta time but then sync back to * computation done during the running delta time but then sync back to
@@ -75,9 +77,13 @@ static inline void cfs_se_util_change(struct sched_avg *avg)
*/ */
static inline void update_rq_clock_pelt(struct rq *rq, s64 delta) static inline void update_rq_clock_pelt(struct rq *rq, s64 delta)
{ {
delta <<= READ_ONCE(sched_pelt_lshift);
per_cpu(clock_task_mult, rq->cpu) += delta;
if (unlikely(is_idle_task(rq->curr))) { if (unlikely(is_idle_task(rq->curr))) {
/* The rq is idle, we can sync to clock_task */ /* The rq is idle, we can sync to clock_task */
rq->clock_pelt = rq_clock_task(rq); rq->clock_pelt = rq_clock_task_mult(rq);
return; return;
} }
@@ -129,7 +135,8 @@ static inline void update_idle_rq_clock_pelt(struct rq *rq)
* rq's clock_task. * rq's clock_task.
*/ */
if (util_sum >= divider) if (util_sum >= divider)
rq->lost_idle_time += rq_clock_task(rq) - rq->clock_pelt; rq->lost_idle_time += rq_clock_task_mult(rq) -
rq->clock_pelt;
} }
static inline u64 rq_clock_pelt(struct rq *rq) static inline u64 rq_clock_pelt(struct rq *rq)

View File

@@ -1193,6 +1193,16 @@ static inline u64 rq_clock_task(struct rq *rq)
return rq->clock_task; return rq->clock_task;
} }
DECLARE_PER_CPU(u64, clock_task_mult);
static inline u64 rq_clock_task_mult(struct rq *rq)
{
lockdep_assert_held(&rq->lock);
assert_clock_updated(rq);
return per_cpu(clock_task_mult, cpu_of(rq));
}
/** /**
* By default the decay is the default pelt decay period. * By default the decay is the default pelt decay period.
* The decay shift can change the decay period in * The decay shift can change the decay period in

View File

@@ -1832,6 +1832,15 @@ static struct ctl_table kern_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = sched_rr_handler, .proc_handler = sched_rr_handler,
}, },
#ifdef CONFIG_SMP
{
.procname = "sched_pelt_multiplier",
.data = &sysctl_sched_pelt_multiplier,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = sched_pelt_multiplier,
},
#endif
#ifdef CONFIG_UCLAMP_TASK #ifdef CONFIG_UCLAMP_TASK
{ {
.procname = "sched_util_clamp_min", .procname = "sched_util_clamp_min",

View File

@@ -33,7 +33,7 @@
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/numa.h> #include <linux/numa.h>
#include <linux/page_owner.h> #include <linux/page_owner.h>
#include <trace/hooks/mm.h>
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include "internal.h" #include "internal.h"
@@ -2033,6 +2033,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
bool young, write, soft_dirty, pmd_migration = false, uffd_wp = false; bool young, write, soft_dirty, pmd_migration = false, uffd_wp = false;
unsigned long addr; unsigned long addr;
int i; int i;
bool success = false;
VM_BUG_ON(haddr & ~HPAGE_PMD_MASK); VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
VM_BUG_ON_VMA(vma->vm_start > haddr, vma); VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
@@ -2164,8 +2165,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
pte = pte_offset_map(&_pmd, addr); pte = pte_offset_map(&_pmd, addr);
BUG_ON(!pte_none(*pte)); BUG_ON(!pte_none(*pte));
set_pte_at(mm, addr, pte, entry); set_pte_at(mm, addr, pte, entry);
if (!pmd_migration) if (!pmd_migration) {
trace_android_vh_update_page_mapcount(&page[i], true,
false, NULL, &success);
if (!success)
atomic_inc(&page[i]._mapcount); atomic_inc(&page[i]._mapcount);
}
pte_unmap(pte); pte_unmap(pte);
} }
@@ -2176,9 +2181,13 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
*/ */
if (compound_mapcount(page) > 1 && if (compound_mapcount(page) > 1 &&
!TestSetPageDoubleMap(page)) { !TestSetPageDoubleMap(page)) {
for (i = 0; i < HPAGE_PMD_NR; i++) for (i = 0; i < HPAGE_PMD_NR; i++) {
trace_android_vh_update_page_mapcount(&page[i], true,
false, NULL, &success);
if (!success)
atomic_inc(&page[i]._mapcount); atomic_inc(&page[i]._mapcount);
} }
}
lock_page_memcg(page); lock_page_memcg(page);
if (atomic_add_negative(-1, compound_mapcount_ptr(page))) { if (atomic_add_negative(-1, compound_mapcount_ptr(page))) {
@@ -2186,10 +2195,14 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
__dec_lruvec_page_state(page, NR_ANON_THPS); __dec_lruvec_page_state(page, NR_ANON_THPS);
if (TestClearPageDoubleMap(page)) { if (TestClearPageDoubleMap(page)) {
/* No need in mapcount reference anymore */ /* No need in mapcount reference anymore */
for (i = 0; i < HPAGE_PMD_NR; i++) for (i = 0; i < HPAGE_PMD_NR; i++) {
trace_android_vh_update_page_mapcount(&page[i],
false, false, NULL, &success);
if (!success)
atomic_dec(&page[i]._mapcount); atomic_dec(&page[i]._mapcount);
} }
} }
}
unlock_page_memcg(page); unlock_page_memcg(page);
} }

View File

@@ -1372,6 +1372,38 @@ out:
return lruvec; return lruvec;
} }
struct lruvec *page_to_lruvec(struct page *page, pg_data_t *pgdat)
{
struct lruvec *lruvec;
lruvec = mem_cgroup_page_lruvec(page, pgdat);
return lruvec;
}
EXPORT_SYMBOL_GPL(page_to_lruvec);
void do_traversal_all_lruvec(void)
{
pg_data_t *pgdat;
for_each_online_pgdat(pgdat) {
struct mem_cgroup *memcg = NULL;
spin_lock_irq(&pgdat->lru_lock);
memcg = mem_cgroup_iter(NULL, NULL, NULL);
do {
struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat);
trace_android_vh_do_traversal_lruvec(lruvec);
memcg = mem_cgroup_iter(NULL, memcg, NULL);
} while (memcg);
spin_unlock_irq(&pgdat->lru_lock);
}
}
EXPORT_SYMBOL_GPL(do_traversal_all_lruvec);
/** /**
* mem_cgroup_update_lru_size - account for adding or removing an lru page * mem_cgroup_update_lru_size - account for adding or removing an lru page
* @lruvec: mem_cgroup per zone lru vector * @lruvec: mem_cgroup per zone lru vector

View File

@@ -4794,7 +4794,9 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
int no_progress_loops; int no_progress_loops;
unsigned int cpuset_mems_cookie; unsigned int cpuset_mems_cookie;
int reserve_flags; int reserve_flags;
unsigned long vh_record;
trace_android_vh_alloc_pages_slowpath_begin(gfp_mask, order, &vh_record);
/* /*
* We also sanity check to catch abuse of atomic reserves being used by * We also sanity check to catch abuse of atomic reserves being used by
* callers that are not in atomic context. * callers that are not in atomic context.
@@ -5036,6 +5038,7 @@ fail:
warn_alloc(gfp_mask, ac->nodemask, warn_alloc(gfp_mask, ac->nodemask,
"page allocation failure: order:%u", order); "page allocation failure: order:%u", order);
got_pg: got_pg:
trace_android_vh_alloc_pages_slowpath_end(gfp_mask, order, vh_record);
return page; return page;
} }
@@ -5647,6 +5650,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
free_pcp, free_pcp,
global_zone_page_state(NR_FREE_CMA_PAGES)); global_zone_page_state(NR_FREE_CMA_PAGES));
trace_android_vh_show_mapcount_pages(NULL);
for_each_online_pgdat(pgdat) { for_each_online_pgdat(pgdat) {
if (show_mem_node_skip(filter, pgdat->node_id, nodemask)) if (show_mem_node_skip(filter, pgdat->node_id, nodemask))
continue; continue;

View File

@@ -525,6 +525,7 @@ struct anon_vma *page_lock_anon_vma_read(struct page *page)
struct anon_vma *anon_vma = NULL; struct anon_vma *anon_vma = NULL;
struct anon_vma *root_anon_vma; struct anon_vma *root_anon_vma;
unsigned long anon_mapping; unsigned long anon_mapping;
bool success = false;
rcu_read_lock(); rcu_read_lock();
anon_mapping = (unsigned long)READ_ONCE(page->mapping); anon_mapping = (unsigned long)READ_ONCE(page->mapping);
@@ -547,7 +548,11 @@ struct anon_vma *page_lock_anon_vma_read(struct page *page)
} }
goto out; goto out;
} }
trace_android_vh_do_page_trylock(page, NULL, NULL, &success);
if (success) {
anon_vma = NULL;
goto out;
}
/* trylock failed, we got to sleep */ /* trylock failed, we got to sleep */
if (!atomic_inc_not_zero(&anon_vma->refcount)) { if (!atomic_inc_not_zero(&anon_vma->refcount)) {
anon_vma = NULL; anon_vma = NULL;
@@ -1113,6 +1118,7 @@ void do_page_add_anon_rmap(struct page *page,
{ {
bool compound = flags & RMAP_COMPOUND; bool compound = flags & RMAP_COMPOUND;
bool first; bool first;
bool success = false;
if (unlikely(PageKsm(page))) if (unlikely(PageKsm(page)))
lock_page_memcg(page); lock_page_memcg(page);
@@ -1126,6 +1132,9 @@ void do_page_add_anon_rmap(struct page *page,
mapcount = compound_mapcount_ptr(page); mapcount = compound_mapcount_ptr(page);
first = atomic_inc_and_test(mapcount); first = atomic_inc_and_test(mapcount);
} else { } else {
trace_android_vh_update_page_mapcount(page, true, compound,
&first, &success);
if (!success)
first = atomic_inc_and_test(&page->_mapcount); first = atomic_inc_and_test(&page->_mapcount);
} }
@@ -1200,14 +1209,23 @@ void __page_add_new_anon_rmap(struct page *page,
void page_add_file_rmap(struct page *page, bool compound) void page_add_file_rmap(struct page *page, bool compound)
{ {
int i, nr = 1; int i, nr = 1;
bool first_mapping;
bool success = false;
VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page); VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page);
lock_page_memcg(page); lock_page_memcg(page);
if (compound && PageTransHuge(page)) { if (compound && PageTransHuge(page)) {
for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
trace_android_vh_update_page_mapcount(&page[i], true,
compound, &first_mapping, &success);
if ((success)) {
if (first_mapping)
nr++;
} else {
if (atomic_inc_and_test(&page[i]._mapcount)) if (atomic_inc_and_test(&page[i]._mapcount))
nr++; nr++;
} }
}
if (!atomic_inc_and_test(compound_mapcount_ptr(page))) if (!atomic_inc_and_test(compound_mapcount_ptr(page)))
goto out; goto out;
if (PageSwapBacked(page)) if (PageSwapBacked(page))
@@ -1222,9 +1240,16 @@ void page_add_file_rmap(struct page *page, bool compound)
if (PageMlocked(page)) if (PageMlocked(page))
clear_page_mlock(compound_head(page)); clear_page_mlock(compound_head(page));
} }
trace_android_vh_update_page_mapcount(page, true,
compound, &first_mapping, &success);
if (success) {
if (!first_mapping)
goto out;
} else {
if (!atomic_inc_and_test(&page->_mapcount)) if (!atomic_inc_and_test(&page->_mapcount))
goto out; goto out;
} }
}
__mod_lruvec_page_state(page, NR_FILE_MAPPED, nr); __mod_lruvec_page_state(page, NR_FILE_MAPPED, nr);
out: out:
unlock_page_memcg(page); unlock_page_memcg(page);
@@ -1233,6 +1258,8 @@ out:
static void page_remove_file_rmap(struct page *page, bool compound) static void page_remove_file_rmap(struct page *page, bool compound)
{ {
int i, nr = 1; int i, nr = 1;
bool first_mapping;
bool success = false;
VM_BUG_ON_PAGE(compound && !PageHead(page), page); VM_BUG_ON_PAGE(compound && !PageHead(page), page);
@@ -1246,19 +1273,33 @@ static void page_remove_file_rmap(struct page *page, bool compound)
/* page still mapped by someone else? */ /* page still mapped by someone else? */
if (compound && PageTransHuge(page)) { if (compound && PageTransHuge(page)) {
for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
trace_android_vh_update_page_mapcount(&page[i], false,
compound, &first_mapping, &success);
if (success) {
if (first_mapping)
nr++;
} else {
if (atomic_add_negative(-1, &page[i]._mapcount)) if (atomic_add_negative(-1, &page[i]._mapcount))
nr++; nr++;
} }
}
if (!atomic_add_negative(-1, compound_mapcount_ptr(page))) if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
return; return;
if (PageSwapBacked(page)) if (PageSwapBacked(page))
__dec_node_page_state(page, NR_SHMEM_PMDMAPPED); __dec_node_page_state(page, NR_SHMEM_PMDMAPPED);
else else
__dec_node_page_state(page, NR_FILE_PMDMAPPED); __dec_node_page_state(page, NR_FILE_PMDMAPPED);
} else {
trace_android_vh_update_page_mapcount(page, false,
compound, &first_mapping, &success);
if (success) {
if (!first_mapping)
return;
} else { } else {
if (!atomic_add_negative(-1, &page->_mapcount)) if (!atomic_add_negative(-1, &page->_mapcount))
return; return;
} }
}
/* /*
* We use the irq-unsafe __{inc|mod}_lruvec_page_state because * We use the irq-unsafe __{inc|mod}_lruvec_page_state because
@@ -1274,6 +1315,8 @@ static void page_remove_file_rmap(struct page *page, bool compound)
static void page_remove_anon_compound_rmap(struct page *page) static void page_remove_anon_compound_rmap(struct page *page)
{ {
int i, nr; int i, nr;
bool first_mapping;
bool success = false;
if (!atomic_add_negative(-1, compound_mapcount_ptr(page))) if (!atomic_add_negative(-1, compound_mapcount_ptr(page)))
return; return;
@@ -1293,9 +1336,16 @@ static void page_remove_anon_compound_rmap(struct page *page)
* them are still mapped. * them are still mapped.
*/ */
for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) {
trace_android_vh_update_page_mapcount(&page[i], false,
false, &first_mapping, &success);
if (success) {
if (first_mapping)
nr++;
} else {
if (atomic_add_negative(-1, &page[i]._mapcount)) if (atomic_add_negative(-1, &page[i]._mapcount))
nr++; nr++;
} }
}
/* /*
* Queue the page for deferred split if at least one small * Queue the page for deferred split if at least one small
@@ -1324,6 +1374,8 @@ static void page_remove_anon_compound_rmap(struct page *page)
*/ */
void page_remove_rmap(struct page *page, bool compound) void page_remove_rmap(struct page *page, bool compound)
{ {
bool first_mapping;
bool success = false;
lock_page_memcg(page); lock_page_memcg(page);
if (!PageAnon(page)) { if (!PageAnon(page)) {
@@ -1336,10 +1388,16 @@ void page_remove_rmap(struct page *page, bool compound)
goto out; goto out;
} }
trace_android_vh_update_page_mapcount(page, false,
compound, &first_mapping, &success);
if (success) {
if (!first_mapping)
goto out;
} else {
/* page still mapped by someone else? */ /* page still mapped by someone else? */
if (!atomic_add_negative(-1, &page->_mapcount)) if (!atomic_add_negative(-1, &page->_mapcount))
goto out; goto out;
}
/* /*
* We use the irq-unsafe __{inc|mod}_zone_page_stat because * We use the irq-unsafe __{inc|mod}_zone_page_stat because
* these counters are not modified in interrupt context, and * these counters are not modified in interrupt context, and
@@ -1928,6 +1986,7 @@ static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
struct address_space *mapping = page_mapping(page); struct address_space *mapping = page_mapping(page);
pgoff_t pgoff_start, pgoff_end; pgoff_t pgoff_start, pgoff_end;
struct vm_area_struct *vma; struct vm_area_struct *vma;
bool got_lock = false, success = false;
/* /*
* The page lock not only makes sure that page->mapping cannot * The page lock not only makes sure that page->mapping cannot
@@ -1942,8 +2001,16 @@ static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
pgoff_start = page_to_pgoff(page); pgoff_start = page_to_pgoff(page);
pgoff_end = pgoff_start + thp_nr_pages(page) - 1; pgoff_end = pgoff_start + thp_nr_pages(page) - 1;
if (!locked) if (!locked) {
trace_android_vh_do_page_trylock(page,
&mapping->i_mmap_rwsem, &got_lock, &success);
if (success) {
if (!got_lock)
return;
} else {
i_mmap_lock_read(mapping); i_mmap_lock_read(mapping);
}
}
vma_interval_tree_foreach(vma, &mapping->i_mmap, vma_interval_tree_foreach(vma, &mapping->i_mmap,
pgoff_start, pgoff_end) { pgoff_start, pgoff_end) {
unsigned long address = vma_address(page, vma); unsigned long address = vma_address(page, vma);

View File

@@ -46,6 +46,7 @@
#undef CREATE_TRACE_POINTS #undef CREATE_TRACE_POINTS
#include <trace/hooks/shmem_fs.h> #include <trace/hooks/shmem_fs.h>
#include <trace/hooks/mm.h>
static struct vfsmount *shm_mnt; static struct vfsmount *shm_mnt;
@@ -1430,6 +1431,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
SetPageUptodate(page); SetPageUptodate(page);
} }
trace_android_vh_set_shmem_page_flag(page);
swap = get_swap_page(page); swap = get_swap_page(page);
if (!swap.val) if (!swap.val)
goto redirty; goto redirty;
@@ -4311,7 +4313,6 @@ int reclaim_shmem_address_space(struct address_space *mapping)
pgoff_t start = 0; pgoff_t start = 0;
struct page *page; struct page *page;
LIST_HEAD(page_list); LIST_HEAD(page_list);
int reclaimed;
XA_STATE(xas, &mapping->i_pages, start); XA_STATE(xas, &mapping->i_pages, start);
if (!shmem_mapping(mapping)) if (!shmem_mapping(mapping))
@@ -4329,8 +4330,6 @@ int reclaim_shmem_address_space(struct address_space *mapping)
continue; continue;
list_add(&page->lru, &page_list); list_add(&page->lru, &page_list);
inc_node_page_state(page, NR_ISOLATED_ANON +
page_is_file_lru(page));
if (need_resched()) { if (need_resched()) {
xas_pause(&xas); xas_pause(&xas);
@@ -4338,9 +4337,8 @@ int reclaim_shmem_address_space(struct address_space *mapping)
} }
} }
rcu_read_unlock(); rcu_read_unlock();
reclaimed = reclaim_pages_from_list(&page_list);
return reclaimed; return reclaim_pages(&page_list);
#else #else
return 0; return 0;
#endif #endif

View File

@@ -437,6 +437,7 @@ void mark_page_accessed(struct page *page)
{ {
page = compound_head(page); page = compound_head(page);
trace_android_vh_mark_page_accessed(page);
if (!PageReferenced(page)) { if (!PageReferenced(page)) {
SetPageReferenced(page); SetPageReferenced(page);
} else if (PageUnevictable(page)) { } else if (PageUnevictable(page)) {

View File

@@ -2170,6 +2170,7 @@ struct vm_struct *remove_vm_area(const void *addr)
if (va && va->vm) { if (va && va->vm) {
struct vm_struct *vm = va->vm; struct vm_struct *vm = va->vm;
trace_android_vh_remove_vmalloc_stack(vm);
va->vm = NULL; va->vm = NULL;
spin_unlock(&vmap_area_lock); spin_unlock(&vmap_area_lock);

View File

@@ -1020,11 +1020,20 @@ static enum page_references page_check_references(struct page *page,
{ {
int referenced_ptes, referenced_page; int referenced_ptes, referenced_page;
unsigned long vm_flags; unsigned long vm_flags;
bool should_protect = false;
bool trylock_fail = false;
trace_android_vh_page_should_be_protected(page, &should_protect);
if (unlikely(should_protect))
return PAGEREF_ACTIVATE;
trace_android_vh_page_trylock_set(page);
referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup, referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup,
&vm_flags); &vm_flags);
referenced_page = TestClearPageReferenced(page); referenced_page = TestClearPageReferenced(page);
trace_android_vh_page_trylock_get_result(page, &trylock_fail);
if (trylock_fail)
return PAGEREF_KEEP;
/* /*
* Mlock lost the isolation race with us. Let try_to_unmap() * Mlock lost the isolation race with us. Let try_to_unmap()
* move the page to the unevictable list. * move the page to the unevictable list.
@@ -1336,6 +1345,7 @@ static unsigned int shrink_page_list(struct list_head *page_list,
if (unlikely(PageTransHuge(page))) if (unlikely(PageTransHuge(page)))
flags |= TTU_SPLIT_HUGE_PMD; flags |= TTU_SPLIT_HUGE_PMD;
trace_android_vh_page_trylock_set(page);
if (!try_to_unmap(page, flags)) { if (!try_to_unmap(page, flags)) {
stat->nr_unmap_fail += nr_pages; stat->nr_unmap_fail += nr_pages;
if (!was_swapbacked && PageSwapBacked(page)) if (!was_swapbacked && PageSwapBacked(page))
@@ -1446,6 +1456,7 @@ static unsigned int shrink_page_list(struct list_head *page_list,
* increment nr_reclaimed here (and * increment nr_reclaimed here (and
* leave it off the LRU). * leave it off the LRU).
*/ */
trace_android_vh_page_trylock_clear(page);
nr_reclaimed++; nr_reclaimed++;
continue; continue;
} }
@@ -1481,8 +1492,10 @@ free_it:
*/ */
if (unlikely(PageTransHuge(page))) if (unlikely(PageTransHuge(page)))
destroy_compound_page(page); destroy_compound_page(page);
else else {
trace_android_vh_page_trylock_clear(page);
list_add(&page->lru, &free_pages); list_add(&page->lru, &free_pages);
}
continue; continue;
activate_locked_split: activate_locked_split:
@@ -1564,36 +1577,6 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,
return nr_reclaimed; return nr_reclaimed;
} }
int reclaim_pages_from_list(struct list_head *page_list)
{
struct scan_control sc = {
.gfp_mask = GFP_KERNEL,
.priority = DEF_PRIORITY,
.may_writepage = 1,
.may_unmap = 1,
.may_swap = 1,
};
unsigned long nr_reclaimed;
struct reclaim_stat dummy_stat;
struct page *page;
list_for_each_entry(page, page_list, lru)
ClearPageActive(page);
nr_reclaimed = shrink_page_list(page_list, NULL, &sc,
&dummy_stat, false);
while (!list_empty(page_list)) {
page = lru_to_page(page_list);
list_del(&page->lru);
dec_node_page_state(page, NR_ISOLATED_ANON +
page_is_file_lru(page));
putback_lru_page(page);
}
return nr_reclaimed;
}
/* /*
* Attempt to remove the specified page from its LRU. Only take this page * Attempt to remove the specified page from its LRU. Only take this page
* if it is of the appropriate PageActive status. Pages which are being * if it is of the appropriate PageActive status. Pages which are being
@@ -1757,6 +1740,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
case 0: case 0:
nr_taken += nr_pages; nr_taken += nr_pages;
nr_zone_taken[page_zonenum(page)] += nr_pages; nr_zone_taken[page_zonenum(page)] += nr_pages;
trace_android_vh_del_page_from_lrulist(page, false, lru);
list_move(&page->lru, dst); list_move(&page->lru, dst);
break; break;
@@ -1931,6 +1915,7 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec,
nr_pages = thp_nr_pages(page); nr_pages = thp_nr_pages(page);
update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); update_lru_size(lruvec, lru, page_zonenum(page), nr_pages);
list_move(&page->lru, &lruvec->lists[lru]); list_move(&page->lru, &lruvec->lists[lru]);
trace_android_vh_add_page_to_lrulist(page, false, lru);
if (put_page_testzero(page)) { if (put_page_testzero(page)) {
__ClearPageLRU(page); __ClearPageLRU(page);
@@ -2022,6 +2007,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
return 0; return 0;
nr_reclaimed = shrink_page_list(&page_list, pgdat, sc, &stat, false); nr_reclaimed = shrink_page_list(&page_list, pgdat, sc, &stat, false);
trace_android_vh_handle_failed_page_trylock(&page_list);
spin_lock_irq(&pgdat->lru_lock); spin_lock_irq(&pgdat->lru_lock);
@@ -2034,7 +2020,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
__count_vm_events(item, nr_reclaimed); __count_vm_events(item, nr_reclaimed);
__count_memcg_events(lruvec_memcg(lruvec), item, nr_reclaimed); __count_memcg_events(lruvec_memcg(lruvec), item, nr_reclaimed);
__count_vm_events(PGSTEAL_ANON + file, nr_reclaimed); __count_vm_events(PGSTEAL_ANON + file, nr_reclaimed);
spin_unlock_irq(&pgdat->lru_lock); spin_unlock_irq(&pgdat->lru_lock);
mem_cgroup_uncharge_list(&page_list); mem_cgroup_uncharge_list(&page_list);
@@ -2085,6 +2070,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
int file = is_file_lru(lru); int file = is_file_lru(lru);
struct pglist_data *pgdat = lruvec_pgdat(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec);
bool bypass = false; bool bypass = false;
bool should_protect = false;
lru_add_drain(); lru_add_drain();
@@ -2119,10 +2105,17 @@ static void shrink_active_list(unsigned long nr_to_scan,
} }
} }
trace_android_vh_page_should_be_protected(page, &should_protect);
if (unlikely(should_protect)) {
nr_rotated += thp_nr_pages(page);
list_add(&page->lru, &l_active);
continue;
}
trace_android_vh_page_referenced_check_bypass(page, nr_to_scan, lru, &bypass); trace_android_vh_page_referenced_check_bypass(page, nr_to_scan, lru, &bypass);
if (bypass) if (bypass)
goto skip_page_referenced; goto skip_page_referenced;
trace_android_vh_page_trylock_set(page);
if (page_referenced(page, 0, sc->target_mem_cgroup, if (page_referenced(page, 0, sc->target_mem_cgroup,
&vm_flags)) { &vm_flags)) {
/* /*
@@ -2135,11 +2128,13 @@ static void shrink_active_list(unsigned long nr_to_scan,
* so we ignore them here. * so we ignore them here.
*/ */
if ((vm_flags & VM_EXEC) && page_is_file_lru(page)) { if ((vm_flags & VM_EXEC) && page_is_file_lru(page)) {
trace_android_vh_page_trylock_clear(page);
nr_rotated += thp_nr_pages(page); nr_rotated += thp_nr_pages(page);
list_add(&page->lru, &l_active); list_add(&page->lru, &l_active);
continue; continue;
} }
} }
trace_android_vh_page_trylock_clear(page);
skip_page_referenced: skip_page_referenced:
ClearPageActive(page); /* we are de-activating */ ClearPageActive(page); /* we are de-activating */
SetPageWorkingset(page); SetPageWorkingset(page);
@@ -2221,6 +2216,7 @@ unsigned long reclaim_pages(struct list_head *page_list)
return nr_reclaimed; return nr_reclaimed;
} }
EXPORT_SYMBOL_GPL(reclaim_pages);
static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan, static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
struct lruvec *lruvec, struct scan_control *sc) struct lruvec *lruvec, struct scan_control *sc)

View File

@@ -9,14 +9,51 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/pcm_iec958.h> #include <sound/pcm_iec958.h>
static int create_iec958_consumer(uint rate, uint sample_width, /**
u8 *cs, size_t len) * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Create the consumer format channel status data in @cs of maximum size
* @len. When relevant, the configuration-dependant bits will be set as
* unspecified.
*
* Drivers should then call einter snd_pcm_fill_iec958_consumer() or
* snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified
* bits by their actual values.
*
* Drivers may wish to tweak the contents of the buffer after creation.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len)
{ {
unsigned int fs, ws;
if (len < 4) if (len < 4)
return -EINVAL; return -EINVAL;
memset(cs, 0, len);
cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
cs[1] = IEC958_AES1_CON_GENERAL;
cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;
if (len > 4)
cs[4] = IEC958_AES4_CON_WORDLEN_NOTID;
return len;
}
EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default);
static int fill_iec958_consumer(uint rate, uint sample_width,
u8 *cs, size_t len)
{
if (len < 4)
return -EINVAL;
if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) {
unsigned int fs;
switch (rate) { switch (rate) {
case 32000: case 32000:
fs = IEC958_AES3_CON_FS_32000; fs = IEC958_AES3_CON_FS_32000;
@@ -43,7 +80,14 @@ static int create_iec958_consumer(uint rate, uint sample_width,
return -EINVAL; return -EINVAL;
} }
if (len > 4) { cs[3] &= ~IEC958_AES3_CON_FS;
cs[3] |= fs;
}
if (len > 4 &&
(cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) {
unsigned int ws;
switch (sample_width) { switch (sample_width) {
case 16: case 16:
ws = IEC958_AES4_CON_WORDLEN_20_16; ws = IEC958_AES4_CON_WORDLEN_20_16;
@@ -64,21 +108,58 @@ static int create_iec958_consumer(uint rate, uint sample_width,
default: default:
return -EINVAL; return -EINVAL;
} }
cs[4] &= ~IEC958_AES4_CON_WORDLEN;
cs[4] |= ws;
} }
memset(cs, 0, len);
cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
cs[1] = IEC958_AES1_CON_GENERAL;
cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs;
if (len > 4)
cs[4] = ws;
return len; return len;
} }
/**
* snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status
* @runtime: pcm runtime structure with ->rate filled in
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Fill the unspecified bits in an IEC958 status bits array using the
* parameters of the PCM runtime @runtime.
*
* Drivers may wish to tweak the contents of the buffer after its been
* filled.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime,
u8 *cs, size_t len)
{
return fill_iec958_consumer(runtime->rate,
snd_pcm_format_width(runtime->format),
cs, len);
}
EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer);
/**
* snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status
* @params: the hw_params instance for extracting rate and sample format
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Fill the unspecified bits in an IEC958 status bits array using the
* parameters of the PCM hardware parameters @params.
*
* Drivers may wish to tweak the contents of the buffer after its been
* filled..
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len)
{
return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);
}
EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params);
/** /**
* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status
* @runtime: pcm runtime structure with ->rate filled in * @runtime: pcm runtime structure with ->rate filled in
@@ -95,9 +176,13 @@ static int create_iec958_consumer(uint rate, uint sample_width,
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len) size_t len)
{ {
return create_iec958_consumer(runtime->rate, int ret;
snd_pcm_format_width(runtime->format),
cs, len); ret = snd_pcm_create_iec958_consumer_default(cs, len);
if (ret < 0)
return ret;
return snd_pcm_fill_iec958_consumer(runtime, cs, len);
} }
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
@@ -117,7 +202,12 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len) u8 *cs, size_t len)
{ {
return create_iec958_consumer(params_rate(params), params_width(params), int ret;
cs, len);
ret = snd_pcm_create_iec958_consumer_default(cs, len);
if (ret < 0)
return ret;
return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);
} }
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params);

View File

@@ -22,7 +22,6 @@
struct hdmi_codec_channel_map_table { struct hdmi_codec_channel_map_table {
unsigned char map; /* ALSA API channel map position */ unsigned char map; /* ALSA API channel map position */
unsigned long spk_mask; /* speaker position bit mask */
}; };
/* /*
@@ -278,10 +277,12 @@ struct hdmi_codec_priv {
bool busy; bool busy;
struct snd_soc_jack *jack; struct snd_soc_jack *jack;
unsigned int jack_status; unsigned int jack_status;
u8 iec_status[5];
}; };
static const struct snd_soc_dapm_widget hdmi_widgets[] = { static const struct snd_soc_dapm_widget hdmi_widgets[] = {
SND_SOC_DAPM_OUTPUT("TX"), SND_SOC_DAPM_OUTPUT("TX"),
SND_SOC_DAPM_OUTPUT("RX"),
}; };
enum { enum {
@@ -385,10 +386,52 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static int hdmi_codec_iec958_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int hdmi_codec_iec958_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
memcpy(ucontrol->value.iec958.status, hcp->iec_status,
sizeof(hcp->iec_status));
return 0;
}
static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
memcpy(hcp->iec_status, ucontrol->value.iec958.status,
sizeof(hcp->iec_status));
return 0;
}
static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
memset(ucontrol->value.iec958.status, 0xff,
sizeof_field(struct hdmi_codec_priv, iec_status));
return 0;
}
static int hdmi_codec_startup(struct snd_pcm_substream *substream, static int hdmi_codec_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
int ret = 0; int ret = 0;
mutex_lock(&hcp->lock); mutex_lock(&hcp->lock);
@@ -404,7 +447,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
goto err; goto err;
} }
if (hcp->hcd.ops->get_eld) { if (tx && hcp->hcd.ops->get_eld) {
ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
hcp->eld, sizeof(hcp->eld)); hcp->eld, sizeof(hcp->eld));
if (ret) if (ret)
@@ -438,6 +481,42 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
mutex_unlock(&hcp->lock); mutex_unlock(&hcp->lock);
} }
static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
unsigned int sample_width,
unsigned int sample_rate,
unsigned int channels,
struct hdmi_codec_params *hp)
{
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
int idx;
/* Select a channel allocation that matches with ELD and pcm channels */
idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
if (idx < 0) {
dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
idx);
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
return idx;
}
memset(hp, 0, sizeof(*hp));
hdmi_audio_infoframe_init(&hp->cea);
hp->cea.channels = channels;
hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
hp->sample_width = sample_width;
hp->sample_rate = sample_rate;
hp->channels = channels;
hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
return 0;
}
static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
@@ -452,13 +531,25 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
.dig_subframe = { 0 }, .dig_subframe = { 0 },
} }
}; };
int ret, idx; int ret;
if (!hcp->hcd.ops->hw_params)
return 0;
dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
params_width(params), params_rate(params), params_width(params), params_rate(params),
params_channels(params)); params_channels(params));
ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, ret = hdmi_codec_fill_codec_params(dai,
params_width(params),
params_rate(params),
params_channels(params),
&hp);
if (ret < 0)
return ret;
memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status));
ret = snd_pcm_fill_iec958_consumer_hw_params(params, hp.iec.status,
sizeof(hp.iec.status)); sizeof(hp.iec.status));
if (ret < 0) { if (ret < 0) {
dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
@@ -466,31 +557,47 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
} }
hdmi_audio_infoframe_init(&hp.cea); cf->bit_fmt = params_format(params);
hp.cea.channels = params_channels(params);
hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
/* Select a channel allocation that matches with ELD and pcm channels */
idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels);
if (idx < 0) {
dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
idx);
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
return idx;
}
hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
hp.sample_width = params_width(params);
hp.sample_rate = params_rate(params);
hp.channels = params_channels(params);
return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data,
cf, &hp); cf, &hp);
} }
static int hdmi_codec_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int channels = runtime->channels;
unsigned int width = snd_pcm_format_width(runtime->format);
unsigned int rate = runtime->rate;
struct hdmi_codec_params hp;
int ret;
if (!hcp->hcd.ops->prepare)
return 0;
dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
width, rate, channels);
ret = hdmi_codec_fill_codec_params(dai, width, rate, channels, &hp);
if (ret < 0)
return ret;
memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status));
ret = snd_pcm_fill_iec958_consumer(runtime, hp.iec.status,
sizeof(hp.iec.status));
if (ret < 0) {
dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
ret);
return ret;
}
cf->bit_fmt = runtime->format;
return hcp->hcd.ops->prepare(dai->dev->parent, hcp->hcd.data,
cf, &hp);
}
static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt) unsigned int fmt)
{ {
@@ -582,6 +689,7 @@ static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
.startup = hdmi_codec_startup, .startup = hdmi_codec_startup,
.shutdown = hdmi_codec_shutdown, .shutdown = hdmi_codec_shutdown,
.hw_params = hdmi_codec_hw_params, .hw_params = hdmi_codec_hw_params,
.prepare = hdmi_codec_prepare,
.set_fmt = hdmi_codec_i2s_set_fmt, .set_fmt = hdmi_codec_i2s_set_fmt,
.mute_stream = hdmi_codec_mute, .mute_stream = hdmi_codec_mute,
}; };
@@ -615,23 +723,40 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
static struct snd_kcontrol_new hdmi_codec_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
.info = hdmi_codec_iec958_info,
.get = hdmi_codec_iec958_mask_get,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
.info = hdmi_codec_iec958_info,
.get = hdmi_codec_iec958_default_get,
.put = hdmi_codec_iec958_default_put,
},
{
.access = (SNDRV_CTL_ELEM_ACCESS_READ |
SNDRV_CTL_ELEM_ACCESS_VOLATILE),
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "ELD",
.info = hdmi_eld_ctl_info,
.get = hdmi_eld_ctl_get,
},
};
static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct snd_soc_dai_driver *drv = dai->driver; struct snd_soc_dai_driver *drv = dai->driver;
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
struct snd_kcontrol *kctl; unsigned int i;
struct snd_kcontrol_new hdmi_eld_ctl = {
.access = SNDRV_CTL_ELEM_ACCESS_READ |
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "ELD",
.info = hdmi_eld_ctl_info,
.get = hdmi_eld_ctl_get,
.device = rtd->pcm->device,
};
int ret; int ret;
ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -648,26 +773,41 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(hdmi_codec_controls); i++) {
struct snd_kcontrol *kctl;
/* add ELD ctl with the device number corresponding to the PCM stream */ /* add ELD ctl with the device number corresponding to the PCM stream */
kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); kctl = snd_ctl_new1(&hdmi_codec_controls[i], dai->component);
if (!kctl) if (!kctl)
return -ENOMEM; return -ENOMEM;
return snd_ctl_add(rtd->card->snd_card, kctl); kctl->id.device = rtd->pcm->device;
ret = snd_ctl_add(rtd->card->snd_card, kctl);
if (ret < 0)
return ret;
}
return 0;
} }
static int hdmi_dai_probe(struct snd_soc_dai *dai) static int hdmi_dai_probe(struct snd_soc_dai *dai)
{ {
struct snd_soc_dapm_context *dapm; struct snd_soc_dapm_context *dapm;
struct hdmi_codec_daifmt *daifmt; struct hdmi_codec_daifmt *daifmt;
struct snd_soc_dapm_route route = { struct snd_soc_dapm_route route[] = {
{
.sink = "TX", .sink = "TX",
.source = dai->driver->playback.stream_name, .source = dai->driver->playback.stream_name,
},
{
.sink = dai->driver->capture.stream_name,
.source = "RX",
},
}; };
int ret; int ret;
dapm = snd_soc_component_get_dapm(dai->component); dapm = snd_soc_component_get_dapm(dai->component);
ret = snd_soc_dapm_add_routes(dapm, &route, 1); ret = snd_soc_dapm_add_routes(dapm, route, 2);
if (ret) if (ret)
return ret; return ret;
@@ -692,10 +832,16 @@ static void plugged_cb(struct device *dev, bool plugged)
{ {
struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); struct hdmi_codec_priv *hcp = dev_get_drvdata(dev);
if (plugged) if (plugged) {
if (hcp->hcd.ops->get_eld) {
hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data,
hcp->eld, sizeof(hcp->eld));
}
hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT);
else } else {
hdmi_codec_jack_report(hcp, 0); hdmi_codec_jack_report(hcp, 0);
memset(hcp->eld, 0, sizeof(hcp->eld));
}
} }
static int hdmi_codec_set_jack(struct snd_soc_component *component, static int hdmi_codec_set_jack(struct snd_soc_component *component,
@@ -703,7 +849,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
void *data) void *data)
{ {
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
int ret = -EOPNOTSUPP; int ret = -ENOTSUPP;
if (hcp->hcd.ops->hook_plugged_cb) { if (hcp->hcd.ops->hook_plugged_cb) {
hcp->jack = jack; hcp->jack = jack;
@@ -719,7 +865,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
{ {
struct hdmi_codec_daifmt *cf = dai->playback_dma_data; struct hdmi_codec_daifmt *cf;
int ret; int ret;
ret = hdmi_dai_probe(dai); ret = hdmi_dai_probe(dai);
@@ -751,6 +897,14 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.formats = I2S_FORMATS, .formats = I2S_FORMATS,
.sig_bits = 24, .sig_bits = 24,
}, },
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 8,
.rates = HDMI_RATES,
.formats = I2S_FORMATS,
.sig_bits = 24,
},
.ops = &hdmi_codec_i2s_dai_ops, .ops = &hdmi_codec_i2s_dai_ops,
.pcm_new = hdmi_codec_pcm_new, .pcm_new = hdmi_codec_pcm_new,
}; };
@@ -767,6 +921,13 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.rates = HDMI_RATES, .rates = HDMI_RATES,
.formats = SPDIF_FORMATS, .formats = SPDIF_FORMATS,
}, },
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = HDMI_RATES,
.formats = SPDIF_FORMATS,
},
.ops = &hdmi_codec_spdif_dai_ops, .ops = &hdmi_codec_spdif_dai_ops,
.pcm_new = hdmi_codec_pcm_new, .pcm_new = hdmi_codec_pcm_new,
}; };
@@ -819,7 +980,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
} }
dai_count = hcd->i2s + hcd->spdif; dai_count = hcd->i2s + hcd->spdif;
if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params || if (dai_count < 1 || !hcd->ops ||
(!hcd->ops->hw_params && !hcd->ops->prepare) ||
!hcd->ops->audio_shutdown) { !hcd->ops->audio_shutdown) {
dev_err(dev, "%s: Invalid parameters\n", __func__); dev_err(dev, "%s: Invalid parameters\n", __func__);
return -EINVAL; return -EINVAL;
@@ -832,6 +994,11 @@ static int hdmi_codec_probe(struct platform_device *pdev)
hcp->hcd = *hcd; hcp->hcd = *hcd;
mutex_init(&hcp->lock); mutex_init(&hcp->lock);
ret = snd_pcm_create_iec958_consumer_default(hcp->iec_status,
sizeof(hcp->iec_status));
if (ret < 0)
return ret;
daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL);
if (!daidrv) if (!daidrv)
return -ENOMEM; return -ENOMEM;