6.6.157-rc1 review
Subsystems (5)
Greg Kroah-Hartman
maintainerPATCH 564/1424 drm/bridge: cdns-mhdp8546: Return an error pointer on allocation failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Ripard <[email protected]>
[ Upstream commit 30ac1d403438a6c6039f0af5bb2df3d021f96036 ]
The drm_bridge_funcs.atomic_reset documentation states that the hook must return either a valid drm_bridge_state object or an ERR_PTR().
The cdns_mhdp_bridge_atomic_reset() callback returns NULL when the allocation of its state fails, violating this contract.
Return ERR_PTR(-ENOMEM) instead.
--- drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +1 -1
@@ -2161,7 +2161,7 @@ cdns_mhdp_bridge_atomic_reset(struct drm_bridge *bridge) cdns_mhdp_state =kzalloc (sizeof (*cdns_mhdp_state),GFP_KERNEL );if (!cdns_mhdp_state) -return NULL ; +return ERR_PTR (-ENOMEM );__drm_atomic_helper_bridge_reset (bridge, &cdns_mhdp_state->base);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 565/1424 smack: fix incorrect task context in smack_msg_queue_msgrcv
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Andreev <[email protected]>
[ Upstream commit fba3d32825f4bbc8e20f0cdc3b14df57965b8fe5 ]
The smack_msg_queue_msgrcv() function incorrectly checks the permissions of the 'current' task instead of the 'target' task.
In the msgsnd() syscall path, if a receiver is already waiting, the pipelined_send() optimization is used to push the message directly to the receiver task:
ipc/msg.c`pipelined_send():
` smp_store_release(&msr->r_msg, msg)In this case, the 'sender' (current) task performs the check on behalf of the 'receiver' task (msr->r_tsk, passed as the 'target' parameter):
ipc/msg.c`pipelined_send():
` security_msg_queue_msgrcv(,, target := msr->r_tsk,,)
However, smack_msg_queue_msgrcv() ignores the 'target' and checks 'current':
smack_msg_queue_msgrcv(…)
` smk_curacc_msq(isp, MAY_READWRITE); // current task
'current' MAY satisfy smack_msg_queue_msgrcv r/w requirement, but 'target' (the receiver task) might NOT;
as a result, an unauthorized receiver gets the message, violating MAC policy.
Test:
1) create a sysv message queue with label “foo”
2) echo "bar foo r" >/smack/load2
3) msgrcv(,,,0,MSG_NOERROR) in "bar"-labeled task. The task is waiting for the messages ...
4) msgsnd() from a "foo"-labeled task:
"bar"-labeled task gets the message.
This patch fixes the issue by checking permission on the 'target' task instead of 'current'.
(2008-02-04, Casey Schaufler)
--- security/smack/smack_lsm.c | 65 +++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 18 deletions(-)
security/smack/smack_lsm.c +47 -18
@@ -145,12 +145,13 @@ static int smk_bu_note(char *note, struct smack_known *sskp,#define smk_bu_note (note, sskp, oskp, mode,RC ) (RC)#endif -#ifdef CONFIG_SECURITY_SMACK_BRINGUP -static int smk_bu_current (char *note,struct smack_known *oskp, -int mode,int rc) +static int +smk_bu_tsk_to_obj (struct task_struct *tsk,const struct task_smack *tsp, +char *note,struct smack_known *oskp,int mode,int rc) { -struct task_smack *tsp =smack_cred (current_cred ()); +#ifdef CONFIG_SECURITY_SMACK_BRINGUP char acc[SMK_NUM_ACCESS_TYPE +1 ]; +char comm[TASK_COMM_LEN ];if (rc <=0 )return rc;
@@ -158,14 +159,22 @@ static int smk_bu_current(char *note, struct smack_known *oskp, rc =0 ;smk_bu_mode (mode, acc); +pr_info ("Smack %s: (%s %s %s) %s %s\n" , smk_bu_mess[rc], - tsp->smk_task->smk_known, oskp->smk_known, - acc, current->comm, note); +smk_of_task (tsp)->smk_known, oskp->smk_known, + acc,get_task_comm (comm, tsk), note);return 0 ; -}#else -#define smk_bu_current (note, oskp, mode,RC ) (RC) +return rc;#endif +} + +static int smk_bu_current (char *note,struct smack_known *oskp, +int mode,int rc) +{ +return smk_bu_tsk_to_obj (current,smack_cred (current_cred ()), + note, oskp, mode, rc); +}#ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_task (struct task_struct *otp,int mode,int rc)
@@ -3283,14 +3292,20 @@ static int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops, }/** -* smk_curacc_msq : helper to check if current has access on msq -* @isp : the msq +* smk_tskacc_msq : helper to check if tsk has access on msq +* @tsk: the task that requests access +* @isp : the sysv msg queue permissions * @access : access requested * -* return 0 if current has access, error otherwise +* return 0 if tsk has access, error otherwise */ -static int smk_curacc_msq (struct kern_ipc_perm *isp,int access) +static int +smk_tskacc_msq (struct task_struct *tsk,struct kern_ipc_perm *isp,int access) { +const bool tsk_is_current = (tsk == current); +const struct cred *const tsk_cred = + (tsk_is_current ?current_cred () :get_task_cred (tsk)); +struct task_smack *const tsp =smack_cred (tsk_cred);struct smack_known *msp =smack_of_ipc (isp);struct smk_audit_info ad;int rc;
@@ -3299,11 +3314,25 @@ static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)smk_ad_init (&ad, __func__,LSM_AUDIT_DATA_IPC ); ad.a.u.ipc_id = isp->id;#endif - rc =smk_curacc (msp, access, &ad); - rc =smk_bu_current ("msq" , msp, access, rc); + rc =smk_tskacc (tsp, msp, access, &ad); + rc =smk_bu_tsk_to_obj (tsk, tsp,"msq" , msp, access, rc); +if (!tsk_is_current) +put_cred (tsk_cred);return rc; } +/** +* smk_curacc_msq : helper to check if current has access on msq +* @isp : the sysv msg queue permissions +* @access : access requested +* +* return 0 if current has access, error otherwise +*/ +static int smk_curacc_msq (struct kern_ipc_perm *isp,int access) +{ +return smk_tskacc_msq (current, isp, access); +} +/** * smack_msg_queue_associate - Smack access check for msg_queue * @isp: the object
@@ -3371,21 +3400,21 @@ static int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg }/** -* smack_msg_queue_msgrcv - Smack access check for msg_queue +* smack_msg_queue_msgrcv - check it target has r/w access to msg_queue * @isp: the object * @msg: unused -* @target: unused +* @target: the task that msgrcv() from the queue * @type: unused * @mode: unused * -* Returns 0 if current has read and write access, error code otherwise +* Returns 0 if target has read and write access, error code otherwise */ static int smack_msg_queue_msgrcv (struct kern_ipc_perm *isp,struct msg_msg *msg,struct task_struct *target,long type,int mode) { -return smk_curacc_msq (isp,MAY_READWRITE ); +return smk_tskacc_msq (target, isp,MAY_READWRITE ); }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 566/1424 smack: simplify write handlers of sysfs entries
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Antipov <[email protected]>
[ Upstream commit b78fede1c69a090d377bf80417ce1f7f7f314534 ]
Use the convenient 'kstrto{u,s}32_from_user()' to simplify write handlers of /smack/{doi,direct,mapped,logging,ptrace} sysfs entries.
Stable-dep-of: 577dc3b6a8cf ("smack: deduplicate smackfs/{direct,mapped} file_operations")
--- security/smack/smackfs.c | 81 +++++++++++----------------------------- 1 file changed, 22 insertions(+), 59 deletions(-)
security/smack/smackfs.c +22 -59
@@ -1616,24 +1616,17 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf,static ssize_t smk_write_doi (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -char temp[80 ]; -unsigned long u; +int ret; +u32 u;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; - - temp[count] ='\0' ; + ret =kstrtou32_from_user (buf, count,10 , &u); +if (unlikely (ret)) +return ret; -if (kstrtoul (temp,10 , &u)) -return -EINVAL ; - -if (u ==CIPSO_V4_DOI_UNKNOWN || u >U32_MAX ) +if (u ==CIPSO_V4_DOI_UNKNOWN )return -EINVAL ;return smk_cipso_doi (u,GFP_KERNEL ) ? : count;
@@ -1682,22 +1675,14 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct smack_known *skp; -char temp[80 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; - - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret;/* * Don't do anything if the value hasn't actually changed.
@@ -1760,22 +1745,14 @@ static ssize_t smk_write_mapped(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct smack_known *skp; -char temp[80 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; - - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret;/* * Don't do anything if the value hasn't actually changed.
@@ -2196,22 +2173,15 @@ static ssize_t smk_read_logging(struct file *filp, char __user *buf,static ssize_t smk_write_logging (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -char temp[32 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret; - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ;if (i <0 || i >3 )return -EINVAL ; log_policy = i;
@@ -2854,22 +2824,15 @@ static ssize_t smk_read_ptrace(struct file *filp, char __user *buf,static ssize_t smk_write_ptrace (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -char temp[32 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (*ppos !=0 || count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret; - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ;if (i <SMACK_PTRACE_DEFAULT || i >SMACK_PTRACE_MAX )return -EINVAL ; smack_ptrace_rule = i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 567/1424 smack: deduplicate smackfs/{direct,mapped} file_operations
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Andreev <[email protected]>
[ Upstream commit 577dc3b6a8cf200e6e27b2d9967cac14a1fed2f3 ]
The file_operations for smackfs/direct and smackfs/mapped are identical up to a textual replacement of "direct" with "mapped"
This patch combines two instances of file_operations into one, handling both files.
--- security/smack/smack.h | 5 +- security/smack/smackfs.c | 133 ++++++++++++--------------------------- 2 files changed, 42 insertions(+), 96 deletions(-)
security/smack/smack.h +3 -2
@@ -299,8 +299,9 @@ int smack_populate_secattr(struct smack_known *skp);* Shared data. */ extern int smack_enabled__initdata ; -extern int smack_cipso_direct; -extern int smack_cipso_mapped; +extern int smack_cipso_auto_level[2 ]; +#define smack_cipso_direct (+smack_cipso_auto_level[0]) +#define smack_cipso_mapped (+smack_cipso_auto_level[1])extern struct smack_known *smack_net_ambient;extern struct smack_known *smack_syslog_label;#ifdef CONFIG_SECURITY_SMACK_BRINGUP
security/smack/smackfs.c +39 -94
206 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 568/1424 smack: restrict smackfs/{direct,mapped} values to 0-255
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Andreev <[email protected]>
[ Upstream commit a7c44fd9f80e37763acf9cd3c87a58058d206427 ]
Both smackfs/direct and smackfs/mapped incorrectly accept the full range of integer values. For example:
# cd /sys/fs/smackfs/
# cat direct ; echo
250 # cat cipso2
@ 250/2
_ 250/2,4,5,6,7,8
* 250/3,5,7
^ 250/2,4,5,6,7
? 250/3,4,5,6,7,8 # echo -1234 >direct ; cat direct ; echo
-1234
# cat cipso2
@ -1234/2
_ -1234/2,4,5,6,7,8
* -1234/3,5,7
^ -1234/2,4,5,6,7
? -1234/3,4,5,6,7,8
#I noticed two things regarding this:
1) sensitivity levels are truncated to 8 bits when labeling outgoing packets (0x2e = 46 for the -1234 example above)
2) the reverse process fails: incoming packets with sensitivity level 46 do not match these smackfs/cipso2 entries.
Even observation (1) on its own warrants a fix.
This patch restricts smackfs/direct and smackfs/mapped accepted values to the 0-255 range.
--- security/smack/smack.h | 2 +- security/smack/smackfs.c | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-)
security/smack/smack.h +1 -1
@@ -299,7 +299,7 @@ int smack_populate_secattr(struct smack_known *skp);* Shared data. */ extern int smack_enabled__initdata ; -extern int smack_cipso_auto_level[2 ]; +extern u8 smack_cipso_auto_level[2 ];#define smack_cipso_direct (+smack_cipso_auto_level[0])#define smack_cipso_mapped (+smack_cipso_auto_level[1])extern struct smack_known *smack_net_ambient;
security/smack/smackfs.c +14 -12
@@ -92,7 +92,7 @@ struct smack_known *smack_net_ambient;* secid is contained directly in the category set. * It can be reset via smackfs/mapped */ -int smack_cipso_auto_level[2 ] = { +u8 smack_cipso_auto_level[2 ] = {SMACK_CIPSO_DIRECT_DEFAULT ,SMACK_CIPSO_MAPPED_DEFAULT , };
@@ -1659,17 +1659,15 @@ static const struct file_operations smk_doi_ops = {static ssize_t smk_read_cipso_auto_level (struct file *filp,char __user *buf,size_t count,loff_t *ppos) { -char temp[80 ]; -ssize_t rc; +char temp[sizeof "255" ]; +int n;if (*ppos !=0 )return 0 ; -sprintf (temp,"%d" , smack_cipso_auto_level[ -smk_cipso_auto_level_idx (filp)]); - rc =simple_read_from_buffer (buf, count, ppos, temp,strlen (temp)); - -return rc; + n =sprintf (temp,"%u" , (unsigned int )smack_cipso_auto_level[ +smk_cipso_auto_level_idx (filp)]); +return simple_read_from_buffer (buf, count, ppos, temp, n); }/**
@@ -1685,13 +1683,16 @@ static ssize_t smk_write_cipso_auto_level(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { - struct smack_known *skp; -int i, ret, idx, old_lvl; + int ret, idx; +u8 i, old_lvl;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; - - ret =kstrtos32_from_user (buf, count,10 , &i); +/* +* draft-ietf-cipso-ipsecurity-01 (CIPSO 2.2), 3.4.2.4: +* "Sensitivity Level is 1 octet in length. Its value is from 0 to 255" +*/ + ret =kstrtou8_from_user (buf, count,10 , &i);if (unlikely (ret))return ret;
@@ -1704,6 +1705,7 @@ smk_write_cipso_auto_level(struct file *filp, const char __user *buf, old_lvl = smack_cipso_auto_level[idx];if (old_lvl != i) { +struct smack_known *skp;mutex_lock (&smack_known_lock);list_for_each_entry_rcu (skp, &smack_known_list, list) if (skp->smk_netlabel.attr.mls.lvl ==
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 569/1424 x86/cfi: Use symmetric SYM_START and SYM_END in __CFI_TYPE()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Remus <[email protected]>
[ Upstream commit 0cfdf974f133e0ff17ed80e7895adbe7889d9522 ]
Commit
ccace936eec7 ("x86: Add types to indirectly called assembly functions")
introduced a x86-specific implementation of __CFI_TYPE() using an asymmetric combination of SYM_START() and SYM_FUNC_END() to add a symbol to the KCFI type identifier that precedes a function.
This asymmetric combination is an issue if SYM_FUNC_END() ever gets extended in a way that requires it to be used symmetrically with SYM_FUNC_START*(). For instance to emit DWARF CFI directives that denote the start/end of a function. [1]
Use SYM_END() with SYM_T_FUNC instead. No functional change, as the generic implementation of SYM_FUNC_END(name) expands into SYM_END(name, SYM_T_FUNC).
--- arch/x86/include/asm/linkage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/linkage.h +1 -1
@@ -103,7 +103,7 @@ .byte 0xb8 ASM_NL \ .long __kcfi_typeid_##name ASM_NL \ CFI_POST_PADDING \ - SYM_FUNC_END(__cfi_##name) + SYM_END(__cfi_##name, SYM_T_FUNC)/* UML needs to be able to override memcpy() and friends for KASAN. */ #ifdef CONFIG_UML
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 570/1424 platform/chrome: cros_ec_typec: Reject out-of-bounds PD cap count
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
[ Upstream commit a0a8cd9fc9c48b95095bcec4b146f7a99486f58e ]
cros_typec_register_partner_pdos() copies the partner PDOs from the EC TYPEC_STATUS response into the fixed caps_desc.pdo[PDO_MAX_OBJECTS] array.
memcpy(caps_desc.pdo, resp->source_cap_pdos, sizeof(u32) * resp->source_cap_count); ... memcpy(caps_desc.pdo, resp->sink_cap_pdos, sizeof(u32) * resp->sink_cap_count);
PDO_MAX_OBJECTS is 7. source_cap_count and sink_cap_count are u8 fields from the EC. The only check is that they are not both zero. If either is larger than 7, the memcpy writes past the end of the array on the stack. A count of 255 overflows it by about 1 KB. The EC source arrays are only seven entries wide. A larger count reads past them too.
The ChromeOS EC firmware caps these counts today, so a compliant setup does not hit this. The kernel should still validate these values rather than trust them.
Validate the counts in cros_typec_register_partner_pdos() next to the memcpy. Skip the PDO registration if either count is above PDO_MAX_OBJECTS. The rest of cros_typec_handle_status() still runs so events are handled and cleared.
--- drivers/platform/chrome/cros_ec_typec.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/platform/chrome/cros_ec_typec.c +6 -0
@@ -942,6 +942,12 @@ static void cros_typec_register_partner_pdos(struct cros_typec_data *typec,if (!resp->source_cap_count && !resp->sink_cap_count)return ; +if (resp->source_cap_count >PDO_MAX_OBJECTS || + resp->sink_cap_count >PDO_MAX_OBJECTS ) { +dev_warn (typec->dev,"Invalid PDO count from EC, port: %d\n" , port_num); +return ; + } + port->partner_pd =typec_partner_usb_power_delivery_register (port->partner, &desc);if (IS_ERR (port->partner_pd)) {dev_warn (typec->dev,"Failed to register partner PD device, port: %d\n" , port_num);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 571/1424 HID: core: quiesce input in hid_hw_stop() to prevent use-after-free
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Philipp Weber <[email protected]>
[ Upstream commit a4bc41504690b7d7064931909874f5b98cd148b6 ]
A driver's probe calls hid_device_io_start() to enable input delivery, then fails at a later initialization step and unwinds via hid_hw_stop(). The unwind frees struct hidraw via hidraw_disconnect() while in-flight HID reports may still be running on another CPU, dereferencing the freed object through hidraw_report_event(). syzbot reports the resulting use-after-free for the corsair-psu HID driver.
Edward Adam Davis posted a per-driver fix for corsair-psu that adds an explicit hid_device_io_stop() before hid_hw_stop() in the probe error path ("hwmon: prevent packets from going to driver for probe", 2026-04-28). Auditing the tree shows 15 drivers call hid_device_io_start(); 7 also call hid_device_io_stop() and 8 do not:
drivers calling hid_device_io_start() without a matching hid_device_io_stop() before hid_hw_stop():
drivers/hwmon/corsair-psu.c (fix posted by Edward)
drivers/hwmon/corsair-cpro.c drivers/hwmon/nzxt-kraken3.c drivers/hwmon/nzxt-smart2.c drivers/hwmon/gigabyte_waterforce.c drivers/hid/hid-logitech-dj.c drivers/hid/hid-nintendo.c drivers/hid/hid-mcp2221.c
Roughly half of all callers of the API are exposed. Centralize the quiesce in hid_hw_stop() so callers do not have to remember the matching stop: if a driver has left hdev->io_started true on entry, call hid_device_io_stop() before hid_disconnect().
For the 7 drivers that already call hid_device_io_stop() correctly, hdev->io_started is false on entry, the guard short-circuits, and behavior is unchanged.
No Fixes: tag because the affected drivers gained their hid_device_io_start() calls independently over years; the bug is a class-wide API misuse rather than a regression from one commit.
--- drivers/hid/hid-core.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/hid/hid-core.c +7 -0
@@ -2370,9 +2370,16 @@ EXPORT_SYMBOL_GPL(hid_hw_start);* * This is usually called from remove function or from probe when something * failed and hid_hw_start was called already. +* +* If the caller enabled HID input via hid_device_io_start() and is unwinding +* without an explicit hid_device_io_stop(), quiesce input first so that +* in-flight reports cannot reach handlers (e.g. hidraw_report_event) whose +* backing objects hid_disconnect() is about to free. */ void hid_hw_stop (struct hid_device *hdev) { +if (hdev->io_started) +hid_device_io_stop (hdev);hid_disconnect (hdev); hdev->ll_driver->stop (hdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 572/1424 HID: nintendo: Fix imu_timestamp_us double increment per report
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christos Maragkos <[email protected]>
[ Upstream commit 1f9b25d3fb65b9384dec16d9db13a3e71abd9145 ]
Previously, the imu_timestamp_us variable was incremented twice per report, causing it to advance by two times the desired amount.
This resulted in incorrect jumps in IMU timestamps reported using MSC_TIMESTAMP, so userspace applications saw corrupted timing on functions such as gyroscope-based aim and motion controls.
This is fixed by removing the redundant increment at the start of the report handling so the remaining can account for the full report interval.
--- drivers/hid/hid-nintendo.c | 1 - 1 file changed, 1 deletion(-)
drivers/hid/hid-nintendo.c +0 -1
@@ -1164,7 +1164,6 @@ static void joycon_parse_imu_report(struct joycon_ctlr *ctlr, dropped_threshold = ctlr->imu_avg_delta_ms *3 /2 ; dropped_pkts = (delta -min (delta, dropped_threshold)) / ctlr->imu_avg_delta_ms; - ctlr->imu_timestamp_us +=1000 * ctlr->imu_avg_delta_ms;if (dropped_pkts >JC_IMU_DROPPED_PKT_WARNING ) { hid_warn(ctlr->hdev, "compensating for %u dropped IMU reports\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 573/1424 HID: roccat: bound device-supplied profile index
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 43fae42628a8c10fa8981773d7ec9f1a367821a7 ]
kone_keep_values_up_to_date() and kone_profile_activated() use an 8-bit, device-supplied profile value as an index into the 5-element kone->profiles[] array without a range check. A malicious USB device claiming the Roccat Kone id can send a switch-profile event (or a startup_profile read at probe) with an out-of-range value and make the driver read out of bounds; the result is exposed via the actual_dpi sysfs attribute.
Reject out-of-range indices in both paths.
This was found with static analysis and confirmed with the KUnit test added in the following patch (KASAN: slab-out-of-bounds).
--- drivers/hid/hid-roccat-kone.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/hid/hid-roccat-kone.c +6 -2
@@ -36,6 +36,8 @@ static uint profile_numbers[5] = {0, 1, 2, 3, 4};static void kone_profile_activated (struct kone_device *kone,uint new_profile) { +if (new_profile <1 || new_profile >ARRAY_SIZE (kone->profiles)) + new_profile =1 ; kone->actual_profile = new_profile; kone->actual_dpi = kone->profiles[new_profile -1 ].startup_dpi; }
@@ -793,8 +795,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone, {switch (event->event) {case kone_mouse_event_switch_profile: - kone->actual_dpi = kone->profiles[event->value -1 ]. - startup_dpi; +if (event->value >=1 && + event->value <=ARRAY_SIZE (kone->profiles)) + kone->actual_dpi = + kone->profiles[event->value -1 ].startup_dpi; fallthrough;case kone_mouse_event_osd_profile: kone->actual_profile = event->value;
Signature · 1 line
2.53.0
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.6.157-rc1-gfcb8c41a77e1 #1 SMP PREEMPT_DYNAMIC Sat Sep 12 13:50:15 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Greg Kroah-Hartman
maintainerPATCH 574/1424 soc: samsung: exynos-pmu: fix of_node refcount leak in exynos_get_pmu_regmap()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weigang He <[email protected]>
[ Upstream commit fa476d53edd24e8105faace04e881b9c4179738f ]
exynos_get_pmu_regmap() obtains a device_node via of_find_matching_node() and passes it to exynos_get_pmu_regmap_by_phandle(np, NULL). With propname == NULL the callee uses np directly and does not drop a reference, so the reference taken by of_find_matching_node() is leaked on every call -- including on each -EPROBE_DEFER retry of the only in-tree caller, exynos_retention_init() in the Exynos pinctrl driver.
Annotate np with the __free(device_node) cleanup attribute so the reference is released when the function returns.
Found by static analysis tool CodeQL.
--- drivers/soc/samsung/exynos-pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/soc/samsung/exynos-pmu.c +2 -2
@@ -115,8 +115,8 @@ static const struct mfd_cell exynos_pmu_devs[] = {struct regmap *exynos_get_pmu_regmap (void ) { -struct device_node *np =of_find_matching_node (NULL , - exynos_pmu_of_device_ids); + struct device_node *np __free(device_node) = +of_find_matching_node (NULL , exynos_pmu_of_device_ids);if (np)return syscon_node_to_regmap (np);return ERR_PTR (-ENODEV );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 575/1424 media: cec-pin: Fix event FIFO ordering
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gui-Dong Han <[email protected]>
[ Upstream commit a1d83d1b810665bd53ce8a7b7867e054d68676c7 ]
cec_pin_update() fills work_pin_events[] and work_pin_ts[], then increments work_pin_num_events. cec_pin_thread_func() uses that counter to decide when to read the FIFO entries.
Do not let the counter update be observed without the event update. Also do not let a freed slot be reused before the thread has finished reading it. Use release operations when publishing an entry and releasing a slot, and acquire operations when consuming those counter updates.
Leave the other work_pin_num_events users as they do not participate in this FIFO publication path.
--- drivers/media/cec/core/cec-pin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/media/cec/core/cec-pin.c +4 -4
@@ -114,7 +114,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)return ; pin->adap->cec_pin_is_high = v; -if (atomic_read (&pin->work_pin_num_events) <CEC_NUM_PIN_EVENTS ) { +if (atomic_read_acquire (&pin->work_pin_num_events) <CEC_NUM_PIN_EVENTS ) {u8 ev = v;if (pin->work_pin_events_dropped) {
@@ -125,7 +125,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) pin->work_pin_ts[pin->work_pin_events_wr] =ktime_get (); pin->work_pin_events_wr = (pin->work_pin_events_wr +1 ) %CEC_NUM_PIN_EVENTS ; -atomic_inc (&pin->work_pin_num_events); +atomic_inc_return_release (&pin->work_pin_num_events); }else { pin->work_pin_events_dropped = true; pin->work_pin_events_dropped_cnt++;
@@ -1074,7 +1074,7 @@ static int cec_pin_thread_func(void *_adap) pin->work_tx_ts); } -while (atomic_read (&pin->work_pin_num_events)) { +while (atomic_read_acquire (&pin->work_pin_num_events)) {unsigned int idx = pin->work_pin_events_rd;u8 v = pin->work_pin_events[idx];
@@ -1083,7 +1083,7 @@ static int cec_pin_thread_func(void *_adap) v &CEC_PIN_EVENT_FL_DROPPED , pin->work_pin_ts[idx]); pin->work_pin_events_rd = (idx +1 ) %CEC_NUM_PIN_EVENTS ; -atomic_dec (&pin->work_pin_num_events); +atomic_dec_return_release (&pin->work_pin_num_events); } switch (atomic_xchg(&pin->work_irq_change,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 576/1424 clk: versaclock7: Fix APLL clock leak on probe failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit e25d8d35e8cbc1a4c04a8b86eed6aa7229f6449e ]
vc7_probe() registers the APLL with clk_register_fixed_rate(), which is not devm-managed and must be explicitly unregistered on probe failure.
Most later errors already unwind through err_clk, but a failure from vc7_get_bank_clk() in the output registration loop returned directly. That skipped clk_unregister_fixed_rate() and leaked the APLL clock.
Route that error through the existing err_clk label so the fixed-rate clock is released consistently with the other probe failure paths.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/clk/clk-versaclock7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/clk-versaclock7.c +1 -1
@@ -1191,7 +1191,7 @@ static int vc7_probe(struct i2c_client *client)if (ret) {dev_err_probe (&client->dev, ret,"unable to register output %d\n" , i); -return ret; + goto err_clk; }switch (bank_src_map.type) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 577/1424 clk: moxart: remove unused variables, fix refcount leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander A. Klimov <[email protected]>
[ Upstream commit 9f275f2ee9ca60ea4c092bdc0195987945ad8ad8 ]
Not only these error checks are redundand,
those of_clk_get() return values weren't cleaned up via clk_put().
--- drivers/clk/clk-moxart.c | 14 -------------- 1 file changed, 14 deletions(-)
drivers/clk/clk-moxart.c +0 -14
@@ -17,7 +17,6 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) {void __iomem *base;struct clk_hw *hw; -struct clk *ref_clk;unsigned int mul;const char *name = node->name;const char *parent_name;
@@ -34,12 +33,6 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) mul =readl (base +0x30 ) >>3 &0x3f ;iounmap (base); - ref_clk =of_clk_get (node,0 ); -if (IS_ERR (ref_clk)) { -pr_err ("%pOF: of_clk_get failed\n" , node); -return ; - } - hw =clk_hw_register_fixed_factor (NULL , name, parent_name,0 , mul,1 );if (IS_ERR (hw)) {pr_err ("%pOF: failed to register clock\n" , node);
@@ -56,7 +49,6 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) {void __iomem *base;struct clk_hw *hw; -struct clk *pll_clk;unsigned int div, val;unsigned int div_idx[] = {2 ,3 ,4 ,6 ,8 };const char *name = node->name;
@@ -78,12 +70,6 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) val =0 ; div = div_idx[val] *2 ; - pll_clk =of_clk_get (node,0 ); -if (IS_ERR (pll_clk)) { -pr_err ("%pOF: of_clk_get failed\n" , node); -return ; - } - hw =clk_hw_register_fixed_factor (NULL , name, parent_name,0 ,1 , div);if (IS_ERR (hw)) {pr_err ("%pOF: failed to register clock\n" , node);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 578/1424 clk: nuvoton: ma35d1: fix ignored div_u64 return values in PLL freq calculation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joey Lu <[email protected]>
[ Upstream commit b3a2223a7805c7e6759a32a5d6ca574ad07e2710 ]
div_u64() does not modify its argument in place; the return value must be assigned. Both ma35d1_calc_smic_pll_freq() and ma35d1_calc_pll_freq() called div_u64() and discarded the result, leaving pll_freq holding the undivided product and thus returning a frequency orders of magnitude too high.
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +2 -2
@@ -92,7 +92,7 @@ static unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0, p =FIELD_GET (SPLL0_CTL0_OUTDIV , pll0_ctl0); outdiv =1 << p; pll_freq = (u64 )parent_rate * n; -div_u64 (pll_freq, m * outdiv); + pll_freq =div_u64 (pll_freq, m * outdiv);return pll_freq; }
@@ -110,7 +110,7 @@ static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long pif (mode ==PLL_MODE_INT ) { pll_freq = (u64 )parent_rate * n; -div_u64 (pll_freq, m * p); + pll_freq =div_u64 (pll_freq, m * p); }else { x =FIELD_GET (PLL_CTL1_FRAC , reg_ctl[1 ]);/* 2 decimal places floating to integer (ex. 1.23 to 123) */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 579/1424 clk: nuvoton: ma35d1: fix PLL_CTL1_FRAC bit field width and fractional calc
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joey Lu <[email protected]>
[ Upstream commit 26de5aed72d80bd8aec2583134aca3597c64fda9 ]
PLL_CTL1_FRAC was defined as GENMASK(31, 24), covering only 8 bits. The hardware fractional field occupies bits [31:8] (24 bits), so the mask must be GENMASK(31, 8).
The previous fractional-mode calculation used FIELD_MAX(PLL_CTL1_FRAC) as the denominator to obtain 2 decimal places. With the corrected 24-bit mask the old divisor is wrong; replace the arithmetic with a proper 24-bit fixed-point rounding to 3 decimal places using the kernel's DIV_ROUND_CLOSEST_ULL helper:
n_frac = n * 1000 + DIV_ROUND_CLOSEST_ULL(x * 1000, 1 << 24)
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +4 -4
@@ -48,7 +48,7 @@#define PLL_CTL1_PD BIT(0)#define PLL_CTL1_BP BIT(1)#define PLL_CTL1_OUTDIV GENMASK(6, 4) -#define PLL_CTL1_FRAC GENMASK(31, 24) +#define PLL_CTL1_FRAC GENMASK(31, 8)#define PLL_CTL2_SLOPE GENMASK(23, 0)#define INDIV_MIN 1
@@ -113,9 +113,9 @@ static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long p pll_freq =div_u64 (pll_freq, m * p); }else { x =FIELD_GET (PLL_CTL1_FRAC , reg_ctl[1 ]); -/* 2 decimal places floating to integer (ex. 1.23 to 123) */ - n = n *100 + ((x *100 ) /FIELD_MAX (PLL_CTL1_FRAC )); - pll_freq =div_u64 (parent_rate * n,100 * m * p); +/* convert 24-bit fraction to 3 decimal digits, rounding to closest */ + n = n *1000 +DIV_ROUND_CLOSEST_ULL ((u64 )x *1000 ,1ULL <<24 ); + pll_freq =div_u64 ((u64 )parent_rate * n,1000 * m * p); }return pll_freq; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 580/1424 clk: nuvoton: ma35d1-pll: convert from round_rate() to determine_rate()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Masney <[email protected]>
[ Upstream commit cd9e9bbfd93be277e316ee854614e2c4cd502fa8 ]
The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series.
Stable-dep-of: e1311954cb60 ("clk: nuvoton: ma35d1: fix ma35d1_clk_pll_determine_rate logic")
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +18 -10
@@ -244,35 +244,43 @@ static unsigned long ma35d1_clk_pll_recalc_rate(struct clk_hw *hw, unsigned longreturn 0 ; } -static long ma35d1_clk_pll_round_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *parent_rate) +static int ma35d1_clk_pll_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) {struct ma35d1_clk_pll *pll =to_ma35d1_clk_pll (hw);u32 reg_ctl[3 ] = {0 };unsigned long pll_freq;long ret; -if (*parent_rate <PLL_FREF_MIN_FREQ || *parent_rate >PLL_FREF_MAX_FREQ ) +if (req->best_parent_rate <PLL_FREF_MIN_FREQ || req->best_parent_rate >PLL_FREF_MAX_FREQ )return -EINVAL ; - ret =ma35d1_pll_find_closest (pll, rate, *parent_rate, reg_ctl, &pll_freq); + ret =ma35d1_pll_find_closest (pll, req->rate, req->best_parent_rate, + reg_ctl, &pll_freq);if (ret <0 )return ret;switch (pll->id) {case CAPLL : reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); - pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], *parent_rate); -return pll_freq; + pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], req->best_parent_rate); + req->rate = pll_freq; + +return 0 ;case DDRPLL :case APLL :case EPLL :case VPLL : reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); reg_ctl[1 ] =readl_relaxed (pll->ctl1_base); - pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, *parent_rate); -return pll_freq; + pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, req->best_parent_rate); + req->rate = pll_freq; + +return 0 ; } + + req->rate =0 ; +return 0 ; }
@@ -311,12 +319,12 @@ static const struct clk_ops ma35d1_clk_pll_ops = { .unprepare = ma35d1_clk_pll_unprepare, .set_rate = ma35d1_clk_pll_set_rate, .recalc_rate = ma35d1_clk_pll_recalc_rate, - .round_rate = ma35d1_clk_pll_round_rate, + .determine_rate = ma35d1_clk_pll_determine_rate, };static const struct clk_ops ma35d1_clk_fixed_pll_ops = { .recalc_rate = ma35d1_clk_pll_recalc_rate, - .round_rate = ma35d1_clk_pll_round_rate, + .determine_rate = ma35d1_clk_pll_determine_rate, }; struct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const char *name,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 581/1424 clk: nuvoton: ma35d1: fix ma35d1_clk_pll_determine_rate logic
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joey Lu <[email protected]>
[ Upstream commit e1311954cb600d5f95cd9e2fe9a7376edc2ac3c5 ]
ma35d1_clk_pll_determine_rate() called ma35d1_pll_find_closest() unconditionally before the switch statement, and then every case branch overwrote pll_freq by reading the current hardware registers. For CAPLL and DDRPLL this means find_closest() ran unnecessarily (and incorrectly, since those PLLs are read-only) and its result was silently discarded.
Fix by moving the find_closest() call inside the APLL/EPLL/VPLL branch where it belongs. Group CAPLL and DDRPLL together as read-only PLLs that simply report their current rate; handle them with an explicit if/else to keep the CAPLL (SMIC design) and DDRPLL (standard design) paths distinct.
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +13 -13
@@ -255,32 +255,32 @@ static int ma35d1_clk_pll_determine_rate(struct clk_hw *hw,if (req->best_parent_rate <PLL_FREF_MIN_FREQ || req->best_parent_rate >PLL_FREF_MAX_FREQ )return -EINVAL ; - ret =ma35d1_pll_find_closest (pll, req->rate, req->best_parent_rate, - reg_ctl, &pll_freq); -if (ret <0 ) -return ret; -switch (pll->id) {case CAPLL : +case DDRPLL : +/* Read-only PLLs: return current rate */ reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); - pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], req->best_parent_rate); +if (pll->id ==CAPLL ) { + pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], req->best_parent_rate); + }else { + reg_ctl[1 ] =readl_relaxed (pll->ctl1_base); + pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, req->best_parent_rate); + } req->rate = pll_freq; -return 0 ; -case DDRPLL :case APLL :case EPLL :case VPLL : - reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); - reg_ctl[1 ] =readl_relaxed (pll->ctl1_base); - pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, req->best_parent_rate); +/* Configurable PLLs: find closest achievable rate */ + ret =ma35d1_pll_find_closest (pll, req->rate, req->best_parent_rate, + reg_ctl, &pll_freq); +if (ret <0 ) +return ret; req->rate = pll_freq; -return 0 ; } req->rate =0 ; -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 582/1424 ASoC: rt700-sdw: always drain jack work on remove
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 612ccf42acd14bb2685fa60c3495ca13e63e8989 ]
rt700_sdw_remove() drains jack_detect_work and jack_btn_check_work only when rt700->hw_init is true. That state bit is cleared by rt700_update_status() when the SoundWire slave becomes UNATTACHED, but a jack work item can already have been queued by rt700_interrupt_callback() or rt700_jack_init() while the device was initialized.
Do not use hw_init as the remove-time guard for draining these work objects. The delayed works are initialized during rt700_init(), so remove can cancel them unconditionally and pair the object lifetime with the codec-private data lifetime instead of a mutable hardware state bit.
This issue was found by our static analysis tool and then confirmed by manual review of the SoundWire status, interrupt and remove paths. The remove path should drain work based on whether the work object exists, not on a runtime hardware state bit that can change after the work was queued.
A QEMU PoC queued jack_detect_work, simulated SDW_SLAVE_UNATTACHED, and then entered remove. DEBUG_OBJECTS reported an active timer/work object associated with the rt700 jack work path after remove skipped the cancel.
This is sent as an RFC because the practical trigger depends on SoundWire core remove ordering after an UNATTACHED status update. If remove cannot run after hw_init has been cleared while jack work is still pending, this is a defensive lifecycle cleanup rather than a reachable race on current systems.
--- sound/soc/codecs/rt700-sdw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
sound/soc/codecs/rt700-sdw.c +2 -4
@@ -459,10 +459,8 @@ static int rt700_sdw_remove(struct sdw_slave *slave) {struct rt700_priv *rt700 =dev_get_drvdata (&slave->dev); -if (rt700->hw_init) { -cancel_delayed_work_sync (&rt700->jack_detect_work); -cancel_delayed_work_sync (&rt700->jack_btn_check_work); - } +cancel_delayed_work_sync (&rt700->jack_detect_work); +cancel_delayed_work_sync (&rt700->jack_btn_check_work);pm_runtime_disable (&slave->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 583/1424 ASoC: fsl_audmix: rework runtime PM handling in probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit 3359ba93d01a23b2e4249e9e44ccfe48eb9c5d71 ]
After pm_runtime_enable() the AUDMIX block is powered off and stays suspended until the first runtime resume. Register writes issued between probe() and the first resume (e.g. from DAPM or ALSA control paths) target unpowered hardware and cause a system hang.
Fix this by calling pm_runtime_resume_and_get() immediately after pm_runtime_enable() to power the hardware up and enable its clocks. Release the reference afterwards with pm_runtime_put() to allow the runtime PM framework to suspend the device and switch the regmap to cache-only mode when idle.
When CONFIG_PM is disabled or runtime PM is not enabled, pm_runtime_* calls are stubs that do not power up the hardware. Handle this case explicitly by calling fsl_audmix_runtime_resume() directly so the hardware is always initialised and its clocks are enabled, ensuring register accesses succeed regardless of PM configuration.
--- sound/soc/fsl/fsl_audmix.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
sound/soc/fsl/fsl_audmix.c +22 -2
@@ -458,6 +458,9 @@ static const struct of_device_id fsl_audmix_ids[] = { };MODULE_DEVICE_TABLE (of, fsl_audmix_ids); +static int fsl_audmix_runtime_resume (struct device *dev); +static int fsl_audmix_runtime_suspend (struct device *dev); +static int fsl_audmix_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -489,13 +492,25 @@ static int fsl_audmix_probe(struct platform_device *pdev)spin_lock_init (&priv->lock);platform_set_drvdata (pdev, priv);pm_runtime_enable (dev); +if (!pm_runtime_enabled (dev)) { + ret =fsl_audmix_runtime_resume (dev); +if (ret) + goto err_disable_pm; + } + + ret =pm_runtime_resume_and_get (dev); +if (ret <0 ) + goto err_pm_get_sync; + +/* To enable regmap cache only when runtime PM enabled */ +pm_runtime_put (dev); ret =devm_snd_soc_register_component (dev, &fsl_audmix_component, fsl_audmix_dai,ARRAY_SIZE (fsl_audmix_dai));if (ret) {dev_err (dev,"failed to register ASoC DAI\n" ); - goto err_disable_pm; + goto err_pm_get_sync; }/*
@@ -507,12 +522,15 @@ static int fsl_audmix_probe(struct platform_device *pdev)if (IS_ERR (priv->pdev)) { ret =PTR_ERR (priv->pdev);dev_err (dev,"failed to register platform: %d\n" , ret); - goto err_disable_pm; + goto err_pm_get_sync; } }return 0 ; +err_pm_get_sync: +if (!pm_runtime_status_suspended (dev)) +fsl_audmix_runtime_suspend (dev); err_disable_pm:pm_runtime_disable (dev);return ret;
@@ -523,6 +541,8 @@ static void fsl_audmix_remove(struct platform_device *pdev)struct fsl_audmix *priv =dev_get_drvdata (&pdev->dev);pm_runtime_disable (&pdev->dev); +if (!pm_runtime_status_suspended (&pdev->dev)) +fsl_audmix_runtime_suspend (&pdev->dev);if (priv->pdev)platform_device_unregister (priv->pdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 584/1424 clk: hisilicon: reset: Use devm_kzalloc to initialize hisi_reset_controller
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Min zhang <[email protected]>
[ Upstream commit a8036f4591542de4b38ec81d3e2ba47bc0b2652b ]
Using devm_kmalloc() does not zero-initialize the allocated structure. Uninitialized members in struct hisi_reset_controller may contain garbage data, which can cause reset_controller_register() to fail unexpectedly.
Replace devm_kmalloc() with devm_kzalloc() to ensure all structure fields are properly zero-initialized.
--- drivers/clk/hisilicon/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/hisilicon/reset.c +1 -1
@@ -91,7 +91,7 @@ struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev) {struct hisi_reset_controller *rstc; - rstc =devm_kmalloc (&pdev->dev,sizeof (*rstc),GFP_KERNEL ); + rstc =devm_kzalloc (&pdev->dev,sizeof (*rstc),GFP_KERNEL );if (!rstc)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 585/1424 ARM: imx: fix device_node refcount leak in imx_src_init()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weigang He <[email protected]>
[ Upstream commit 936407c3563ac745cbbb9953c0cf2472128a22f4 ]
imx_src_init() obtains a device_node reference via of_find_compatible_node() matching "fsl,imx51-src" and uses it only to call of_iomap(). It never releases that reference: on the success path the function returns at the end without of_node_put(np), leaking one device_node refcount on every boot of an i.MX5/6 platform.
Release the reference right after of_iomap(). of_iomap() maps the node's registers but does not retain a reference to the device_node, so the node can be put once the mapping is done. The early return on a NULL np needs no put.
Found by static analysis tool CodeQL.
--- arch/arm/mach-imx/src.c | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-imx/src.c +1 -0
@@ -171,6 +171,7 @@ void __init imx_src_init(void)if (!np)return ; src_base =of_iomap (np,0 ); +of_node_put (np);WARN_ON (!src_base);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 586/1424 ARM: imx: fix device_node refcount leaks in imx7_src_init()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weigang He <[email protected]>
[ Upstream commit 3de939b2ac843d56d88e2ab1e1b1f667cba9e1d4 ]
imx7_src_init() obtains two device_node references via of_find_compatible_node() - one for "fsl,imx7d-src" and one for "fsl,imx7d-gpc" - reusing the same np variable, but never calls of_node_put() on either. On every i.MX7D boot up to two device_node refcounts are leaked:
- The "fsl,imx7d-src" node is leaked both when of_iomap() fails (the early return after the mapping) and when it succeeds, because np is then overwritten by the second of_find_compatible_node() call without releasing the prior reference.
- The "fsl,imx7d-gpc" node is leaked on every path leaving the function after it is acquired.
Release each reference immediately after of_iomap() consumes the node. of_iomap() maps the node's registers but does not retain a reference to the device_node, so it is safe to put the node once mapped; this also drops the first reference before np is reused for the second lookup.
Found by static analysis tool CodeQL.
--- arch/arm/mach-imx/src.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/mach-imx/src.c +2 -0
@@ -196,6 +196,7 @@ void __init imx7_src_init(void)return ; src_base =of_iomap (np,0 ); +of_node_put (np);if (!src_base)return ;
@@ -204,6 +205,7 @@ void __init imx7_src_init(void)return ; gpc_base =of_iomap (np,0 ); +of_node_put (np);if (!gpc_base)return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 587/1424 clk: imx: scu: drop redundant init.ops variable assignment
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Masney <[email protected]>
[ Upstream commit 5f2db1ce201216e81333ecc2ab51494410b2fe0d ]
The init.ops is assigned a default value, however right below it is an if, else if, and else where all of them also assign a value to init.ops. Drop the redundant init.ops assignment at the top.
--- drivers/clk/imx/clk-scu.c | 1 - 1 file changed, 1 deletion(-)
drivers/clk/imx/clk-scu.c +0 -1
@@ -481,7 +481,6 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, clk->clk_type = clk_type; init.name = name; - init.ops = &clk_scu_ops;if (rsrc_id ==IMX_SC_R_A35 || rsrc_id ==IMX_SC_R_A53 || rsrc_id ==IMX_SC_R_A72 ) init.ops = &clk_scu_cpu_ops;else if (rsrc_id ==IMX_SC_R_PI_0_PLL )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 588/1424 drm/lima: call drm_mm_init() with a valid allocation range
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henrik Grimler <[email protected]>
[ Upstream commit 3b3bce4a692ac60d9f4a341e6b597dd1fd0a28f9 ]
lima_vm_create() is currently run before va_start and va_end are set up, meaning they are both 0. lima_vm_create() runs drm_mm_init() with them as arguments for the allocator, and if DRM_DEBUG_MM is enabled the DRM_MM_BUG_ON check in drm_mm_init then fires, as seen here on exynos4412-odroid-u2:
[ 1.736297] ------------[ cut here ]------------ [ 1.740370] kernel BUG at drivers/gpu/drm/drm_mm.c:931! [ 1.745574] Internal error: Oops - BUG: 0 [#1] SMP ARM [ 1.750697] Modules linked in: [ 1.753734] CPU: 0 UID: 0 PID: 41 Comm: kworker/u16:1 Not tainted 7.0.10-postmarketos-exynos4 #11 PREEMPT [ 1.763372] Hardware name: Samsung Exynos (Flattened Device Tree) [ 1.769446] Workqueue: events_unbound deferred_probe_work_func [ 1.775261] PC is at drm_mm_init+0x9c/0xa4 [ 1.779339] LR is at lima_vm_create+0x144/0x17c
[ ... ]
Fix the issue by moving the lima_vm_create() call after va_start and va_end are set up.
--- drivers/gpu/drm/lima/lima_device.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/lima/lima_device.c +6 -6
@@ -368,12 +368,6 @@ int lima_device_init(struct lima_device *ldev)if (err) goto err_out0; - ldev->empty_vm =lima_vm_create (ldev); -if (!ldev->empty_vm) { - err = -ENOMEM ; - goto err_out1; - } - ldev->va_start =0 ;if (ldev->id == lima_gpu_mali450) { ldev->va_end =LIMA_VA_RESERVE_START ;
@@ -387,6 +381,12 @@ int lima_device_init(struct lima_device *ldev) }else ldev->va_end =LIMA_VA_RESERVE_END ; + ldev->empty_vm =lima_vm_create (ldev); +if (!ldev->empty_vm) { + err = -ENOMEM ; + goto err_out1; + } + ldev->iomem =devm_platform_ioremap_resource (pdev,0 );if (IS_ERR (ldev->iomem)) {dev_err (ldev->dev,"fail to ioremap iomem\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 589/1424 mm/mm_init: fix incorrect node_spanned_pages
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Yang <[email protected]>
[ Upstream commit 7783dcd79ae9c4aa48bc47bd4275772445dc4b2a ]
Current node_spanned_pages is got as a summation of all zone's spanned page in calculate_node_totalpages(). Generally this is good, but if we use kernelcore=mirror, it is would be wrong.
Without kernelcore=mirror:
The test machine has below memory layout:
memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x0
memory[0x1] [0x0000000000100000-0x00000000bffdefff], 0x00000000bfedf000 bytes on node 0 flags: 0x0
memory[0x2] [0x0000000100000000-0x00000001bfffffff], 0x00000000c0000000 bytes on node 0 flags: 0x0
And the Zone range is:
DMA [mem 0x0000000000001000-0x0000000000ffffff]
DMA32 [mem 0x0000000001000000-0x00000000ffffffff]
Normal [mem 0x0000000100000000-0x00000001bfffffff]
Then we see, with spanned_pages printed:
On node 0 spanned_pages: 1835007 totalpages: 1572733With kernelcore=mirror:
The test machine has below memory layout:
memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x2
memory[0x1] [0x0000000000100000-0x00000000bffdefff], 0x00000000bfedf000 bytes on node 0 flags: 0x2
memory[0x2] [0x0000000100000000-0x000000013fffffff], 0x0000000040000000 bytes on node 0 flags: 0x2
memory[0x3] [0x0000000140000000-0x00000001bfffffff], 0x0000000080000000 bytes on node 0 flags: 0x0
And the Zone range is:
DMA [mem 0x0000000000001000-0x0000000000ffffff]
DMA32 [mem 0x0000000001000000-0x00000000ffffffff]
Normal [mem 0x0000000100000000-0x00000001bfffffff]
Device empty
Movable zone start for each node
Node 0: 0x0000000140000000
Then we see, with spanned_pages printed:
On node 0 spanned_pages: 2359295 totalpages: 1572733The total range of memory on node 0 doesn't change, but the spanned_pages becomes much larger.
The reason is when kernelcore=mirror is specified, the range of Zone Normal and Zone Movable would overlap. So the overlapped range would be calculated twice.
A wrong node_spanned_pages would effect defer_init(), since each zone_end_pfn is less than pgdat_end_pfn().
As we already passed in node_start_pfn and node_end_pfn, fix this by get it from (node_start_pfn - node_end_pfn) directly.
--- mm/mm_init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
mm/mm_init.c +2 -3
@@ -1279,7 +1279,7 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat,unsigned long node_start_pfn, unsigned long node_end_pfn) { - unsigned long realtotalpages = 0, totalpages = 0; + unsigned long realtotalpages = 0;enum zone_type i;for (i =0 ; i <MAX_NR_ZONES ; i++) {
@@ -1309,11 +1309,10 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat, zone->present_early_pages = real_size;#endif - totalpages += spanned; realtotalpages += real_size; } - pgdat->node_spanned_pages = totalpages; + pgdat->node_spanned_pages = node_end_pfn - node_start_pfn; pgdat->node_present_pages = realtotalpages;pr_debug ("On node %d totalpages: %lu\n" , pgdat->node_id, realtotalpages); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 590/1424 sched/fair: Fix overflow in update_tg_cfs_runnable()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen, Yu C <[email protected]>
[ Upstream commit 4f166adb5cb0525d9e32d45729fd8f28c80acbee ]
A divide-by-zero crash is observed when running hackbench:
[14697.488452] CPU: 112 UID: 0 PID: 124791 Comm: hackbench Not tainted 7.1.0-rc2+ [14697.492627] RIP: 0010:propagate_entity_load_avg+0x35f/0x3e0 [14697.506799] <TASK> [14697.507411] __dequeue_task+0x2b4/0xc70 [14697.508677] dequeue_task_fair+0x36/0x370 [14697.509047] dequeue_task+0x101/0x2f0 [14697.509426] __schedule+0x1b1/0x1a00 [14697.510868] anon_pipe_read+0x3da/0x450 [14697.511400] vfs_read+0x361/0x390 [14697.512053] __x64_sys_read+0x19/0x30
The divide-by-zero happens here:
if (scale_load_down(gcfs_rq->load.weight)) {
load_sum = div_u64(gcfs_rq->avg.load_sum,
scale_load_down(gcfs_rq->load.weight));
}gcfs_rq->load.weight is an insane large value and is truncated to the lower 32 bits by div_u64, which happen to be 0.
Using AI for investigation, the cause is a u32 overflow in update_tg_cfs_runnable(), and flat pickup became a victim when using tg_tasks():
u32 new_sum, divider;
...
new_sum = se->avg.runnable_avg * divider; <-- boom
The following sequence shows how this triggers the crash:
propagate_entity_load_avg()
update_tg_cfs_runnable() # u32 overflow corrupts runnable_sum
__update_load_avg_cfs_rq()
___update_load_avg() # computes insane runnable_avg
update_tg_load_avg() # propagates to tg->runnable_avg
update_cfs_group()
calc_concur_shares()
tg_tasks() # long-to-int truncation, negative nr
reweight_entity() # corrupted se->load.weight
update_load_add() # corrupted cfs_rq->load.weight propagate_entity_load_avg()
update_tg_cfs_load()
div_u64() # divide-by-zero
Fix by widening new_sum from u32 to u64 (no need to force tg_tasks() to return unsigned long after this fix)
--- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/sched/fair.c +3 -2
@@ -4312,7 +4312,8 @@ static inline void update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq) { long delta_sum, delta_avg = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg; -u32 new_sum, divider; +u64 new_sum; +u32 divider;/* Nothing to update */ if (!delta_avg)
@@ -4326,7 +4327,7 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf/* Set new sched_entity's runnable */ se->avg.runnable_avg = gcfs_rq->avg.runnable_avg; - new_sum = se->avg.runnable_avg * divider; + new_sum = (u64 )se->avg.runnable_avg * divider; delta_sum = (long )new_sum - (long )se->avg.runnable_sum; se->avg.runnable_sum = new_sum;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 591/1424 perf/x86/intel/uncore: Keep PCI PMUs working when MMIO/MSR setup fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zide Chen <[email protected]>
[ Upstream commit 3012af7df3430788eddd30b3c6654d0a0a5f06c6 ]
uncore_event_cpu_online() returns -ENOMEM early when both the MSR and MMIO box allocations fail. This also aborts PCI uncore setup, even though PCI PMUs are independent of the MSR/MMIO paths.
Remove the early return so PCI uncore setup always runs regardless of whether MSR or MMIO box allocation succeeds.
--- arch/x86/events/intel/uncore.c | 2 -- 1 file changed, 2 deletions(-)
arch/x86/events/intel/uncore.c +0 -2
@@ -1607,8 +1607,6 @@ static int uncore_event_cpu_online(unsigned int cpu) die =topology_logical_die_id (cpu); msr_ret =uncore_box_ref (uncore_msr_uncores, die, cpu); mmio_ret =uncore_box_ref (uncore_mmio_uncores, die, cpu); -if (msr_ret && mmio_ret) -return -ENOMEM ;/* * Check if there is an online cpu in the package
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 592/1424 pinctrl: bcm2835: Dont remove an unregistered GPIO chip
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel McCarthy <[email protected]>
[ Upstream commit 32711f77db0641e57fd96fdc013bf1286b9f2514 ]
If the devm_pinctrl_register() function fails, bcm2835_pinctrl_probe() calls gpiochip_remove() before gpiochip_add_data() has registered the GPIO chip.
This means that upon failure the gpio_chip.gpiodev
is NULL resulting in a null pointer dereference
inside the gpiochip_remove() function.
Remove the unnecessary function call to gpiochip_remove(). No GPIO cleanup is required because the GPIO chip has not yet been registered. Without this change there is potential for a kernel panic upon registration failure
--- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 - 1 file changed, 1 deletion(-)
drivers/pinctrl/bcm/pinctrl-bcm2835.c +0 -1
@@ -1280,7 +1280,6 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) pc->pctl_desc = *pdata->pctl_desc; pc->pctl_dev =devm_pinctrl_register (dev, &pc->pctl_desc, pc);if (IS_ERR (pc->pctl_dev)) { -gpiochip_remove (&pc->gpio_chip);return PTR_ERR (pc->pctl_dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 593/1424 media: keymaps: Remove obsolete RC_MAP_RC5_TV keymap define
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Young <[email protected]>
[ Upstream commit 5370facb7b4461166a4610d456fefeb92ef50a82 ]
Since commit 206241069ecf ("[media] rc/keymaps: Remove the obsolete rc-rc5-tv keymap"), the rc-rc5-tv keymap is no longer in the tree.
--- include/media/rc-map.h | 1 - 1 file changed, 1 deletion(-)
include/media/rc-map.h +0 -1
@@ -308,7 +308,6 @@ struct rc_map *rc_map_get(const char *name);#define RC_MAP_PROTEUS_2309 "rc-proteus-2309"#define RC_MAP_PURPLETV "rc-purpletv"#define RC_MAP_PV951 "rc-pv951" -#define RC_MAP_RC5_TV "rc-rc5-tv"#define RC_MAP_RC6_MCE "rc-rc6-mce"#define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys"#define RC_MAP_REDDO "rc-reddo"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 594/1424 media: keymaps: Remove obsolete RC_MAP_HAUPPAUGE_NEW keymap define
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Young <[email protected]>
[ Upstream commit 6e5deb2923b0d1b73c77a1a77c30b0da43d9e022 ]
Since commit af86ce79f020 ("[media] remove the old RC_MAP_HAUPPAUGE_NEW RC map"), the RC_MAP_HAUPPAUGE_NEW define is no longer used.
--- include/media/rc-map.h | 1 - 1 file changed, 1 deletion(-)
include/media/rc-map.h +0 -1
@@ -262,7 +262,6 @@ struct rc_map *rc_map_get(const char *name);#define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce"#define RC_MAP_GOTVIEW7135 "rc-gotview7135"#define RC_MAP_HAUPPAUGE "rc-hauppauge" -#define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge"#define RC_MAP_HISI_POPLAR "rc-hisi-poplar"#define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo"#define RC_MAP_IMON_MCE "rc-imon-mce"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 595/1424 perf test: Simplify metric value validation test final report
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weilin Wang <[email protected]>
[ Upstream commit 8f95b29c73e181274759c3f9483ba7f875447e3c ]
The original test report was too complicated to read with information that not really useful. This new update simplify the report which should largely improve the readibility.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- .../tests/shell/lib/perf_metric_validation.py | 231 ++++++++++-------- tools/perf/tests/shell/stat_metrics_values.sh | 4 +- 2 files changed, 127 insertions(+), 108 deletions(-)
tools/perf/tests/shell/lib/perf_metric_validation.py +124 -107
@@ -1,4 +1,4 @@ -#SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: GPL-2.0 import re import csv import json
@@ -6,36 +6,61 @@ import argparse from pathlib import Path import subprocess + +class TestError: + def __init__(self, metric: list[str], wl: str, value: list[float], low: float, up=float('nan'), description=str()): + self.metric: list = metric # multiple metrics in relationship type tests + self.workloads = [wl] # multiple workloads possible + self.collectedValue: list = value + self.valueLowBound = low + self.valueUpBound = up + self.description = description + + def __repr__(self) -> str: + if len(self.metric) > 1: + return "\nMetric Relationship Error: \tThe collected value of metric {0}\n\ + \tis {1} in workload(s): {2} \n\ + \tbut expected value range is [{3}, {4}]\n\ + \tRelationship rule description: \'{5}\'".format(self.metric, self.collectedValue, self.workloads, + self.valueLowBound, self.valueUpBound, self.description) + elif len(self.collectedValue) == 0: + return "\nNo Metric Value Error: \tMetric {0} returns with no value \n\ + \tworkload(s): {1}".format(self.metric, self.workloads) + else: + return "\nWrong Metric Value Error: \tThe collected value of metric {0}\n\ + \tis {1} in workload(s): {2}\n\ + \tbut expected value range is [{3}, {4}]"\ + .format(self.metric, self.collectedValue, self.workloads, + self.valueLowBound, self.valueUpBound) + + class Validator: def __init__(self, rulefname, reportfname='', t=5, debug=False, datafname='', fullrulefname='', workload='true', metrics=''): self.rulefname = rulefname self.reportfname = reportfname self.rules = None - self.collectlist:str = metrics + self.collectlist: str = metrics self.metrics = self.__set_metrics(metrics) self.skiplist = set() self.tolerance = t self.workloads = [x for x in workload.split(",") if x] - self.wlidx = 0 # idx of current workloads - self.allresults = dict() # metric results of all workload - self.allignoremetrics = dict() # metrics with no results or negative results - self.allfailtests = dict() + self.wlidx = 0 # idx of current workloads + self.allresults = dict() # metric results of all workload self.alltotalcnt = dict() self.allpassedcnt = dict() - self.allerrlist = dict() - self.results = dict() # metric results of current workload + self.results = dict() # metric results of current workload # vars for test pass/failure statistics - self.ignoremetrics= set() # metrics with no results or negative results, neg result counts as a failed test - self.failtests = dict() + # metrics with no results or negative results, neg result counts failed tests + self.ignoremetrics = set() self.totalcnt = 0 self.passedcnt = 0 # vars for errors self.errlist = list() # vars for Rule Generator - self.pctgmetrics = set() # Percentage rule + self.pctgmetrics = set() # Percentage rule # vars for debug self.datafname = datafname
@@ -69,10 +94,10 @@ class Validator: ensure_ascii=True, indent=4) - def get_results(self, idx:int = 0): + def get_results(self, idx: int = 0): return self.results[idx] - def get_bounds(self, lb, ub, error, alias={}, ridx:int = 0) -> list: + def get_bounds(self, lb, ub, error, alias={}, ridx: int = 0) -> list: """ Get bounds and tolerance from lb, ub, and error. If missing lb, use 0.0; missing ub, use float('inf); missing error, use self.tolerance.
@@ -85,7 +110,7 @@ class Validator: tolerance, denormalized base on upper bound value """ # init ubv and lbv to invalid values - def get_bound_value (bound, initval, ridx): + def get_bound_value(bound, initval, ridx): val = initval if isinstance(bound, int) or isinstance(bound, float): val = bound
@@ -113,10 +138,10 @@ class Validator: return lbv, ubv, denormerr - def get_value(self, name:str, ridx:int = 0) -> list: + def get_value(self, name: str, ridx: int = 0) -> list: """ Get value of the metric from self.results. - If result of this metric is not provided, the metric name will be added into self.ignoremetics and self.errlist. + If result of this metric is not provided, the metric name will be added into self.ignoremetics. All future test(s) on this metric will fail. @param name: name of the metric
@@ -142,7 +167,7 @@ class Validator: Check if metrics value are non-negative. One metric is counted as one test. Failure: when metric value is negative or not provided. - Metrics with negative value will be added into the self.failtests['PositiveValueTest'] and self.ignoremetrics. + Metrics with negative value will be added into self.ignoremetrics. """ negmetric = dict() pcnt = 0
@@ -155,25 +180,27 @@ class Validator: else: pcnt += 1 tcnt += 1 + # The first round collect_perf() run these metrics with simple workload + # "true". We give metrics a second chance with a longer workload if less + # than 20 metrics failed positive test. if len(rerun) > 0 and len(rerun) < 20: second_results = dict() self.second_test(rerun, second_results) for name, val in second_results.items(): - if name not in negmetric: continue + if name not in negmetric: + continue if val >= 0: del negmetric[name] pcnt += 1 - self.failtests['PositiveValueTest']['Total Tests'] = tcnt - self.failtests['PositiveValueTest']['Passed Tests'] = pcnt if len(negmetric.keys()): self.ignoremetrics.update(negmetric.keys()) - negmessage = ["{0}(={1:.4f})".format(name, val) for name, val in negmetric.items()] - self.failtests['PositiveValueTest']['Failed Tests'].append({'NegativeValue': negmessage}) + self.errlist.extend( + [TestError([m], self.workloads[self.wlidx], negmetric[m], 0) for m in negmetric.keys()]) return - def evaluate_formula(self, formula:str, alias:dict, ridx:int = 0): + def evaluate_formula(self, formula: str, alias: dict, ridx: int = 0): """ Evaluate the value of formula.
@@ -187,10 +214,11 @@ class Validator: sign = "+" f = str() - #TODO: support parenthesis? + # TODO: support parenthesis? for i in range(len(formula)): if i+1 == len(formula) or formula[i] in ('+', '-', '*', '/'): - s = alias[formula[b:i]] if i+1 < len(formula) else alias[formula[b:]] + s = alias[formula[b:i]] if i + \ + 1 < len(formula) else alias[formula[b:]] v = self.get_value(s, ridx) if not v: errs.append(s)
@@ -228,49 +256,49 @@ class Validator: alias = dict() for m in rule['Metrics']: alias[m['Alias']] = m['Name'] - lbv, ubv, t = self.get_bounds(rule['RangeLower'], rule['RangeUpper'], rule['ErrorThreshold'], alias, ridx=rule['RuleIndex']) - val, f = self.evaluate_formula(rule['Formula'], alias, ridx=rule['RuleIndex']) + lbv, ubv, t = self.get_bounds( + rule['RangeLower'], rule['RangeUpper'], rule['ErrorThreshold'], alias, ridx=rule['RuleIndex']) + val, f = self.evaluate_formula( + rule['Formula'], alias, ridx=rule['RuleIndex']) + + lb = rule['RangeLower'] + ub = rule['RangeUpper'] + if isinstance(lb, str): + if lb in alias: + lb = alias[lb] + if isinstance(ub, str): + if ub in alias: + ub = alias[ub] + if val == -1: - self.failtests['RelationshipTest']['Failed Tests'].append({'RuleIndex': rule['RuleIndex'], 'Description':f}) + self.errlist.append(TestError([m['Name'] for m in rule['Metrics']], self.workloads[self.wlidx], [], + lb, ub, rule['Description'])) elif not self.check_bound(val, lbv, ubv, t): - lb = rule['RangeLower'] - ub = rule['RangeUpper'] - if isinstance(lb, str): - if lb in alias: - lb = alias[lb] - if isinstance(ub, str): - if ub in alias: - ub = alias[ub] - self.failtests['RelationshipTest']['Failed Tests'].append({'RuleIndex': rule['RuleIndex'], 'Formula':f, - 'RangeLower': lb, 'LowerBoundValue': self.get_value(lb), - 'RangeUpper': ub, 'UpperBoundValue':self.get_value(ub), - 'ErrorThreshold': t, 'CollectedValue': val}) + self.errlist.append(TestError([m['Name'] for m in rule['Metrics']], self.workloads[self.wlidx], [val], + lb, ub, rule['Description'])) else: self.passedcnt += 1 - self.failtests['RelationshipTest']['Passed Tests'] += 1 self.totalcnt += 1 - self.failtests['RelationshipTest']['Total Tests'] += 1 return - # Single Metric Test - def single_test(self, rule:dict): + def single_test(self, rule: dict): """ Validate if the metrics are in the required value range. eg. lower_bound <= metrics_value <= upper_bound One metric is counted as one test in this type of test. One rule may include one or more metrics. Failure: when the metric value not provided or the value is outside the bounds. - This test updates self.total_cnt and records failed tests in self.failtest['SingleMetricTest']. + This test updates self.total_cnt. @param rule: dict with metrics to validate and the value range requirement """ - lbv, ubv, t = self.get_bounds(rule['RangeLower'], rule['RangeUpper'], rule['ErrorThreshold']) + lbv, ubv, t = self.get_bounds( + rule['RangeLower'], rule['RangeUpper'], rule['ErrorThreshold']) metrics = rule['Metrics'] passcnt = 0 totalcnt = 0 - faillist = list() failures = dict() rerun = list() for m in metrics:
@@ -286,25 +314,20 @@ class Validator: second_results = dict() self.second_test(rerun, second_results) for name, val in second_results.items(): - if name not in failures: continue + if name not in failures: + continue if self.check_bound(val, lbv, ubv, t): passcnt += 1 del failures[name] else: - failures[name] = val + failures[name] = [val] self.results[0][name] = val self.totalcnt += totalcnt self.passedcnt += passcnt - self.failtests['SingleMetricTest']['Total Tests'] += totalcnt - self.failtests['SingleMetricTest']['Passed Tests'] += passcnt if len(failures.keys()) != 0: - faillist = [{'MetricName':name, 'CollectedValue':val} for name, val in failures.items()] - self.failtests['SingleMetricTest']['Failed Tests'].append({'RuleIndex':rule['RuleIndex'], - 'RangeLower': rule['RangeLower'], - 'RangeUpper': rule['RangeUpper'], - 'ErrorThreshold':rule['ErrorThreshold'], - 'Failure':faillist}) + self.errlist.extend([TestError([name], self.workloads[self.wlidx], val, + rule['RangeLower'], rule['RangeUpper']) for name, val in failures.items()]) return
@@ -312,19 +335,11 @@ class Validator: """ Create final report and write into a JSON file. """ - alldata = list() - for i in range(0, len(self.workloads)): - reportstas = {"Total Rule Count": self.alltotalcnt[i], "Passed Rule Count": self.allpassedcnt[i]} - data = {"Metric Validation Statistics": reportstas, "Tests in Category": self.allfailtests[i], - "Errors":self.allerrlist[i]} - alldata.append({"Workload": self.workloads[i], "Report": data}) - - json_str = json.dumps(alldata, indent=4) - print("Test validation finished. Final report: ") - print(json_str) + print(self.errlist) if self.debug: - allres = [{"Workload": self.workloads[i], "Results": self.allresults[i]} for i in range(0, len(self.workloads))] + allres = [{"Workload": self.workloads[i], "Results": self.allresults[i]} + for i in range(0, len(self.workloads))] self.json_dump(allres, self.datafname) def check_rule(self, testtype, metric_list):
@@ -342,13 +357,13 @@ class Validator: return True # Start of Collector and Converter - def convert(self, data: list, metricvalues:dict): + def convert(self, data: list, metricvalues: dict): """ Convert collected metric data from the -j output to dict of {metric_name:value}. """ for json_string in data: try: - result =json.loads(json_string) + result = json.loads(json_string) if "metric-unit" in result and result["metric-unit"] != "(null)" and result["metric-unit"] != "": name = result["metric-unit"].split(" ")[1] if len(result["metric-unit"].split(" ")) > 1 \ else result["metric-unit"]
@@ -365,9 +380,10 @@ class Validator: print(" ".join(command)) cmd = subprocess.run(command, stderr=subprocess.PIPE, encoding='utf-8') data = [x+'}' for x in cmd.stderr.split('}\n') if x] + if data[0][0] != '{': + data[0] = data[0][data[0].find('{'):] return data - def collect_perf(self, workload: str): """ Collect metric data with "perf stat -M" on given workload with -a and -j.
@@ -385,14 +401,18 @@ class Validator: if rule["TestType"] == "RelationshipTest": metrics = [m["Name"] for m in rule["Metrics"]] if not any(m not in collectlist[0] for m in metrics): - collectlist[rule["RuleIndex"]] = [",".join(list(set(metrics)))] + collectlist[rule["RuleIndex"]] = [ + ",".join(list(set(metrics)))] for idx, metrics in collectlist.items(): - if idx == 0: wl = "true" - else: wl = workload + if idx == 0: + wl = "true" + else: + wl = workload for metric in metrics: data = self._run_perf(metric, wl) - if idx not in self.results: self.results[idx] = dict() + if idx not in self.results: + self.results[idx] = dict() self.convert(data, self.results[idx]) return
@@ -412,7 +432,8 @@ class Validator: 2) create metric name list """ command = ['perf', 'list', '-j', '--details', 'metrics'] - cmd = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8') + cmd = subprocess.run(command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, encoding='utf-8') try: data = json.loads(cmd.stdout) for m in data:
@@ -453,12 +474,12 @@ class Validator: rules = data['RelationshipRules'] self.skiplist = set([name.lower() for name in data['SkipList']]) self.rules = self.remove_unsupported_rules(rules) - pctgrule = {'RuleIndex':0, - 'TestType':'SingleMetricTest', - 'RangeLower':'0', + pctgrule = {'RuleIndex': 0, + 'TestType': 'SingleMetricTest', + 'RangeLower': '0', 'RangeUpper': '100', 'ErrorThreshold': self.tolerance, - 'Description':'Metrics in percent unit have value with in [0, 100]', + 'Description': 'Metrics in percent unit have value with in [0, 100]', 'Metrics': [{'Name': m.lower()} for m in self.pctgmetrics]} self.rules.append(pctgrule)
@@ -469,8 +490,9 @@ class Validator: idx += 1 if self.debug: - #TODO: need to test and generate file name correctly - data = {'RelationshipRules':self.rules, 'SupportedMetrics': [{"MetricName": name} for name in self.metrics]} + # TODO: need to test and generate file name correctly + data = {'RelationshipRules': self.rules, 'SupportedMetrics': [ + {"MetricName": name} for name in self.metrics]} self.json_dump(data, self.fullrulefname) return
@@ -482,20 +504,17 @@ class Validator: @param key: key to the dictionaries (index of self.workloads). ''' self.allresults[key] = self.results - self.allignoremetrics[key] = self.ignoremetrics - self.allfailtests[key] = self.failtests self.alltotalcnt[key] = self.totalcnt self.allpassedcnt[key] = self.passedcnt - self.allerrlist[key] = self.errlist - #Initialize data structures before data validation of each workload + # Initialize data structures before data validation of each workload def _init_data(self): - testtypes = ['PositiveValueTest', 'RelationshipTest', 'SingleMetricTest'] + testtypes = ['PositiveValueTest', + 'RelationshipTest', 'SingleMetricTest'] self.results = dict() - self.ignoremetrics= set() + self.ignoremetrics = set() self.errlist = list() - self.failtests = {k:{'Total Tests':0, 'Passed Tests':0, 'Failed Tests':[]} for k in testtypes} self.totalcnt = 0 self.passedcnt = 0
@@ -525,32 +544,33 @@ class Validator: testtype = r['TestType'] if not self.check_rule(testtype, r['Metrics']): continue - if testtype == 'RelationshipTest': + if testtype == 'RelationshipTest': self.relationship_test(r) elif testtype == 'SingleMetricTest': self.single_test(r) else: print("Unsupported Test Type: ", testtype) - self.errlist.append("Unsupported Test Type from rule: " + r['RuleIndex']) - self._storewldata(i) print("Workload: ", self.workloads[i]) - print("Total metrics collected: ", self.failtests['PositiveValueTest']['Total Tests']) - print("Non-negative metric count: ", self.failtests['PositiveValueTest']['Passed Tests']) print("Total Test Count: ", self.totalcnt) print("Passed Test Count: ", self.passedcnt) - + self._storewldata(i) self.create_report() - return sum(self.alltotalcnt.values()) != sum(self.allpassedcnt.values()) + return len(self.errlist) > 0 # End of Class Validator def main() -> None: - parser = argparse.ArgumentParser(description="Launch metric value validation") - - parser.add_argument("-rule", help="Base validation rule file", required=True) - parser.add_argument("-output_dir", help="Path for validator output file, report file", required=True) - parser.add_argument("-debug", help="Debug run, save intermediate data to files", action="store_true", default=False) - parser.add_argument("-wl", help="Workload to run while data collection", default="true") + parser = argparse.ArgumentParser( + description="Launch metric value validation") + + parser.add_argument( + "-rule", help="Base validation rule file", required=True) + parser.add_argument( + "-output_dir", help="Path for validator output file, report file", required=True) + parser.add_argument("-debug", help="Debug run, save intermediate data to files", + action="store_true", default=False) + parser.add_argument( + "-wl", help="Workload to run while data collection", default="true") parser.add_argument("-m", help="Metric list to validate", default="") args = parser.parse_args() outpath = Path(args.output_dir)
@@ -559,8 +579,8 @@ def main() -> None: datafile = Path.joinpath(outpath, 'perf_data.json') validator = Validator(args.rule, reportf, debug=args.debug, - datafname=datafile, fullrulefname=fullrule, workload=args.wl, - metrics=args.m) + datafname=datafile, fullrulefname=fullrule, workload=args.wl, + metrics=args.m) ret = validator.test() return ret
@@ -569,6 +589,3 @@ def main() -> None: if __name__ == "__main__": import sys sys.exit(main()) - - -
tools/perf/tests/shell/stat_metrics_values.sh +3 -1
@@ -25,6 +25,8 @@ echo "Output will be stored in: $tmpdir" $PYTHON $pythonvalidator -rule $rulefile -output_dir $tmpdir -wl "${workload}" ret=$? rm -rf $tmpdir - +if [ $ret -ne 0 ]; then + echo "Metric validation return with erros. Please check metrics reported with errors." +fi exit $ret
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 596/1424 perf test: Update all metrics test like metricgroups test
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namhyung Kim <[email protected]>
[ Upstream commit e2cb1db7daf8b7863aeec07bb574d3fae54518e6 ]
Like in the metricgroup tests, it should check the permission first and then skip relevant failures accordingly.
Also it needs to try again with the system wide flag properly. On the second round, check if the result has the metric name because other failure cases are checked in the first round already.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 87 ++++++++++++++++------ 1 file changed, 66 insertions(+), 21 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +66 -21
@@ -2,42 +2,87 @@ # perf all metrics test # SPDX-License-Identifier: GPL-2.0 +ParanoidAndNotRoot() +{ + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + +system_wide_flag="-a" +if ParanoidAndNotRoot 0 +then + system_wide_flag="" +fi + err=0 for m in $(perf list --raw-dump metrics); do echo "Testing $m" - result=$(perf stat -M "$m" true 2>&1) - if [[ "$result" =~ ${m:0:50} ]] || [[ "$result" =~ "<not supported>" ]] + result=$(perf stat -M "$m" $system_wide_flag -- sleep 0.01 2>&1) + result_err=$? + if [[ $result_err -gt 0 ]] then - continue + if [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not supported>" ]] + then + echo "Not supported events" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + then + echo "FP issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "PMM" ]] + then + echo "Optane memory issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + fi fi - # Failed so try system wide. - result=$(perf stat -M "$m" -a sleep 0.01 2>&1) + if [[ "$result" =~ ${m:0:50} ]] then continue fi - # Failed again, possibly the workload was too small so retry with something - # longer. - result=$(perf stat -M "$m" perf bench internals synthesize 2>&1) + + # Failed, possibly the workload was too small so retry with something longer. + result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) if [[ "$result" =~ ${m:0:50} ]] then continue fi echo "Metric '$m' not printed in:" echo "$result" - if [[ "$err" != "1" ]] - then - err=2 - if [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] - then - echo "Skip, not fail, for FP issues" - elif [[ "$result" =~ "PMM" ]] - then - echo "Skip, not fail, for Optane memory issues" - else - err=1 - fi - fi + err=1 done exit "$err"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 597/1424 perf test stat_all_metrics: Ensure missing events fail test
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 08d9e883481b2c38326ed37314b1f6a1284c03d8 ]
Issue reported by Thomas Falcon and diagnosed by Kan Liang here:
https://lore.kernel.org/lkml/[email protected]/
Metrics with missing events can be erroneously skipped if they contain FP, AMX or PMM events.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
tools/perf/tests/shell/stat_all_metrics.sh +7 -1
@@ -20,7 +20,13 @@ for m in $(perf list --raw-dump metrics); do result_err=$? if [[ $result_err -gt 0 ]] then - if [[ "$result" =~ \ + if [[ "$result" =~ "Cannot resolve IDs for" ]] + then + echo "Metric contains missing events" + echo $result + err=1 # Fail + continue + elif [[ "$result" =~ \ "Access to performance monitoring and observability operations is limited" ]] then echo "Permission failure"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 598/1424 perf tests metrics: Permission related fixes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 365e02ddb65d443f1ba16af5a4ddcd638f1e7823 ]
When permissions are limited running sleep without system wide isn't a good benchmark to run to achieve samples, switch to running noploop.
Remove indent for non-success cases.
Allow skip for the not counted case.
Minor debug changes.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 118 +++++++++++---------- 1 file changed, 64 insertions(+), 54 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +64 -54
@@ -7,86 +7,96 @@ ParanoidAndNotRoot() [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] } +test_prog="sleep 0.01" system_wide_flag="-a" if ParanoidAndNotRoot 0 then system_wide_flag="" + test_prog="perf test -w noploop" fi err=0 for m in $(perf list --raw-dump metrics); do echo "Testing $m" - result=$(perf stat -M "$m" $system_wide_flag -- sleep 0.01 2>&1) + result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1) result_err=$? - if [[ $result_err -gt 0 ]] + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then - if [[ "$result" =~ "Cannot resolve IDs for" ]] - then - echo "Metric contains missing events" - echo $result - err=1 # Fail - continue - elif [[ "$result" =~ \ - "Access to performance monitoring and observability operations is limited" ]] + # No error result and metric shown. + continue + fi + if [[ "$result" =~ "Cannot resolve IDs for" ]] + then + echo "Metric contains missing events" + echo $result + err=1 # Fail + continue + elif [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] then - echo "Permission failure" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] then - echo "Permissions - need system wide mode" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "<not supported>" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not supported>" ]] + then + echo "Not supported events" + echo $result + if [[ $err -eq 0 ]] then - echo "Not supported events" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not counted>" ]] + then + echo "Not counted events" + echo $result + if [[ $err -eq 0 ]] then - echo "FP issues" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "PMM" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + then + echo "FP issues" + echo $result + if [[ $err -eq 0 ]] then - echo "Optane memory issues" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue + err=2 # Skip fi - fi - - if [[ "$result" =~ ${m:0:50} ]] + continue + elif [[ "$result" =~ "PMM" ]] then + echo "Optane memory issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi continue fi # Failed, possibly the workload was too small so retry with something longer. result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) - if [[ "$result" =~ ${m:0:50} ]] + result_err=$? + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then + # No error result and metric shown. continue fi - echo "Metric '$m' not printed in:" + echo "Metric '$m' has non-zero error '$result_err' or not printed in:" echo "$result" err=1 done
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 599/1424 perf test metrics: Update all metrics for possibly failing default metrics
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 91c1949d768520d9befa7761eb97c3826997da25 ]
Default metrics may use unsupported events and be ignored. These metrics shouldn't cause metric testing to fail.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/tests/shell/stat_all_metrics.sh +6 -1
@@ -25,8 +25,13 @@ for m in $(perf list --raw-dump metrics); do # No error result and metric shown. continue fi - if [[ "$result" =~ "Cannot resolve IDs for" ]] + if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]] then + if [[ "$m" == @(l1_prefetch_miss_rate|stalled_cycles_per_instruction) ]] + then + # Default metrics that may use unsupported events. + continue + fi echo "Metric contains missing events" echo $result err=1 # Fail
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 600/1424 perf test all metrics: Fully ignore Default metric failures
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 41b67ab3d2f5be9d0b6e5ba9cbec97c820fc50e8 ]
Determine if a metric is default from perf list --raw-dump $m eg:
``` $ perf list --raw-dump l1_prefetch_miss_rate Default4 l1_prefetch_miss_rate ```
If a metric has "not supported" or "no supported events" then ignore these failures for default metrics. Tidy up the skip/fail messages in the output to make them easier to spot/read.
``` $ perf list -vv "all metrics" ... Testing llc_miss_rate [Ignored llc_miss_rate] failed but as a Default metric this can be expected Error: No supported events found. The LLC-loads event is not supported. ... ```
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +17 -10
@@ -27,19 +27,20 @@ for m in $(perf list --raw-dump metrics); do fi if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]] then - if [[ "$m" == @(l1_prefetch_miss_rate|stalled_cycles_per_instruction) ]] + if [[ $(perf list --raw-dump $m) == "Default"* ]] then - # Default metrics that may use unsupported events. + echo "[Ignored $m] failed but as a Default metric this can be expected" + echo $result continue fi - echo "Metric contains missing events" + echo "[Failed $m] Metric contains missing events" echo $result err=1 # Fail continue elif [[ "$result" =~ \ "Access to performance monitoring and observability operations is limited" ]] then - echo "Permission failure" + echo "[Skipped $m] Permission failure" echo $result if [[ $err -eq 0 ]] then
@@ -48,7 +49,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] then - echo "Permissions - need system wide mode" + echo "[Skipped $m] Permissions - need system wide mode" echo $result if [[ $err -eq 0 ]] then
@@ -57,7 +58,13 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "<not supported>" ]] then - echo "Not supported events" + if [[ $(perf list --raw-dump $m) == "Default"* ]] + then + echo "[Ignored $m] failed but as a Default metric this can be expected" + echo $result + continue + fi + echo "[Skipped $m] Not supported events" echo $result if [[ $err -eq 0 ]] then
@@ -66,7 +73,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "<not counted>" ]] then - echo "Not counted events" + echo "[Skipped $m] Not counted events" echo $result if [[ $err -eq 0 ]] then
@@ -75,7 +82,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] then - echo "FP issues" + echo "[Skipped $m] FP issues" echo $result if [[ $err -eq 0 ]] then
@@ -84,7 +91,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "PMM" ]] then - echo "Optane memory issues" + echo "[Skipped $m] Optane memory issues" echo $result if [[ $err -eq 0 ]] then
@@ -101,7 +108,7 @@ for m in $(perf list --raw-dump metrics); do # No error result and metric shown. continue fi - echo "Metric '$m' has non-zero error '$result_err' or not printed in:" + echo "[Failed $m] has non-zero error '$result_err' or not printed in:" echo "$result" err=1 done
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 601/1424 perf test: Do not skip when some metrics tests succeeded
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namhyung Kim <[email protected]>
[ Upstream commit 1c89bc1b95fa9058f3e7cd37f1142939261417d5 ]
I think the return value of SKIP (2) should be used when it skipped the entire test suite rather than a few of them. While the FAIL should be reserved if any of test failed.
$ perf test -vv 110 110: perf all metrics test: --- start --- test child forked, pid 2496399 Testing tma_core_bound Testing tma_info_core_ilp Testing tma_info_memory_l2mpki Testing tma_memory_bound Testing tma_bottleneck_irregular_overhead Testing tma_bottleneck_mispredictions Testing tma_info_bad_spec_branch_misprediction_cost Testing tma_info_bad_spec_ipmisp_cond_ntaken Testing tma_info_bad_spec_ipmisp_cond_taken Testing tma_info_bad_spec_ipmisp_indirect Testing tma_info_bad_spec_ipmisp_ret Testing tma_info_bad_spec_ipmispredict Testing tma_info_branches_callret Testing tma_info_branches_cond_nt Testing tma_info_branches_cond_tk Testing tma_info_branches_jump Testing tma_info_branches_other_branches Testing tma_branch_mispredicts Testing tma_clears_resteers Testing tma_machine_clears Testing tma_mispredicts_resteers Testing tma_bottleneck_big_code Testing tma_icache_misses Testing tma_itlb_misses Testing tma_unknown_branches Testing tma_info_bad_spec_spec_clears_ratio Testing tma_other_mispredicts Testing tma_branch_instructions Testing tma_info_frontend_tbpc Testing tma_info_inst_mix_bptkbranch Testing tma_info_inst_mix_ipbranch Testing tma_info_inst_mix_ipcall Testing tma_info_inst_mix_iptb Testing tma_info_system_ipfarbranch Testing tma_info_thread_uptb Testing tma_bottleneck_branching_overhead Testing tma_nop_instructions Testing tma_bottleneck_compute_bound_est Testing tma_divider Testing tma_ports_utilized_3m Testing tma_bottleneck_instruction_fetch_bw Testing tma_frontend_bound Testing tma_assists Testing tma_other_nukes Testing tma_serializing_operation Testing tma_bottleneck_data_cache_memory_bandwidth Testing tma_fb_full Testing tma_mem_bandwidth Testing tma_sq_full Testing tma_bottleneck_data_cache_memory_latency Testing tma_l1_latency_dependency Testing tma_l2_bound Testing tma_l3_hit_latency Testing tma_mem_latency Testing tma_store_latency Testing tma_bottleneck_memory_synchronization Testing tma_contested_accesses Testing tma_data_sharing Testing tma_false_sharing Testing tma_bottleneck_memory_data_tlbs Testing tma_dtlb_load Testing tma_dtlb_store Testing tma_backend_bound Testing tma_bottleneck_other_bottlenecks Testing tma_bottleneck_useful_work Testing tma_retiring Testing tma_info_memory_fb_hpki Testing tma_info_memory_l1mpki Testing tma_info_memory_l1mpki_load Testing tma_info_memory_l2hpki_all Testing tma_info_memory_l2hpki_load Testing tma_info_memory_l2mpki_all Testing tma_info_memory_l2mpki_load Testing tma_l1_bound Testing tma_l3_bound Testing tma_info_memory_l2mpki_rfo Testing tma_fp_scalar Testing tma_fp_vector Testing tma_fp_vector_128b Testing tma_fp_vector_256b Testing tma_fp_vector_512b Testing tma_port_0 Testing tma_x87_use Testing tma_info_botlnk_l0_core_bound_likely Testing tma_info_core_fp_arith_utilization Testing tma_info_pipeline_execute Testing tma_info_system_gflops Testing tma_info_thread_execute_per_issue Testing tma_dsb Testing tma_info_botlnk_l2_dsb_bandwidth Testing tma_info_frontend_dsb_coverage Testing tma_decoder0_alone Testing tma_dsb_switches Testing tma_info_botlnk_l2_dsb_misses Testing tma_info_frontend_dsb_switch_cost Testing tma_info_frontend_ipdsb_miss_ret Testing tma_mite Testing tma_mite_4wide Testing CPUs_utilized Testing backend_cycles_idle [Ignored backend_cycles_idle] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not counted> cpu-cycles:u <not supported> stalled-cycles-backend:u 1.014051473 seconds time elapsed 1.005718000 seconds user 0.008013000 seconds sys Testing branch_frequency Testing branch_miss_rate Testing cs_per_second Testing cycles_frequency Testing frontend_cycles_idle [Ignored frontend_cycles_idle] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not counted> cpu-cycles:u <not supported> stalled-cycles-frontend:u 1.012813656 seconds time elapsed 1.004603000 seconds user 0.008004000 seconds sys Testing insn_per_cycle Testing migrations_per_second Testing page_faults_per_second Testing stalled_cycles_per_instruction [Ignored stalled_cycles_per_instruction] failed but as a Default metric this can be expected Error: No supported events found. The stalled-cycles-backend:u event is not supported. Testing tma_bad_speculation Testing l1d_miss_rate Testing llc_miss_rate Testing dtlb_miss_rate Testing itlb_miss_rate [Ignored itlb_miss_rate] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not supported> iTLB-loads:u 3,097 iTLB-load-misses:u 1.012766732 seconds time elapsed 1.004318000 seconds user 0.008002000 seconds sys Testing l1i_miss_rate [Ignored l1i_miss_rate] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not counted> L1-icache-load-misses:u <not supported> L1-icache-loads:u 1.013606395 seconds time elapsed 1.001371000 seconds user 0.011968000 seconds sys Testing l1_prefetch_miss_rate [Ignored l1_prefetch_miss_rate] failed but as a Default metric this can be expected Error: No supported events found. The L1-dcache-prefetches:u event is not supported. Testing tma_info_botlnk_l2_ic_misses Testing tma_info_frontend_fetch_upc Testing tma_info_frontend_icache_miss_latency Testing tma_info_frontend_ipunknown_branch Testing tma_info_frontend_lsd_coverage Testing tma_info_memory_tlb_code_stlb_mpki Testing tma_info_pipeline_fetch_dsb Testing tma_info_pipeline_fetch_lsd Testing tma_info_pipeline_fetch_mite Testing tma_info_pipeline_fetch_ms Testing tma_fetch_bandwidth Testing tma_lsd Testing tma_branch_resteers Testing tma_code_l2_hit Testing tma_code_l2_miss Testing tma_code_stlb_hit Testing tma_code_stlb_miss Testing tma_code_stlb_miss_2m Testing tma_code_stlb_miss_4k Testing tma_lcp Testing tma_ms_switches Testing tma_info_core_flopc Testing tma_info_inst_mix_iparith Testing tma_info_inst_mix_iparith_avx128 Testing tma_info_inst_mix_iparith_avx256 Testing tma_info_inst_mix_iparith_avx512 Testing tma_info_inst_mix_iparith_scalar_dp Testing tma_info_inst_mix_iparith_scalar_sp Testing tma_info_inst_mix_ipflop Testing tma_info_inst_mix_ippause Testing tma_fetch_latency Testing tma_fp_arith Testing tma_fp_assists Testing tma_info_system_cpu_utilization Testing tma_info_system_dram_bw_use [Skipped tma_info_system_dram_bw_use] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_ARB_TRK_REQUESTS.ALL:u <not supported> UNC_ARB_COH_TRK_REQUESTS.ALL:u 1,013,554,749 duration_time 1.013527265 seconds time elapsed 1.005417000 seconds user 0.008011000 seconds sys Testing tma_info_frontend_l2mpki_code Testing tma_info_frontend_l2mpki_code_all Testing tma_info_inst_mix_ipload Testing tma_info_inst_mix_ipstore Testing tma_info_memory_latency_load_l2_miss_latency Testing tma_lock_latency Testing tma_info_memory_core_l1d_cache_fill_bw_2t Testing tma_info_memory_core_l2_cache_fill_bw_2t Testing tma_info_memory_core_l3_cache_access_bw_2t Testing tma_info_memory_core_l3_cache_fill_bw_2t Testing tma_info_memory_l1d_cache_fill_bw Testing tma_info_memory_l2_cache_fill_bw Testing tma_info_memory_l3_cache_access_bw Testing tma_info_memory_l3_cache_fill_bw Testing tma_info_memory_l3mpki Testing tma_info_memory_load_miss_real_latency Testing tma_info_memory_mix_bus_lock_pki Testing tma_info_memory_mix_uc_load_pki Testing tma_info_memory_mlp Testing tma_info_memory_tlb_load_stlb_mpki Testing tma_info_memory_tlb_page_walks_utilization Testing tma_info_memory_tlb_store_stlb_mpki Testing tma_info_system_mem_parallel_reads [Skipped tma_info_system_mem_parallel_reads] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_ARB_DAT_OCCUPANCY.RD:u <not counted> UNC_ARB_DAT_OCCUPANCY.RD/cmask=1/ 1.013354884 seconds time elapsed 1.009239000 seconds user 0.004004000 seconds sys Testing tma_info_system_mem_read_latency [Skipped tma_info_system_mem_read_latency] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_ARB_DAT_OCCUPANCY.RD:u <not counted> UNC_ARB_TRK_OCCUPANCY.RD <not counted> UNC_ARB_TRK_REQUESTS.RD 1.012882143 seconds time elapsed 1.004600000 seconds user 0.008036000 seconds sys Testing tma_info_thread_cpi Testing tma_streaming_stores Testing tma_dram_bound Testing tma_store_bound Testing tma_l2_hit_latency Testing tma_load_stlb_hit Testing tma_load_stlb_miss Testing tma_load_stlb_miss_1g Testing tma_load_stlb_miss_2m Testing tma_load_stlb_miss_4k Testing tma_store_stlb_hit Testing tma_store_stlb_miss Testing tma_store_stlb_miss_1g Testing tma_store_stlb_miss_2m Testing tma_store_stlb_miss_4k Testing tma_info_memory_latency_data_l2_mlp Testing tma_info_memory_latency_load_l2_mlp Testing tma_info_pipeline_ipassist Testing tma_microcode_sequencer Testing tma_ms Testing tma_info_system_kernel_cpi [Failed tma_info_system_kernel_cpi] Metric contains missing events Error: No supported events found. Access to performance monitoring and observability operations is limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open access to performance monitoring and observability operations for processes without CAP_PERFMON, CAP_SYS_PTRACE or CAP_SYS_ADMIN Linux capability. More information can be found at 'Perf events and tool security' document: https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html perf_event_paranoid setting is 2: -1: Allow use of (almost) all events by all users Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK >= 0: Disallow raw and ftrace function tracepoint access >= 1: Disallow CPU event access >= 2: Disallow kernel profiling To make the adjusted perf_event_paranoid setting permanent preserve it in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) Testing tma_info_system_kernel_utilization [Failed tma_info_system_kernel_utilization] Metric contains missing events Error: No supported events found. Access to performance monitoring and observability operations is limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open access to performance monitoring and observability operations for processes without CAP_PERFMON, CAP_SYS_PTRACE or CAP_SYS_ADMIN Linux capability. More information can be found at 'Perf events and tool security' document: https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html perf_event_paranoid setting is 2: -1: Allow use of (almost) all events by all users Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK >= 0: Disallow raw and ftrace function tracepoint access >= 1: Disallow CPU event access >= 2: Disallow kernel profiling To make the adjusted perf_event_paranoid setting permanent preserve it in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) Testing tma_info_pipeline_retire Testing tma_info_thread_clks Testing tma_info_thread_uoppi Testing tma_memory_operations Testing tma_other_light_ops Testing tma_ports_utilization Testing tma_ports_utilized_0 Testing tma_ports_utilized_1 Testing tma_ports_utilized_2 Testing C10_Pkg_Residency [Failed C10_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c10-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c10-residency/u) in per-thread mode, enable system wide with '-a'. Testing C2_Pkg_Residency [Failed C2_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c2-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c2-residency/u) in per-thread mode, enable system wide with '-a'. Testing C3_Pkg_Residency [Failed C3_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { msr/tsc/, cstate_pkg/c3-residency/ } Error: No supported events found. Invalid event (msr/tsc/u) in per-thread mode, enable system wide with '-a'. Testing C6_Core_Residency [Failed C6_Core_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_core/c6-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_core/c6-residency/u) in per-thread mode, enable system wide with '-a'. Testing C6_Pkg_Residency [Failed C6_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c6-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c6-residency/u) in per-thread mode, enable system wide with '-a'. Testing C7_Core_Residency [Failed C7_Core_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_core/c7-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_core/c7-residency/u) in per-thread mode, enable system wide with '-a'. Testing C7_Pkg_Residency [Failed C7_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c7-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c7-residency/u) in per-thread mode, enable system wide with '-a'. Testing C8_Pkg_Residency [Failed C8_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c8-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c8-residency/u) in per-thread mode, enable system wide with '-a'. Testing C9_Pkg_Residency [Failed C9_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c9-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c9-residency/u) in per-thread mode, enable system wide with '-a'. Testing tma_info_core_epc Testing tma_info_system_core_frequency Testing tma_info_system_power [Skipped tma_info_system_power] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> Joules power/energy-pkg/u 1,013,238,256 duration_time 1.013223072 seconds time elapsed 0.995924000 seconds user 0.011903000 seconds sys Testing tma_info_system_power_license0_utilization Testing tma_info_system_power_license1_utilization Testing tma_info_system_power_license2_utilization Testing tma_info_system_turbo_utilization Testing tma_info_inst_mix_ipswpf Testing tma_info_memory_prefetches_useless_hwpf Testing tma_info_core_coreipc Testing tma_info_thread_ipc Testing tma_heavy_operations Testing tma_light_operations Testing tma_info_core_core_clks Testing tma_info_system_smt_2t_utilization Testing tma_info_thread_slots_utilization Testing UNCORE_FREQ [Skipped UNCORE_FREQ] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_CLOCK.SOCKET:u 1,015,993,466 duration_time 1.015949387 seconds time elapsed 1.007676000 seconds user 0.008029000 seconds sys Testing tma_info_system_socket_clks [Failed tma_info_system_socket_clks] Metric contains missing events Error: No supported events found. Invalid event (UNC_CLOCK.SOCKET:u) in per-thread mode, enable system wide with '-a'. Testing tma_info_inst_mix_instructions Testing tma_info_system_cpus_utilized Testing tma_info_system_mux Testing tma_info_system_time Testing tma_info_thread_slots Testing tma_few_uops_instructions Testing tma_4k_aliasing Testing tma_cisc Testing tma_fp_divider Testing tma_int_divider Testing tma_slow_pause Testing tma_split_loads Testing tma_split_stores Testing tma_store_fwd_blk Testing tma_alu_op_utilization Testing tma_load_op_utilization Testing tma_mixing_vectors Testing tma_store_op_utilization Testing tma_port_1 Testing tma_port_5 Testing tma_port_6 Testing smi_cycles [Skipped smi_cycles] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> msr/smi/u <not supported> msr/aperf/u 3,965,789,327 cycles:u 1.012779591 seconds time elapsed 1.004579000 seconds user 0.007972000 seconds sys Testing smi_num [Failed smi_num] Metric contains missing events Error: No supported events found. Invalid event (msr/smi/u) in per-thread mode, enable system wide with '-a'. Testing tsx_aborted_cycles Testing tsx_cycles_per_elision Testing tsx_cycles_per_transaction Testing tsx_transactional_cycles ---- end(-1) ---- 110: perf all metrics test : FAILED!
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 29 ++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +22 -7
@@ -15,7 +15,8 @@ then test_prog="perf test -w noploop" fi -err=0 +skip=0 +err=3 for m in $(perf list --raw-dump metrics); do echo "Testing $m" result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1)
@@ -23,6 +24,10 @@ for m in $(perf list --raw-dump metrics); do if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then # No error result and metric shown. + if [[ "$err" -ne 1 ]] + then + err=0 + fi continue fi if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]]
@@ -44,7 +49,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "in per-thread mode, enable system wide" ]]
@@ -53,7 +58,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "<not supported>" ]]
@@ -68,7 +73,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "<not counted>" ]]
@@ -77,7 +82,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]]
@@ -86,7 +91,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "PMM" ]]
@@ -95,7 +100,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue fi
@@ -106,6 +111,10 @@ for m in $(perf list --raw-dump metrics); do if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then # No error result and metric shown. + if [[ "$err" -ne 1 ]] + then + err=0 + fi continue fi echo "[Failed $m] has non-zero error '$result_err' or not printed in:"
@@ -113,4 +122,10 @@ for m in $(perf list --raw-dump metrics); do err=1 done +# return SKIP only if no success returned +if [[ "$err" -eq 3 && "$skip" -eq 1 ]] +then + err=2 +fi + exit "$err"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 602/1424 perf tests: Skip metrics validation if system-wide recording lacks permission
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 8953bfd8820b6525032023fda3a420098c1823ae ]
The metrics value validation test requires system-wide recording (-a), which can fail on systems without root permissions or where paranoid levels restrict tracing. Add a check to skip the test if -a is not supported.
Also fix false negatives during validation by updating parse error string patterns and resolving issues in metric list generation.
--- .../tests/shell/lib/perf_metric_validation.py | 11 ++- tools/perf/tests/shell/stat_all_metrics.sh | 75 ++++++++++++------- tools/perf/tests/shell/stat_metrics_values.sh | 7 ++ 3 files changed, 60 insertions(+), 33 deletions(-)
tools/perf/tests/shell/lib/perf_metric_validation.py +7 -4
@@ -378,10 +378,13 @@ class Validator: wl = workload.split() command.extend(wl) print(" ".join(command)) - cmd = subprocess.run(command, stderr=subprocess.PIPE, encoding='utf-8') - data = [x+'}' for x in cmd.stderr.split('}\n') if x] - if data[0][0] != '{': - data[0] = data[0][data[0].find('{'):] + cmd = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8') + lines = cmd.stderr.splitlines() + cmd.stdout.splitlines() + data = [] + for line in lines: + line = line.strip() + if line.startswith('{') and line.endswith('}'): + data.append(line) return data def collect_perf(self, workload: str):
tools/perf/tests/shell/stat_all_metrics.sh +46 -29
110 lines not on this page · raw message
tools/perf/tests/shell/stat_metrics_values.sh +7 -0
@@ -14,6 +14,13 @@ fi grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; } +# Skip if no permission to record system-wide events +if ! perf stat -a -e instructions sleep 0.01 >/dev/null 2>&1; then + echo "Skipping: no permission to record system-wide events (-a)" + exit 2 +fi + + pythonvalidator=$(dirname $0)/lib/perf_metric_validation.py rulefile=$(dirname $0)/lib/perf_metric_validation_rules.json tmpdir=$(mktemp -d /tmp/__perf_test.program.XXXXX)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 603/1424 perf test: raise limit to 20 percent for perf_stat_--bpf-counters_test
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Richter <[email protected]>
[ Upstream commit 999eea92e8d7a1ffa83f7dc89c83d8ed1e746fa9 ]
This test case often fails on s390 (about 2 out of 10) because the 10% percent limit on the difference between --bpf-counters event counting and s390 hardware counting is more than 10% in all failure cases. Raise the limit to 20% on s390 and the test case succeeds.
Stable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +6 -6
@@ -4,19 +4,19 @@ set -e -# check whether $2 is within +/- 10% of $1 +# check whether $2 is within +/- 20% of $1 compare_number() { first_num=$1 second_num=$2 - # upper bound is first_num * 110% - upper=$(expr $first_num + $first_num / 10 ) - # lower bound is first_num * 90% - lower=$(expr $first_num - $first_num / 10 ) + # upper bound is first_num * 120% + upper=$(expr $first_num + $first_num / 5 ) + # lower bound is first_num * 80% + lower=$(expr $first_num - $first_num / 5 ) if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 10%." + echo "The difference between $first_num and $second_num are greater than 20%." exit 1 fi }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 604/1424 perf test bpf-counters: Add test for BPF event modifier
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit d9bd1d4264baddf7ab8baae86e91674d369f22de ]
Refactor test to better enable sharing of logic, to give an idea of progress and introduce test functions. Add test of measuring both cycles and cycles:b simultaneously.
Stable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 75 ++++++++++++++------- 1 file changed, 52 insertions(+), 23 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +52 -23
@@ -4,21 +4,59 @@ set -e +workload="perf bench sched messaging -g 1 -l 100 -t" + # check whether $2 is within +/- 20% of $1 compare_number() { - first_num=$1 - second_num=$2 - - # upper bound is first_num * 120% - upper=$(expr $first_num + $first_num / 5 ) - # lower bound is first_num * 80% - lower=$(expr $first_num - $first_num / 5 ) - - if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 20%." - exit 1 - fi + first_num=$1 + second_num=$2 + + # upper bound is first_num * 120% + upper=$(expr $first_num + $first_num / 5 ) + # lower bound is first_num * 80% + lower=$(expr $first_num - $first_num / 5 ) + + if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then + echo "The difference between $first_num and $second_num are greater than 20%." + exit 1 + fi +} + +check_counts() +{ + base_cycles=$1 + bpf_cycles=$2 + + if [ "$base_cycles" = "<not" ]; then + echo "Skipping: cycles event not counted" + exit 2 + fi + if [ "$bpf_cycles" = "<not" ]; then + echo "Failed: cycles not counted with --bpf-counters" + exit 1 + fi +} + +test_bpf_counters() +{ + printf "Testing --bpf-counters " + base_cycles=$(perf stat --no-big-num -e cycles -- $workload 2>&1 | awk '/cycles/ {print $1}') + bpf_cycles=$(perf stat --no-big-num --bpf-counters -e cycles -- $workload 2>&1 | awk '/cycles/ {print $1}') + check_counts $base_cycles $bpf_cycles + compare_number $base_cycles $bpf_cycles + echo "[Success]" +} + +test_bpf_modifier() +{ + printf "Testing bpf event modifier " + stat_output=$(perf stat --no-big-num -e cycles/name=base_cycles/,cycles/name=bpf_cycles/b -- $workload 2>&1) + base_cycles=$(echo "$stat_output"| awk '/base_cycles/ {print $1}') + bpf_cycles=$(echo "$stat_output"| awk '/bpf_cycles/ {print $1}') + check_counts $base_cycles $bpf_cycles + compare_number $base_cycles $bpf_cycles + echo "[Success]" } # skip if --bpf-counters is not supported
@@ -30,16 +68,7 @@ if ! perf stat -e cycles --bpf-counters true > /dev/null 2>&1; then exit 2 fi -base_cycles=$(perf stat --no-big-num -e cycles -- perf bench sched messaging -g 1 -l 100 -t 2>&1 | awk '/cycles/ {print $1}') -if [ "$base_cycles" = "<not" ]; then - echo "Skipping: cycles event not counted" - exit 2 -fi -bpf_cycles=$(perf stat --no-big-num --bpf-counters -e cycles -- perf bench sched messaging -g 1 -l 100 -t 2>&1 | awk '/cycles/ {print $1}') -if [ "$bpf_cycles" = "<not" ]; then - echo "Failed: cycles not counted with --bpf-counters" - exit 1 -fi +test_bpf_counters +test_bpf_modifier -compare_number $base_cycles $bpf_cycles exit 0
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 605/1424 perf test stat_bpf_counter.sh: Stabilize the test results
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Veronika Molnarova <[email protected]>
[ Upstream commit e8b86f0311a4b721663df8105a680e5968f21d4c ]
The test has been failing for some time when two separate runs of perf benchmarks are recorded for cycles events and their counts are compared, while once the recording was done with option --bpf-counters and once without it. It is expected that the count of the samples should be within a certain range, firstly the difference was set to be within 10%, which was then later raised to 20%. However, the test case keeps failing on certain architectures as recording the provided benchmark can produce completely different counts based on the current load of the system.
Sampling two separate runs on intel-eaglestream-spr-13 of "perf stat --no-big-num -e cycles -- perf bench sched messaging -g 1 -l 100 -t":
Performance counter stats for 'perf bench sched messaging -g 1 -l 100 -t':
396782898 cycles
0.010051983 seconds time elapsed
0.008664000 seconds user
0.097058000 seconds sysPerformance counter stats for 'perf bench sched messaging -g 1 -l 100 -t':
1431133032 cycles
0.021803714 seconds time elapsed
0.023377000 seconds user
0.349918000 seconds sys, which is ranging from 400mil to 1400mil samples.
Instead of recording the cycles use instructions event, which provides more stable values. At the same time change the tested workload to one of the provided testing workloads by perf that is not based on a scheduler, which can provide another dependency on the current load.
Sampling instructions event with the new workload provide much more stable results on intel-eaglestream-spr-13 of "perf stat --no-big-num -e instructions -- perf test -w brstack":
Performance counter stats for 'perf test -w brstack':
64584494 instructions
0.009173945 seconds time elapsed
0.007262000 seconds user
0.002071000 seconds sysPerformance counter stats for 'perf test -w brstack':
64672669 instructions
0.008888135 seconds time elapsed
0.005018000 seconds user
0.004018000 seconds sysStable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +18 -18
@@ -4,7 +4,7 @@ set -e -workload="perf bench sched messaging -g 1 -l 100 -t" +workload="perf test -w brstack" # check whether $2 is within +/- 20% of $1 compare_number()
@@ -25,15 +25,15 @@ compare_number() check_counts() { - base_cycles=$1 - bpf_cycles=$2 + base_instructions=$1 + bpf_instructions=$2 - if [ "$base_cycles" = "<not" ]; then - echo "Skipping: cycles event not counted" + if [ "$base_instructions" = "<not" ]; then + echo "Skipping: instructions event not counted" exit 2 fi - if [ "$bpf_cycles" = "<not" ]; then - echo "Failed: cycles not counted with --bpf-counters" + if [ "$bpf_instructions" = "<not" ]; then + echo "Failed: instructions not counted with --bpf-counters" exit 1 fi }
@@ -41,29 +41,29 @@ check_counts() test_bpf_counters() { printf "Testing --bpf-counters " - base_cycles=$(perf stat --no-big-num -e cycles -- $workload 2>&1 | awk '/cycles/ {print $1}') - bpf_cycles=$(perf stat --no-big-num --bpf-counters -e cycles -- $workload 2>&1 | awk '/cycles/ {print $1}') - check_counts $base_cycles $bpf_cycles - compare_number $base_cycles $bpf_cycles + base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | awk '/instructions/ {print $1}') + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | awk '/instructions/ {print $1}') + check_counts $base_instructions $bpf_instructions + compare_number $base_instructions $bpf_instructions echo "[Success]" } test_bpf_modifier() { printf "Testing bpf event modifier " - stat_output=$(perf stat --no-big-num -e cycles/name=base_cycles/,cycles/name=bpf_cycles/b -- $workload 2>&1) - base_cycles=$(echo "$stat_output"| awk '/base_cycles/ {print $1}') - bpf_cycles=$(echo "$stat_output"| awk '/bpf_cycles/ {print $1}') - check_counts $base_cycles $bpf_cycles - compare_number $base_cycles $bpf_cycles + stat_output=$(perf stat --no-big-num -e instructions/name=base_instructions/,instructions/name=bpf_instructions/b -- $workload 2>&1) + base_instructions=$(echo "$stat_output"| awk '/base_instructions/ {print $1}') + bpf_instructions=$(echo "$stat_output"| awk '/bpf_instructions/ {print $1}') + check_counts $base_instructions $bpf_instructions + compare_number $base_instructions $bpf_instructions echo "[Success]" } # skip if --bpf-counters is not supported -if ! perf stat -e cycles --bpf-counters true > /dev/null 2>&1; then +if ! perf stat -e instructions --bpf-counters true > /dev/null 2>&1; then if [ "$1" = "-v" ]; then echo "Skipping: --bpf-counters not supported" - perf --no-pager stat -e cycles --bpf-counters true || true + perf --no-pager stat -e instructions --bpf-counters true || true fi exit 2 fi
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 606/1424 perf test: Use sqrtloop workload to test bperf event
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tengda Wu <[email protected]>
[ Upstream commit d36e5b36a2928b30e09ff59ce5ce2d5df935176e ]
Replace brstack workload with sqrtloop workload, because sqrtloop workload contains fork(), which is suitable for testing the bperf event inheritance feature.
Stable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/shell/stat_bpf_counters.sh +1 -1
@@ -4,7 +4,7 @@ set -e -workload="perf test -w brstack" +workload="perf test -w sqrtloop" # check whether $2 is within +/- 20% of $1 compare_number()
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 607/1424 perf test: Fix perf stat --bpf-counters on hybrid machines
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namhyung Kim <[email protected]>
[ Upstream commit d9db9c8db56c3e378aa5c91637664f77ca5a6f72 ]
The test constantly fails on my Intel hybrid machine. The issue was it has two events in the output even if I only gave it one event.
$ perf stat -e instructions -- perf test -w sqrtloop
Performance counter stats for 'perf test -w sqrtloop':
910,856,421 cpu_atom/instructions/ (28.05%)
14,852,865,997 cpu_core/instructions/ (96.79%) 1.014313341 seconds time elapsed
1.004114000 seconds user
0.008174000 seconds sysLet's modify the awk script to add the values for each line and print the total. The variable 'i' has a number of input lines that have valid output and variable 'c' has the sum of actual counter values. That way it should work on any platforms.
Stable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +16 -4
@@ -41,8 +41,14 @@ check_counts() test_bpf_counters() { printf "Testing --bpf-counters " - base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | awk '/instructions/ {print $1}') - bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | awk '/instructions/ {print $1}') + base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | \ + awk -v i=0 -v c=0 '/instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | \ + awk -v i=0 -v c=0 '/instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') check_counts $base_instructions $bpf_instructions compare_number $base_instructions $bpf_instructions echo "[Success]"
@@ -52,8 +58,14 @@ test_bpf_modifier() { printf "Testing bpf event modifier " stat_output=$(perf stat --no-big-num -e instructions/name=base_instructions/,instructions/name=bpf_instructions/b -- $workload 2>&1) - base_instructions=$(echo "$stat_output"| awk '/base_instructions/ {print $1}') - bpf_instructions=$(echo "$stat_output"| awk '/bpf_instructions/ {print $1}') + base_instructions=$(echo "$stat_output"| \ + awk -v i=0 -v c=0 '/base_instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') + bpf_instructions=$(echo "$stat_output"| \ + awk -v i=0 -v c=0 '/bpf_instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') check_counts $base_instructions $bpf_instructions compare_number $base_instructions $bpf_instructions echo "[Success]"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 608/1424 perf tests: Fix flakiness in BPF counters test on hybrid systems
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit b02027776ac5bf737f1b76f3759f405e376097e5 ]
The perf stat --bpf-counters test fails intermittently on hybrid architectures or systems with dynamic frequency scaling (DVFS). This happens because the test workload (sqrtloop) runs for a fixed 1-second duration, and the CPU frequency can scale dynamically between idle and maximum frequency. As the first run runs on a cold CPU and the second run runs on a warmed-up CPU (or vice versa), the number of instructions executed in 1 second differs by up to 2.2x, violating the comparison tolerance.
Also, when running as root, BPF tracepoints and scheduling programs trigger frequently. Since standard perf stat -e instructions measures both user and kernel space instructions, it counts BPF helper and program execution overheads, whereas the BPF counters themselves do not self- measure. This introduces a large kernel-space instruction count discrepancy between standard and BPF counters.
Fix these issues by:
1. Switching the workload to a strictly deterministic, iteration-based
workload: awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }'. We pin
the
workload to a single random allowed CPU using taskset -c $CPU via a
bash array.
2. Restricting the counted event to user-space only (instructions:u or /u).
3. Tightening the comparison tolerance from 20% to 15%.
These modifications isolate the measurements to user-space instructions of the deterministic loop, which executes a virtually identical number of instructions on both runs (with less than 0.001% variation), eliminating Dynamic Frequency Scaling (DVFS), kernel scheduling noise, and BPF helper self-measurement overheads.
--- tools/perf/tests/shell/stat_bpf_counters.sh | 28 +++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +18 -10
@@ -4,21 +4,26 @@ set -e -workload="perf test -w sqrtloop" +# Get the first allowed CPU +CPU=$(taskset -c -p $$ | awk -F': ' '{print $2}' | awk -F'[,-]' '{print $1}') +if [ -z "$CPU" ]; then + CPU=0 +fi +workload=(taskset -c "$CPU" awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }') -# check whether $2 is within +/- 20% of $1 +# check whether $2 is within +/- 15% of $1 compare_number() { first_num=$1 second_num=$2 - # upper bound is first_num * 120% - upper=$(expr $first_num + $first_num / 5 ) - # lower bound is first_num * 80% - lower=$(expr $first_num - $first_num / 5 ) + # upper bound is first_num * 115% + upper=$(expr $first_num + $first_num / 20 \* 3 ) + # lower bound is first_num * 85% + lower=$(expr $first_num - $first_num / 20 \* 3 ) if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 20%." + echo "The difference between $first_num and $second_num are greater than 15%." exit 1 fi }
@@ -41,11 +46,12 @@ check_counts() test_bpf_counters() { printf "Testing --bpf-counters " - base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | \ + base_instructions=$(perf stat --no-big-num -e instructions:u -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != "<not") { i++; c += $1 } \ } END { if (i > 0) printf "%.0f", c; else print "<not" }') - bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | \ + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions:u \ + -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != "<not") { i++; c += $1 } \ } END { if (i > 0) printf "%.0f", c; else print "<not" }')
@@ -57,7 +63,9 @@ test_bpf_counters() test_bpf_modifier() { printf "Testing bpf event modifier " - stat_output=$(perf stat --no-big-num -e instructions/name=base_instructions/,instructions/name=bpf_instructions/b -- $workload 2>&1) + stat_output=$(perf stat --no-big-num \ + -e instructions/name=base_instructions/u,instructions/name=bpf_instructions/bu \ + -- "${workload[@]}" 2>&1) base_instructions=$(echo "$stat_output"| \ awk -v i=0 -v c=0 '/base_instructions/ { \ if ($1 != "<not") { i++; c += $1 } \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 609/1424 mfd: tps6594: Add register definitions for TI TPS65224 PMIC
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nirmala Devi Mal Nadar <[email protected]>
[ Upstream commit 84ccfaee29fe46e305244a69c4471e83629ad5d1 ]
Extend TPS6594 PMIC register and field definitions to support TPS65224 power management IC.
TPS65224 is software compatible to TPS6594 and can re-use many of the same definitions, new definitions are added to support additional controls available on TPS65224.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- include/linux/mfd/tps6594.h | 347 ++++++++++++++++++++++++++++++++++-- 1 file changed, 335 insertions(+), 12 deletions(-)
include/linux/mfd/tps6594.h +335 -12
@@ -18,12 +18,13 @@ enum pmic_id {TPS6594 ,TPS6593 ,LP8764 , + TPS65224, };/* Macro to get page index from register address */ #define TPS6594_REG_TO_PAGE (reg) ((reg) >> 8) -/* Registers for page 0 of TPS6594 */ +/* Registers for page 0 */ #define TPS6594_REG_DEV_REV 0x01#define TPS6594_REG_NVM_CODE_1 0x02
@@ -56,9 +57,6 @@ enum pmic_id {#define TPS6594_REG_GPIOX_OUT (gpio_inst) (TPS6594_REG_GPIO_OUT_1 + (gpio_inst) / 8)#define TPS6594_REG_GPIOX_IN (gpio_inst) (TPS6594_REG_GPIO_IN_1 + (gpio_inst) / 8) -#define TPS6594_REG_GPIO_IN_1 0x3f -#define TPS6594_REG_GPIO_IN_2 0x40 -#define TPS6594_REG_RAIL_SEL_1 0x41#define TPS6594_REG_RAIL_SEL_2 0x42#define TPS6594_REG_RAIL_SEL_3 0x43
@@ -70,13 +68,15 @@ enum pmic_id {#define TPS6594_REG_FSM_TRIG_MASK_3 0x48#define TPS6594_REG_MASK_BUCK1_2 0x49 +#define TPS65224_REG_MASK_BUCKS 0x49#define TPS6594_REG_MASK_BUCK3_4 0x4a#define TPS6594_REG_MASK_BUCK5 0x4b#define TPS6594_REG_MASK_LDO1_2 0x4c +#define TPS65224_REG_MASK_LDOS 0x4c#define TPS6594_REG_MASK_LDO3_4 0x4d#define TPS6594_REG_MASK_VMON 0x4e -#define TPS6594_REG_MASK_GPIO1_8_FALL 0x4f -#define TPS6594_REG_MASK_GPIO1_8_RISE 0x50 +#define TPS6594_REG_MASK_GPIO_FALL 0x4f +#define TPS6594_REG_MASK_GPIO_RISE 0x50#define TPS6594_REG_MASK_GPIO9_11 0x51#define TPS6594_REG_MASK_STARTUP 0x52#define TPS6594_REG_MASK_MISC 0x53
@@ -174,6 +174,10 @@ enum pmic_id {#define TPS6594_REG_REGISTER_LOCK 0xa1 +#define TPS65224_REG_SRAM_ACCESS_1 0xa2 +#define TPS65224_REG_SRAM_ACCESS_2 0xa3 +#define TPS65224_REG_SRAM_ADDR_CTRL 0xa4 +#define TPS65224_REG_RECOV_CNT_PFSM_INCR 0xa5#define TPS6594_REG_MANUFACTURING_VER 0xa6#define TPS6594_REG_CUSTOMER_NVM_ID_REG 0xa7
@@ -182,6 +186,9 @@ enum pmic_id {#define TPS6594_REG_SOFT_REBOOT_REG 0xab +#define TPS65224_REG_ADC_CTRL 0xac +#define TPS65224_REG_ADC_RESULT_REG_1 0xad +#define TPS65224_REG_ADC_RESULT_REG_2 0xae#define TPS6594_REG_RTC_SECONDS 0xb5#define TPS6594_REG_RTC_MINUTES 0xb6#define TPS6594_REG_RTC_HOURS 0xb7
@@ -199,6 +206,7 @@ enum pmic_id {#define TPS6594_REG_RTC_CTRL_1 0xc2#define TPS6594_REG_RTC_CTRL_2 0xc3 +#define TPS65224_REG_STARTUP_CTRL 0xc3#define TPS6594_REG_RTC_STATUS 0xc4#define TPS6594_REG_RTC_INTERRUPTS 0xc5#define TPS6594_REG_RTC_COMP_LSB 0xc6
@@ -214,13 +222,17 @@ enum pmic_id {#define TPS6594_REG_PFSM_DELAY_REG_2 0xce#define TPS6594_REG_PFSM_DELAY_REG_3 0xcf#define TPS6594_REG_PFSM_DELAY_REG_4 0xd0 +#define TPS65224_REG_ADC_GAIN_COMP_REG 0xd0 +#define TPS65224_REG_CRC_CALC_CONTROL 0xef +#define TPS65224_REG_REGMAP_USER_CRC_LOW 0xf0 +#define TPS65224_REG_REGMAP_USER_CRC_HIGH 0xf1 -/* Registers for page 1 of TPS6594 */ +/* Registers for page 1 */ #define TPS6594_REG_SERIAL_IF_CONFIG 0x11a#define TPS6594_REG_I2C1_ID 0x122#define TPS6594_REG_I2C2_ID 0x123 -/* Registers for page 4 of TPS6594 */ +/* Registers for page 4 */ #define TPS6594_REG_WD_ANSWER_REG 0x401#define TPS6594_REG_WD_QUESTION_ANSW_CNT 0x402#define TPS6594_REG_WD_WIN1_CFG 0x403
@@ -241,16 +253,26 @@ enum pmic_id {#define TPS6594_BIT_BUCK_PLDN BIT(5)#define TPS6594_BIT_BUCK_RV_SEL BIT(7) -/* BUCKX_CONF register field definition */ +/* TPS6594 BUCKX_CONF register field definition */ #define TPS6594_MASK_BUCK_SLEW_RATE GENMASK(2, 0)#define TPS6594_MASK_BUCK_ILIM GENMASK(5, 3) -/* BUCKX_PG_WINDOW register field definition */ +/* TPS65224 BUCKX_CONF register field definition */ +#define TPS65224_MASK_BUCK_SLEW_RATE GENMASK(1, 0) + +/* TPS6594 BUCKX_PG_WINDOW register field definition */ #define TPS6594_MASK_BUCK_OV_THR GENMASK(2, 0)#define TPS6594_MASK_BUCK_UV_THR GENMASK(5, 3) -/* BUCKX VSET */ -#define TPS6594_MASK_BUCKS_VSET GENMASK(7, 0) +/* TPS65224 BUCKX_PG_WINDOW register field definition */ +#define TPS65224_MASK_BUCK_VMON_THR GENMASK(1, 0) + +/* TPS6594 BUCKX_VOUT register field definition */ +#define TPS6594_MASK_BUCKS_VSET GENMASK(7, 0) + +/* TPS65224 BUCKX_VOUT register field definition */ +#define TPS65224_MASK_BUCK1_VSET GENMASK(7, 0) +#define TPS65224_MASK_BUCKS_VSET GENMASK(6, 0)/* LDOX_CTRL register field definition */ #define TPS6594_BIT_LDO_EN BIT(0)
@@ -258,6 +280,7 @@ enum pmic_id {#define TPS6594_BIT_LDO_VMON_EN BIT(4)#define TPS6594_MASK_LDO_PLDN GENMASK(6, 5)#define TPS6594_BIT_LDO_RV_SEL BIT(7) +#define TPS65224_BIT_LDO_DISCHARGE_EN BIT(5)/* LDORTC_CTRL register field definition */ #define TPS6594_BIT_LDORTC_DIS BIT(0)
@@ -271,6 +294,9 @@ enum pmic_id {#define TPS6594_MASK_LDO_OV_THR GENMASK(2, 0)#define TPS6594_MASK_LDO_UV_THR GENMASK(5, 3) +/* LDOX_PG_WINDOW register field definition */ +#define TPS65224_MASK_LDO_VMON_THR GENMASK(1, 0) +/* VCCA_VMON_CTRL register field definition */ #define TPS6594_BIT_VMON_EN BIT(0)#define TPS6594_BIT_VMON1_EN BIT(1)
@@ -278,10 +304,12 @@ enum pmic_id {#define TPS6594_BIT_VMON2_EN BIT(3)#define TPS6594_BIT_VMON2_RV_SEL BIT(4)#define TPS6594_BIT_VMON_DEGLITCH_SEL BIT(5) +#define TPS65224_BIT_VMON_DEGLITCH_SEL GENMASK(7, 5)/* VCCA_PG_WINDOW register field definition */ #define TPS6594_MASK_VCCA_OV_THR GENMASK(2, 0)#define TPS6594_MASK_VCCA_UV_THR GENMASK(5, 3) +#define TPS65224_MASK_VCCA_VMON_THR GENMASK(1, 0)#define TPS6594_BIT_VCCA_PG_SET BIT(6)/* VMONX_PG_WINDOW register field definition */
@@ -289,6 +317,9 @@ enum pmic_id {#define TPS6594_MASK_VMONX_UV_THR GENMASK(5, 3)#define TPS6594_BIT_VMONX_RANGE BIT(6) +/* VMONX_PG_WINDOW register field definition */ +#define TPS65224_MASK_VMONX_THR GENMASK(1, 0) +/* GPIOX_CONF register field definition */ #define TPS6594_BIT_GPIO_DIR BIT(0)#define TPS6594_BIT_GPIO_OD BIT(1)
@@ -296,6 +327,8 @@ enum pmic_id {#define TPS6594_BIT_GPIO_PU_PD_EN BIT(3)#define TPS6594_BIT_GPIO_DEGLITCH_EN BIT(4)#define TPS6594_MASK_GPIO_SEL GENMASK(7, 5) +#define TPS65224_MASK_GPIO_SEL GENMASK(6, 5) +#define TPS65224_MASK_GPIO_SEL_GPIO6 GENMASK(7, 5)/* NPWRON_CONF register field definition */ #define TPS6594_BIT_NRSTOUT_OD BIT(0)
@@ -305,6 +338,12 @@ enum pmic_id {#define TPS6594_BIT_ENABLE_POL BIT(5)#define TPS6594_MASK_NPWRON_SEL GENMASK(7, 6) +/* POWER_ON_CONFIG register field definition */ +#define TPS65224_BIT_NINT_ENDRV_PU_SEL BIT(0) +#define TPS65224_BIT_NINT_ENDRV_SEL BIT(1) +#define TPS65224_BIT_EN_PB_DEGL BIT(5) +#define TPS65224_MASK_EN_PB_VSENSE_CONFIG GENMASK(7, 6) +/* GPIO_OUT_X register field definition */ #define TPS6594_BIT_GPIOX_OUT (gpio_inst) BIT((gpio_inst) % 8)
@@ -312,6 +351,12 @@ enum pmic_id {#define TPS6594_BIT_GPIOX_IN (gpio_inst) BIT((gpio_inst) % 8)#define TPS6594_BIT_NPWRON_IN BIT(3) +/* GPIO_OUT_X register field definition */ +#define TPS65224_BIT_GPIOX_OUT (gpio_inst) BIT((gpio_inst)) + +/* GPIO_IN_X register field definition */ +#define TPS65224_BIT_GPIOX_IN (gpio_inst) BIT((gpio_inst)) +/* RAIL_SEL_1 register field definition */ #define TPS6594_MASK_BUCK1_GRP_SEL GENMASK(1, 0)#define TPS6594_MASK_BUCK2_GRP_SEL GENMASK(3, 2)
@@ -343,6 +388,9 @@ enum pmic_id {#define TPS6594_BIT_GPIOX_FSM_MASK (gpio_inst) BIT(((gpio_inst) << 1) % 8)#define TPS6594_BIT_GPIOX_FSM_MASK_POL (gpio_inst) BIT(((gpio_inst) << 1) % 8 + 1) +#define TPS65224_BIT_GPIOX_FSM_MASK (gpio_inst) BIT(((gpio_inst) << 1) % 6) +#define TPS65224_BIT_GPIOX_FSM_MASK_POL (gpio_inst) BIT(((gpio_inst) << 1) % 6 + 1) +/* MASK_BUCKX register field definition */ #define TPS6594_BIT_BUCKX_OV_MASK (buck_inst) BIT(((buck_inst) << 2) % 8)#define TPS6594_BIT_BUCKX_UV_MASK (buck_inst) BIT(((buck_inst) << 2) % 8 + 1)
@@ -361,22 +409,46 @@ enum pmic_id {#define TPS6594_BIT_VMON2_OV_MASK BIT(5)#define TPS6594_BIT_VMON2_UV_MASK BIT(6) +/* MASK_BUCK Register field definition */ +#define TPS65224_BIT_BUCK1_UVOV_MASK BIT(0) +#define TPS65224_BIT_BUCK2_UVOV_MASK BIT(1) +#define TPS65224_BIT_BUCK3_UVOV_MASK BIT(2) +#define TPS65224_BIT_BUCK4_UVOV_MASK BIT(4) + +/* MASK_LDO_VMON register field definition */ +#define TPS65224_BIT_LDO1_UVOV_MASK BIT(0) +#define TPS65224_BIT_LDO2_UVOV_MASK BIT(1) +#define TPS65224_BIT_LDO3_UVOV_MASK BIT(2) +#define TPS65224_BIT_VCCA_UVOV_MASK BIT(4) +#define TPS65224_BIT_VMON1_UVOV_MASK BIT(5) +#define TPS65224_BIT_VMON2_UVOV_MASK BIT(6) +/* MASK_GPIOX register field definition */ #define TPS6594_BIT_GPIOX_FALL_MASK (gpio_inst) BIT((gpio_inst) < 8 ? \ (gpio_inst) : (gpio_inst) % 8)#define TPS6594_BIT_GPIOX_RISE_MASK (gpio_inst) BIT((gpio_inst) < 8 ? \ (gpio_inst) : (gpio_inst) % 8 + 3) +/* MASK_GPIOX register field definition */ +#define TPS65224_BIT_GPIOX_FALL_MASK (gpio_inst) BIT((gpio_inst)) +#define TPS65224_BIT_GPIOX_RISE_MASK (gpio_inst) BIT((gpio_inst))/* MASK_STARTUP register field definition */ #define TPS6594_BIT_NPWRON_START_MASK BIT(0)#define TPS6594_BIT_ENABLE_MASK BIT(1)#define TPS6594_BIT_FSD_MASK BIT(4)#define TPS6594_BIT_SOFT_REBOOT_MASK BIT(5) +#define TPS65224_BIT_VSENSE_MASK BIT(0) +#define TPS65224_BIT_PB_SHORT_MASK BIT(2)/* MASK_MISC register field definition */ #define TPS6594_BIT_BIST_PASS_MASK BIT(0)#define TPS6594_BIT_EXT_CLK_MASK BIT(1) +#define TPS65224_BIT_REG_UNLOCK_MASK BIT(2)#define TPS6594_BIT_TWARN_MASK BIT(3) +#define TPS65224_BIT_PB_LONG_MASK BIT(4) +#define TPS65224_BIT_PB_FALL_MASK BIT(5) +#define TPS65224_BIT_PB_RISE_MASK BIT(6) +#define TPS65224_BIT_ADC_CONV_READY_MASK BIT(7)/* MASK_MODERATE_ERR register field definition */ #define TPS6594_BIT_BIST_FAIL_MASK BIT(1)
@@ -391,6 +463,8 @@ enum pmic_id {#define TPS6594_BIT_ORD_SHUTDOWN_MASK BIT(1)#define TPS6594_BIT_MCU_PWR_ERR_MASK BIT(2)#define TPS6594_BIT_SOC_PWR_ERR_MASK BIT(3) +#define TPS65224_BIT_COMM_ERR_MASK BIT(4) +#define TPS65224_BIT_I2C2_ERR_MASK BIT(5)/* MASK_COMM_ERR register field definition */ #define TPS6594_BIT_COMM_FRM_ERR_MASK BIT(0)
@@ -426,6 +500,12 @@ enum pmic_id {#define TPS6594_BIT_BUCK3_4_INT BIT(1)#define TPS6594_BIT_BUCK5_INT BIT(2) +/* INT_BUCK register field definition */ +#define TPS65224_BIT_BUCK1_UVOV_INT BIT(0) +#define TPS65224_BIT_BUCK2_UVOV_INT BIT(1) +#define TPS65224_BIT_BUCK3_UVOV_INT BIT(2) +#define TPS65224_BIT_BUCK4_UVOV_INT BIT(3) +/* INT_BUCKX register field definition */ #define TPS6594_BIT_BUCKX_OV_INT (buck_inst) BIT(((buck_inst) << 2) % 8)#define TPS6594_BIT_BUCKX_UV_INT (buck_inst) BIT(((buck_inst) << 2) % 8 + 1)
@@ -437,6 +517,14 @@ enum pmic_id {#define TPS6594_BIT_LDO3_4_INT BIT(1)#define TPS6594_BIT_VCCA_INT BIT(4) +/* INT_LDO_VMON register field definition */ +#define TPS65224_BIT_LDO1_UVOV_INT BIT(0) +#define TPS65224_BIT_LDO2_UVOV_INT BIT(1) +#define TPS65224_BIT_LDO3_UVOV_INT BIT(2) +#define TPS65224_BIT_VCCA_UVOV_INT BIT(4) +#define TPS65224_BIT_VMON1_UVOV_INT BIT(5) +#define TPS65224_BIT_VMON2_UVOV_INT BIT(6) +/* INT_LDOX register field definition */ #define TPS6594_BIT_LDOX_OV_INT (ldo_inst) BIT(((ldo_inst) << 2) % 8)#define TPS6594_BIT_LDOX_UV_INT (ldo_inst) BIT(((ldo_inst) << 2) % 8 + 1)
@@ -462,17 +550,32 @@ enum pmic_id {/* INT_GPIOX register field definition */ #define TPS6594_BIT_GPIOX_INT (gpio_inst) BIT(gpio_inst) +/* INT_GPIO register field definition */ +#define TPS65224_BIT_GPIO1_INT BIT(0) +#define TPS65224_BIT_GPIO2_INT BIT(1) +#define TPS65224_BIT_GPIO3_INT BIT(2) +#define TPS65224_BIT_GPIO4_INT BIT(3) +#define TPS65224_BIT_GPIO5_INT BIT(4) +#define TPS65224_BIT_GPIO6_INT BIT(5) +/* INT_STARTUP register field definition */ #define TPS6594_BIT_NPWRON_START_INT BIT(0) +#define TPS65224_BIT_VSENSE_INT BIT(0)#define TPS6594_BIT_ENABLE_INT BIT(1)#define TPS6594_BIT_RTC_INT BIT(2) +#define TPS65224_BIT_PB_SHORT_INT BIT(2)#define TPS6594_BIT_FSD_INT BIT(4)#define TPS6594_BIT_SOFT_REBOOT_INT BIT(5)/* INT_MISC register field definition */ #define TPS6594_BIT_BIST_PASS_INT BIT(0)#define TPS6594_BIT_EXT_CLK_INT BIT(1) +#define TPS65224_BIT_REG_UNLOCK_INT BIT(2)#define TPS6594_BIT_TWARN_INT BIT(3) +#define TPS65224_BIT_PB_LONG_INT BIT(4) +#define TPS65224_BIT_PB_FALL_INT BIT(5) +#define TPS65224_BIT_PB_RISE_INT BIT(6) +#define TPS65224_BIT_ADC_CONV_READY_INT BIT(7)/* INT_MODERATE_ERR register field definition */ #define TPS6594_BIT_TSD_ORD_INT BIT(0)
@@ -488,6 +591,7 @@ enum pmic_id {#define TPS6594_BIT_TSD_IMM_INT BIT(0)#define TPS6594_BIT_VCCA_OVP_INT BIT(1)#define TPS6594_BIT_PFSM_ERR_INT BIT(2) +#define TPS65224_BIT_BG_XMON_INT BIT(3)/* INT_FSM_ERR register field definition */ #define TPS6594_BIT_IMM_SHUTDOWN_INT BIT(0)
@@ -496,6 +600,7 @@ enum pmic_id {#define TPS6594_BIT_SOC_PWR_ERR_INT BIT(3)#define TPS6594_BIT_COMM_ERR_INT BIT(4)#define TPS6594_BIT_READBACK_ERR_INT BIT(5) +#define TPS65224_BIT_I2C2_ERR_INT BIT(5)#define TPS6594_BIT_ESM_INT BIT(6)#define TPS6594_BIT_WD_INT BIT(7)
@@ -536,8 +641,18 @@ enum pmic_id {#define TPS6594_BIT_VMON2_OV_STAT BIT(5)#define TPS6594_BIT_VMON2_UV_STAT BIT(6) +/* STAT_LDO_VMON register field definition */ +#define TPS65224_BIT_LDO1_UVOV_STAT BIT(0) +#define TPS65224_BIT_LDO2_UVOV_STAT BIT(1) +#define TPS65224_BIT_LDO3_UVOV_STAT BIT(2) +#define TPS65224_BIT_VCCA_UVOV_STAT BIT(4) +#define TPS65224_BIT_VMON1_UVOV_STAT BIT(5) +#define TPS65224_BIT_VMON2_UVOV_STAT BIT(6) +/* STAT_STARTUP register field definition */ +#define TPS65224_BIT_VSENSE_STAT BIT(0)#define TPS6594_BIT_ENABLE_STAT BIT(1) +#define TPS65224_BIT_PB_LEVEL_STAT BIT(2)/* STAT_MISC register field definition */ #define TPS6594_BIT_EXT_CLK_STAT BIT(1)
@@ -549,6 +664,7 @@ enum pmic_id {/* STAT_SEVERE_ERR register field definition */ #define TPS6594_BIT_TSD_IMM_STAT BIT(0)#define TPS6594_BIT_VCCA_OVP_STAT BIT(1) +#define TPS65224_BIT_BG_XMON_STAT BIT(3)/* STAT_READBACK_ERR register field definition */ #define TPS6594_BIT_EN_DRV_READBACK_STAT BIT(0)
@@ -597,6 +713,8 @@ enum pmic_id {#define TPS6594_BIT_BB_CHARGER_EN BIT(0)#define TPS6594_BIT_BB_ICHR BIT(1)#define TPS6594_MASK_BB_VEOC GENMASK(3, 2) +#define TPS65224_BIT_I2C1_SPI_CRC_EN BIT(4) +#define TPS65224_BIT_I2C2_CRC_EN BIT(5)#define TPS6594_BB_EOC_RDY BIT(7)/* ENABLE_DRV_REG register field definition */
@@ -617,6 +735,7 @@ enum pmic_id {#define TPS6594_BIT_NRSTOUT_SOC_IN BIT(2)#define TPS6594_BIT_FORCE_EN_DRV_LOW BIT(3)#define TPS6594_BIT_SPMI_LPM_EN BIT(4) +#define TPS65224_BIT_TSD_DISABLE BIT(5)/* RECOV_CNT_REG_1 register field definition */ #define TPS6594_MASK_RECOV_CNT GENMASK(3, 0)
@@ -671,15 +790,27 @@ enum pmic_id {/* ESM_SOC_START_REG register field definition */ #define TPS6594_BIT_ESM_SOC_START BIT(0) +/* ESM_MCU_START_REG register field definition */ +#define TPS65224_BIT_ESM_MCU_START BIT(0) +/* ESM_SOC_MODE_CFG register field definition */ #define TPS6594_MASK_ESM_SOC_ERR_CNT_TH GENMASK(3, 0)#define TPS6594_BIT_ESM_SOC_ENDRV BIT(5)#define TPS6594_BIT_ESM_SOC_EN BIT(6)#define TPS6594_BIT_ESM_SOC_MODE BIT(7) +/* ESM_MCU_MODE_CFG register field definition */ +#define TPS65224_MASK_ESM_MCU_ERR_CNT_TH GENMASK(3, 0) +#define TPS65224_BIT_ESM_MCU_ENDRV BIT(5) +#define TPS65224_BIT_ESM_MCU_EN BIT(6) +#define TPS65224_BIT_ESM_MCU_MODE BIT(7) +/* ESM_SOC_ERR_CNT_REG register field definition */ #define TPS6594_MASK_ESM_SOC_ERR_CNT GENMASK(4, 0) +/* ESM_MCU_ERR_CNT_REG register field definition */ +#define TPS6594_MASK_ESM_MCU_ERR_CNT GENMASK(4, 0) +/* REGISTER_LOCK register field definition */ #define TPS6594_BIT_REGISTER_LOCK_STATUS BIT(0)
@@ -687,6 +818,29 @@ enum pmic_id {#define TPS6594_MASK_VMON1_SLEW_RATE GENMASK(2, 0)#define TPS6594_MASK_VMON2_SLEW_RATE GENMASK(5, 3) +/* SRAM_ACCESS_1 Register field definition */ +#define TPS65224_MASk_SRAM_UNLOCK_SEQ GENMASK(7, 0) + +/* SRAM_ACCESS_2 Register field definition */ +#define TPS65224_BIT_SRAM_WRITE_MODE BIT(0) +#define TPS65224_BIT_OTP_PROG_USER BIT(1) +#define TPS65224_BIT_OTP_PROG_PFSM BIT(2) +#define TPS65224_BIT_OTP_PROG_STATUS BIT(3) +#define TPS65224_BIT_SRAM_UNLOCKED BIT(6) +#define TPS65224_USER_PROG_ALLOWED BIT(7) + +/* SRAM_ADDR_CTRL Register field definition */ +#define TPS65224_MASk_SRAM_SEL GENMASK(1, 0) + +/* RECOV_CNT_PFSM_INCR Register field definition */ +#define TPS65224_BIT_INCREMENT_RECOV_CNT BIT(0) + +/* MANUFACTURING_VER Register field definition */ +#define TPS65224_MASK_SILICON_REV GENMASK(7, 0) + +/* CUSTOMER_NVM_ID_REG Register field definition */ +#define TPS65224_MASK_CUSTOMER_NVM_ID GENMASK(7, 0) +/* SOFT_REBOOT_REG register field definition */ #define TPS6594_BIT_SOFT_REBOOT BIT(0)
@@ -755,14 +909,83 @@ enum pmic_id {#define TPS6594_BIT_I2C2_CRC_EN BIT(2)#define TPS6594_MASK_T_CRC GENMASK(7, 3) +/* ADC_CTRL Register field definition */ +#define TPS65224_BIT_ADC_START BIT(0) +#define TPS65224_BIT_ADC_CONT_CONV BIT(1) +#define TPS65224_BIT_ADC_THERMAL_SEL BIT(2) +#define TPS65224_BIT_ADC_RDIV_EN BIT(3) +#define TPS65224_BIT_ADC_STATUS BIT(7) + +/* ADC_RESULT_REG_1 Register field definition */ +#define TPS65224_MASK_ADC_RESULT_11_4 GENMASK(7, 0) + +/* ADC_RESULT_REG_2 Register field definition */ +#define TPS65224_MASK_ADC_RESULT_3_0 GENMASK(7, 4) + +/* STARTUP_CTRL Register field definition */ +#define TPS65224_MASK_STARTUP_DEST GENMASK(6, 5) +#define TPS65224_BIT_FIRST_STARTUP_DONE BIT(7) + +/* SCRATCH_PAD_REG_1 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_1 GENMASK(7, 0) + +/* SCRATCH_PAD_REG_2 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_2 GENMASK(7, 0) + +/* SCRATCH_PAD_REG_3 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_3 GENMASK(7, 0) + +/* SCRATCH_PAD_REG_4 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_4 GENMASK(7, 0) + +/* PFSM_DELAY_REG_1 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY1 GENMASK(7, 0) + +/* PFSM_DELAY_REG_2 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY2 GENMASK(7, 0) + +/* PFSM_DELAY_REG_3 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY3 GENMASK(7, 0) + +/* PFSM_DELAY_REG_4 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY4 GENMASK(7, 0) + +/* CRC_CALC_CONTROL Register field definition */ +#define TPS65224_BIT_RUN_CRC_BIST BIT(0) +#define TPS65224_BIT_RUN_CRC_UPDATE BIT(1) + +/* ADC_GAIN_COMP_REG Register field definition */ +#define TPS65224_MASK_ADC_GAIN_COMP GENMASK(7, 0) + +/* REGMAP_USER_CRC_LOW Register field definition */ +#define TPS65224_MASK_REGMAP_USER_CRC16_LOW GENMASK(7, 0) + +/* REGMAP_USER_CRC_HIGH Register field definition */ +#define TPS65224_MASK_REGMAP_USER_CRC16_HIGH GENMASK(7, 0) + +/* WD_ANSWER_REG Register field definition */ +#define TPS6594_MASK_WD_ANSWER GENMASK(7, 0) +/* WD_QUESTION_ANSW_CNT register field definition */ #define TPS6594_MASK_WD_QUESTION GENMASK(3, 0)#define TPS6594_MASK_WD_ANSW_CNT GENMASK(5, 4) +#define TPS65224_BIT_INT_TOP_STATUS BIT(7) + +/* WD WIN1_CFG register field definition */ +#define TPS6594_MASK_WD_WIN1_CFG GENMASK(6, 0) + +/* WD WIN2_CFG register field definition */ +#define TPS6594_MASK_WD_WIN2_CFG GENMASK(6, 0) + +/* WD LongWin register field definition */ +#define TPS6594_MASK_WD_LONGWIN_CFG GENMASK(7, 0)/* WD_MODE_REG register field definition */ #define TPS6594_BIT_WD_RETURN_LONGWIN BIT(0)#define TPS6594_BIT_WD_MODE_SELECT BIT(1)#define TPS6594_BIT_WD_PWRHOLD BIT(2) +#define TPS65224_BIT_WD_ENDRV_SEL BIT(6) +#define TPS65224_BIT_WD_CNT_SEL BIT(7)/* WD_QA_CFG register field definition */ #define TPS6594_MASK_WD_QUESTION_SEED GENMASK(3, 0)
@@ -993,6 +1216,106 @@ enum tps6594_irqs {#define TPS6594_IRQ_NAME_ALARM "alarm"#define TPS6594_IRQ_NAME_POWERUP "powerup" +/* IRQs */ +enum tps65224_irqs { +/* INT_BUCK register */ +TPS65224_IRQ_BUCK1_UVOV , +TPS65224_IRQ_BUCK2_UVOV , +TPS65224_IRQ_BUCK3_UVOV , +TPS65224_IRQ_BUCK4_UVOV , +/* INT_LDO_VMON register */ +TPS65224_IRQ_LDO1_UVOV , +TPS65224_IRQ_LDO2_UVOV , +TPS65224_IRQ_LDO3_UVOV , +TPS65224_IRQ_VCCA_UVOV , +TPS65224_IRQ_VMON1_UVOV , +TPS65224_IRQ_VMON2_UVOV , +/* INT_GPIO register */ +TPS65224_IRQ_GPIO1 , +TPS65224_IRQ_GPIO2 , +TPS65224_IRQ_GPIO3 , +TPS65224_IRQ_GPIO4 , +TPS65224_IRQ_GPIO5 , +TPS65224_IRQ_GPIO6 , +/* INT_STARTUP register */ +TPS65224_IRQ_VSENSE , +TPS65224_IRQ_ENABLE , +TPS65224_IRQ_PB_SHORT , +TPS65224_IRQ_FSD , +TPS65224_IRQ_SOFT_REBOOT , +/* INT_MISC register */ +TPS65224_IRQ_BIST_PASS , +TPS65224_IRQ_EXT_CLK , +TPS65224_IRQ_REG_UNLOCK , +TPS65224_IRQ_TWARN , +TPS65224_IRQ_PB_LONG , +TPS65224_IRQ_PB_FALL , +TPS65224_IRQ_PB_RISE , +TPS65224_IRQ_ADC_CONV_READY , +/* INT_MODERATE_ERR register */ +TPS65224_IRQ_TSD_ORD , +TPS65224_IRQ_BIST_FAIL , +TPS65224_IRQ_REG_CRC_ERR , +TPS65224_IRQ_RECOV_CNT , +/* INT_SEVERE_ERR register */ +TPS65224_IRQ_TSD_IMM , +TPS65224_IRQ_VCCA_OVP , +TPS65224_IRQ_PFSM_ERR , +TPS65224_IRQ_BG_XMON , +/* INT_FSM_ERR register */ +TPS65224_IRQ_IMM_SHUTDOWN , +TPS65224_IRQ_ORD_SHUTDOWN , +TPS65224_IRQ_MCU_PWR_ERR , +TPS65224_IRQ_SOC_PWR_ERR , +TPS65224_IRQ_COMM_ERR , +TPS65224_IRQ_I2C2_ERR , +}; + +#define TPS65224_IRQ_NAME_BUCK1_UVOV "buck1_uvov" +#define TPS65224_IRQ_NAME_BUCK2_UVOV "buck2_uvov" +#define TPS65224_IRQ_NAME_BUCK3_UVOV "buck3_uvov" +#define TPS65224_IRQ_NAME_BUCK4_UVOV "buck4_uvov" +#define TPS65224_IRQ_NAME_LDO1_UVOV "ldo1_uvov" +#define TPS65224_IRQ_NAME_LDO2_UVOV "ldo2_uvov" +#define TPS65224_IRQ_NAME_LDO3_UVOV "ldo3_uvov" +#define TPS65224_IRQ_NAME_VCCA_UVOV "vcca_uvov" +#define TPS65224_IRQ_NAME_VMON1_UVOV "vmon1_uvov" +#define TPS65224_IRQ_NAME_VMON2_UVOV "vmon2_uvov" +#define TPS65224_IRQ_NAME_GPIO1 "gpio1" +#define TPS65224_IRQ_NAME_GPIO2 "gpio2" +#define TPS65224_IRQ_NAME_GPIO3 "gpio3" +#define TPS65224_IRQ_NAME_GPIO4 "gpio4" +#define TPS65224_IRQ_NAME_GPIO5 "gpio5" +#define TPS65224_IRQ_NAME_GPIO6 "gpio6" +#define TPS65224_IRQ_NAME_VSENSE "vsense" +#define TPS65224_IRQ_NAME_ENABLE "enable" +#define TPS65224_IRQ_NAME_PB_SHORT "pb_short" +#define TPS65224_IRQ_NAME_FSD "fsd" +#define TPS65224_IRQ_NAME_SOFT_REBOOT "soft_reboot" +#define TPS65224_IRQ_NAME_BIST_PASS "bist_pass" +#define TPS65224_IRQ_NAME_EXT_CLK "ext_clk" +#define TPS65224_IRQ_NAME_REG_UNLOCK "reg_unlock" +#define TPS65224_IRQ_NAME_TWARN "twarn" +#define TPS65224_IRQ_NAME_PB_LONG "pb_long" +#define TPS65224_IRQ_NAME_PB_FALL "pb_fall" +#define TPS65224_IRQ_NAME_PB_RISE "pb_rise" +#define TPS65224_IRQ_NAME_ADC_CONV_READY "adc_conv_ready" +#define TPS65224_IRQ_NAME_TSD_ORD "tsd_ord" +#define TPS65224_IRQ_NAME_BIST_FAIL "bist_fail" +#define TPS65224_IRQ_NAME_REG_CRC_ERR "reg_crc_err" +#define TPS65224_IRQ_NAME_RECOV_CNT "recov_cnt" +#define TPS65224_IRQ_NAME_TSD_IMM "tsd_imm" +#define TPS65224_IRQ_NAME_VCCA_OVP "vcca_ovp" +#define TPS65224_IRQ_NAME_PFSM_ERR "pfsm_err" +#define TPS65224_IRQ_NAME_BG_XMON "bg_xmon" +#define TPS65224_IRQ_NAME_IMM_SHUTDOWN "imm_shutdown" +#define TPS65224_IRQ_NAME_ORD_SHUTDOWN "ord_shutdown" +#define TPS65224_IRQ_NAME_MCU_PWR_ERR "mcu_pwr_err" +#define TPS65224_IRQ_NAME_SOC_PWR_ERR "soc_pwr_err" +#define TPS65224_IRQ_NAME_COMM_ERR "comm_err" +#define TPS65224_IRQ_NAME_I2C2_ERR "i2c2_err" +#define TPS65224_IRQ_NAME_POWERUP "powerup" +/** * struct tps6594 - device private data structure *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 610/1424 regulator: tps6594-regulator: Add TI TPS65224 PMIC regulators
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nirmala Devi Mal Nadar <[email protected]>
[ Upstream commit 00c826525fbae0230f6c3e9879e56d50267deb42 ]
Add support for TPS65224 regulators (bucks and LDOs) to TPS6594 driver as they have significant functional overlap. TPS65224 PMIC has 4 buck regulators and 3 LDOs. BUCK12 can operate in dual phase.
The output voltages are configurable and are meant to supply power to the main processor and other components.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/Kconfig | 4 +- drivers/regulator/tps6594-regulator.c | 334 ++++++++++++++++++++------ 2 files changed, 268 insertions(+), 70 deletions(-)
drivers/regulator/Kconfig +3 -1
@@ -1543,13 +1543,15 @@ config REGULATOR_TPS6594 depends on MFD_TPS6594 && OF default MFD_TPS6594 help - This driver supports TPS6594 voltage regulator chips. + This driver supports TPS6594 series and TPS65224 voltage regulator chips. TPS6594 series of PMICs have 5 BUCKs and 4 LDOs voltage regulators. BUCKs 1,2,3,4 can be used in single phase or multiphase mode. Part number defines which single or multiphase mode is i used. It supports software based voltage control for different voltage domains. + TPS65224 PMIC has 4 BUCKs and 3 LDOs. BUCK12 can be used in dual phase. + All BUCKs and LDOs volatge can be controlled through software. config REGULATOR_TPS6524X tristate "TI TPS6524X Power regulators"
drivers/regulator/tps6594-regulator.c +265 -69
503 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 611/1424 regulator: tps6594-regulator: Fix the number of irqs for TPS65224 and TPS6594
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Richard <[email protected]>
[ Upstream commit 8141b6da1763b9db009e5dcf873869bb31bcef45 ]
The number of irqs is computed to allocate the right amount of memory for the irq data. An array of struct tps6594_regulator_irq_data is allocated one time for all the irqs. Each irq uses one cell of the array.
If the computed number of irqs is not correct, not allocated memory could be used.
Fix the values used in the calculation for TPS6594 and TPS65224.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/regulator/tps6594-regulator.c +4 -8
@@ -653,18 +653,14 @@ static int tps6594_regulator_probe(struct platform_device *pdev) } } -if (tps->chip_id ==LP8764 ) { - nr_buck =ARRAY_SIZE (buck_regs); - nr_ldo =0 ; - nr_types =REGS_INT_NB ; - }else if (tps->chip_id ==TPS65224 ) { +if (tps->chip_id ==TPS65224 ) { nr_buck =ARRAY_SIZE (tps65224_buck_regs); nr_ldo =ARRAY_SIZE (tps65224_ldo_regs); - nr_types =REGS_INT_NB ; + nr_types =TPS65224_REGS_INT_NB ; }else { nr_buck =ARRAY_SIZE (buck_regs); - nr_ldo =ARRAY_SIZE (tps6594_ldo_regs); - nr_types =TPS65224_REGS_INT_NB ; + nr_ldo = (tps->chip_id ==LP8764 ) ?0 :ARRAY_SIZE (tps6594_ldo_regs); + nr_types =REGS_INT_NB ; } reg_irq_nb = nr_types * (nr_buck + nr_ldo);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 612/1424 regulator: tps6594-regulator: Constify struct tps6594_regulator_irq_type
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christophe JAILLET <[email protected]>
[ Upstream commit c266209eaef4fef863363557817f7d6a68314321 ]
'struct tps6594_regulator_irq_type' are not modified in this driver.
Constifying this structure moves some data to a read-only section, so increases overall security.
On a x86_64, with allmodconfig, as an example:
Before:
======
text data bss dec hex filename
25645 14480 64 40189 9cfd drivers/regulator/tps6594-regulator.o
After:
=====
text data bss dec hex filename
27949 12176 64 40189 9cfd drivers/regulator/tps6594-regulator.o
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 60 +++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-)
drivers/regulator/tps6594-regulator.c +30 -30
@@ -56,7 +56,7 @@ struct tps6594_regulator_irq_type {unsigned long event; }; -static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { {TPS6594_IRQ_NAME_VCCA_OV ,"VCCA" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_VCCA_UV ,"VCCA" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_VMON1_OV ,"VMON1" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN },
@@ -69,7 +69,7 @@ static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { REGULATOR_EVENT_OVER_VOLTAGE_WARN }, }; -static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = { {TPS65224_IRQ_NAME_VCCA_UVOV ,"VCCA" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, {TPS65224_IRQ_NAME_VMON1_UVOV ,"VMON1" ,"voltage out of range" ,
@@ -80,13 +80,13 @@ static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = {struct tps6594_regulator_irq_data {struct device *dev; -struct tps6594_regulator_irq_type *type; +const struct tps6594_regulator_irq_type *type;struct regulator_dev *rdev; };struct tps6594_ext_regulator_irq_data {struct device *dev; -struct tps6594_regulator_irq_type *type; +const struct tps6594_regulator_irq_type *type; }; #define TPS6594_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
@@ -262,7 +262,7 @@ static const struct regulator_desc tps65224_buck_regs[] = { 4, 0, 0, NULL, 0, 0), }; -static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { {TPS6594_IRQ_NAME_BUCK1_OV ,"BUCK1" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK1_UV ,"BUCK1" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK1_SC ,"BUCK1" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -270,7 +270,7 @@ static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = { {TPS6594_IRQ_NAME_BUCK2_OV ,"BUCK2" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK2_UV ,"BUCK2" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK2_SC ,"BUCK2" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -278,7 +278,7 @@ static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = { {TPS6594_IRQ_NAME_BUCK3_OV ,"BUCK3" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK3_UV ,"BUCK3" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK3_SC ,"BUCK3" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -286,7 +286,7 @@ static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = { {TPS6594_IRQ_NAME_BUCK4_OV ,"BUCK4" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK4_UV ,"BUCK4" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK4_SC ,"BUCK4" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -294,7 +294,7 @@ static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = { {TPS6594_IRQ_NAME_BUCK5_OV ,"BUCK5" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK5_UV ,"BUCK5" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK5_SC ,"BUCK5" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -302,7 +302,7 @@ static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = { {TPS6594_IRQ_NAME_LDO1_OV ,"LDO1" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO1_UV ,"LDO1" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO1_SC ,"LDO1" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -310,7 +310,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = { {TPS6594_IRQ_NAME_LDO2_OV ,"LDO2" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO2_UV ,"LDO2" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO2_SC ,"LDO2" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -318,7 +318,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = { {TPS6594_IRQ_NAME_LDO3_OV ,"LDO3" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO3_UV ,"LDO3" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO3_SC ,"LDO3" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -326,7 +326,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { {TPS6594_IRQ_NAME_LDO4_OV ,"LDO4" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO4_UV ,"LDO4" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO4_SC ,"LDO4" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -334,42 +334,42 @@ static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = { {TPS65224_IRQ_NAME_BUCK1_UVOV ,"BUCK1" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = { {TPS65224_IRQ_NAME_BUCK2_UVOV ,"BUCK2" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = { {TPS65224_IRQ_NAME_BUCK3_UVOV ,"BUCK3" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = { {TPS65224_IRQ_NAME_BUCK4_UVOV ,"BUCK4" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = { {TPS65224_IRQ_NAME_LDO1_UVOV ,"LDO1" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = { {TPS65224_IRQ_NAME_LDO2_UVOV ,"LDO2" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = { {TPS65224_IRQ_NAME_LDO3_UVOV ,"LDO3" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { tps6594_buck1_irq_types, tps6594_buck2_irq_types, tps6594_buck3_irq_types,
@@ -377,21 +377,21 @@ static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { tps6594_buck5_irq_types, }; -static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { tps6594_ldo1_irq_types, tps6594_ldo2_irq_types, tps6594_ldo3_irq_types, tps6594_ldo4_irq_types, }; -static struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = { tps65224_buck1_irq_types, tps65224_buck2_irq_types, tps65224_buck3_irq_types, tps65224_buck4_irq_types, }; -static struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = { tps65224_ldo1_irq_types, tps65224_ldo2_irq_types, tps65224_ldo3_irq_types,
@@ -516,11 +516,11 @@ static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data)static int tps6594_request_reg_irqs (struct platform_device *pdev,struct regulator_dev *rdev,struct tps6594_regulator_irq_data *irq_data, -struct tps6594_regulator_irq_type *regs_irq_types, +const struct tps6594_regulator_irq_type *regs_irq_types,size_t interrupt_cnt,int *irq_idx) { -struct tps6594_regulator_irq_type *irq_type; +const struct tps6594_regulator_irq_type *irq_type;struct tps6594 *tps =dev_get_drvdata (pdev->dev.parent);size_t j;int irq;
@@ -558,8 +558,8 @@ static int tps6594_regulator_probe(struct platform_device *pdev)struct regulator_config config = {};struct tps6594_regulator_irq_data *irq_data;struct tps6594_ext_regulator_irq_data *irq_ext_reg_data; -struct tps6594_regulator_irq_type *irq_type; -struct tps6594_regulator_irq_type *irq_types; +const struct tps6594_regulator_irq_type *irq_type; +const struct tps6594_regulator_irq_type *irq_types;bool buck_configured[BUCK_NB ] = { false };bool buck_multi[MULTI_PHASE_NB ] = { false };
@@ -573,9 +573,9 @@ static int tps6594_regulator_probe(struct platform_device *pdev)unsigned int irq_count;unsigned int multi_phase_cnt;size_t reg_irq_nb; -struct tps6594_regulator_irq_type **bucks_irq_types; +const struct tps6594_regulator_irq_type **bucks_irq_types;const struct regulator_desc *multi_regs; -struct tps6594_regulator_irq_type **ldos_irq_types; +const struct tps6594_regulator_irq_type **ldos_irq_types;const struct regulator_desc *ldo_regs;size_t interrupt_count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 613/1424 regulator: tps6594-regulator: remove interrupt_count
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 16d1a9bf36ef649b1fdb866985b4b87584491fac ]
In .probe() interrupt_count and nr_types is essentially the same. It contains the number of different interrupt per LDO or buck converter. Drop one. This is a preparation patch to further simplify the handling of different variants of this PMIC.
This patch is only compile-time tested.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
drivers/regulator/tps6594-regulator.c +6 -11
@@ -577,18 +577,15 @@ static int tps6594_regulator_probe(struct platform_device *pdev)const struct regulator_desc *multi_regs;const struct tps6594_regulator_irq_type **ldos_irq_types;const struct regulator_desc *ldo_regs; -size_t interrupt_count;if (tps->chip_id ==TPS65224 ) { bucks_irq_types = tps65224_bucks_irq_types; - interrupt_count =ARRAY_SIZE (tps65224_buck1_irq_types); multi_regs = tps65224_multi_regs; ldos_irq_types = tps65224_ldos_irq_types; ldo_regs = tps65224_ldo_regs; multi_phase_cnt =ARRAY_SIZE (tps65224_multi_regs); }else { bucks_irq_types = tps6594_bucks_irq_types; - interrupt_count =ARRAY_SIZE (tps6594_buck1_irq_types); multi_regs = tps6594_multi_regs; ldos_irq_types = tps6594_ldos_irq_types; ldo_regs = tps6594_ldo_regs;
@@ -686,29 +683,27 @@ static int tps6594_regulator_probe(struct platform_device *pdev) error =tps6594_request_reg_irqs (pdev, rdev, irq_data, bucks_irq_types[buck_idx], - interrupt_count, &irq_idx); + nr_types, &irq_idx);if (error)return error; error =tps6594_request_reg_irqs (pdev, rdev, irq_data, bucks_irq_types[buck_idx +1 ], - interrupt_count, &irq_idx); + nr_types, &irq_idx);if (error)return error;if (i ==MULTI_BUCK123 || i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx +2 ], - interrupt_count, - &irq_idx); + nr_types, &irq_idx);if (error)return error; }if (i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx +3 ], - interrupt_count, - &irq_idx); + nr_types, &irq_idx);if (error)return error; }
@@ -727,7 +722,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev) "failed to register %s regulator\n", pdev->name); error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[i], interrupt_count, &irq_idx); + bucks_irq_types[i], nr_types, &irq_idx);if (error)return error; }
@@ -742,7 +737,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev) pdev->name); error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - ldos_irq_types[i], interrupt_count, + ldos_irq_types[i], nr_types, &irq_idx);if (error)return error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 614/1424 regulator: tps6594-regulator: remove hardcoded buck config
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 180a135eafa9e05657559bb04cc9eb6a86ca45f3 ]
Commit 00c826525fba ("regulator: tps6594-regulator: Add TI TPS65224 PMIC regulators") added support for the TPS65224 and made the description of the multi-phase buck converter variable depending on the variant of the PMIC. But this was just done for MUTLI_BUCK12 and MULTI_BUCK12_34 configs probably because this variant only supports a multi-phase configuration on buck 1 and 2. Remove the hardcoded value for the remaining two configs, too as future PMIC variants might also support these.
This is a preparation patch to refactor the regulator description and is compile-time only tested.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/regulator/tps6594-regulator.c +2 -2
@@ -695,14 +695,14 @@ static int tps6594_regulator_probe(struct platform_device *pdev)if (i ==MULTI_BUCK123 || i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx +2 ], + bucks_irq_types[buck_idx +2 ], nr_types, &irq_idx);if (error)return error; }if (i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx +3 ], + bucks_irq_types[buck_idx +3 ], nr_types, &irq_idx);if (error)return error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 615/1424 regulator: tps6594-regulator: refactor variant descriptions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit e64ee27abfe1e9baea14b31c0a6b6bf93ac8652c ]
Instead of using conditionals or tri state operators throughout the .probe() provide a description per variant. This will make it much easier to add new variants later.
While at it, make the variable naming more consistent.
This patch is only compile-time tested.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 199 +++++++++++++++----------- 1 file changed, 112 insertions(+), 87 deletions(-)
drivers/regulator/tps6594-regulator.c +112 -87
@@ -21,10 +21,6 @@#define BUCK_NB 5#define LDO_NB 4#define MULTI_PHASE_NB 4 -/* TPS6593 and LP8764 supports OV, UV, SC, ILIM */ -#define REGS_INT_NB 4 -/* TPS65224 supports OV or UV */ -#define TPS65224_REGS_INT_NB 1enum tps6594_regulator_id {/* DCDC's */
@@ -192,7 +188,7 @@ static const struct regulator_ops tps6594_ldos_4_ops = { .map_voltage = regulator_map_voltage_linear_range, }; -static const struct regulator_desc buck_regs[] = { +static const struct regulator_desc tps6594_buck_regs[] = { TPS6594_REGULATOR("BUCK1", "buck1", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, TPS6594_REG_BUCKX_VOUT_1(0),
@@ -549,6 +545,63 @@ static int tps6594_request_reg_irqs(struct platform_device *pdev,return 0 ; } +struct tps6594_regulator_desc { +const struct regulator_desc *multi_phase_regs; +unsigned int num_multi_phase_regs; + +const struct regulator_desc *buck_regs; +int num_buck_regs; + +const struct regulator_desc *ldo_regs; +int num_ldo_regs; + +const struct tps6594_regulator_irq_type **bucks_irq_types; +const struct tps6594_regulator_irq_type **ldos_irq_types; +int num_irq_types; + +const struct tps6594_regulator_irq_type *ext_irq_types; +int num_ext_irqs; +}; + +static const struct tps6594_regulator_desc tps65224_reg_desc = { + .multi_phase_regs = tps65224_multi_regs, + .num_multi_phase_regs =ARRAY_SIZE (tps65224_multi_regs), + .buck_regs = tps65224_buck_regs, + .num_buck_regs =ARRAY_SIZE (tps65224_buck_regs), + .ldo_regs = tps65224_ldo_regs, + .num_ldo_regs =ARRAY_SIZE (tps65224_ldo_regs), + .bucks_irq_types = tps65224_bucks_irq_types, + .ldos_irq_types = tps65224_ldos_irq_types, + .num_irq_types =1 ,/* OV or UV */ + .ext_irq_types = tps65224_ext_regulator_irq_types, + .num_ext_irqs =ARRAY_SIZE (tps65224_ext_regulator_irq_types), +}; + +static const struct tps6594_regulator_desc tps6594_reg_desc = { + .multi_phase_regs = tps6594_multi_regs, + .num_multi_phase_regs =ARRAY_SIZE (tps6594_multi_regs), + .buck_regs = tps6594_buck_regs, + .num_buck_regs =ARRAY_SIZE (tps6594_buck_regs), + .ldo_regs = tps6594_ldo_regs, + .num_ldo_regs =ARRAY_SIZE (tps6594_ldo_regs), + .bucks_irq_types = tps6594_bucks_irq_types, + .ldos_irq_types = tps6594_ldos_irq_types, + .num_irq_types =4 ,/* OV, UV, SC and ILIM */ + .ext_irq_types = tps6594_ext_regulator_irq_types, + .num_ext_irqs =2 ,/* only VCCA OV and UV */ +}; + +static const struct tps6594_regulator_desc lp8764_reg_desc = { + .multi_phase_regs = tps6594_multi_regs, + .num_multi_phase_regs =ARRAY_SIZE (tps6594_multi_regs), + .buck_regs = tps6594_buck_regs, + .num_buck_regs =ARRAY_SIZE (tps6594_buck_regs), + .bucks_irq_types = tps6594_bucks_irq_types, + .num_irq_types =4 ,/* OV, UV, SC and ILIM */ + .ext_irq_types = tps6594_ext_regulator_irq_types, + .num_ext_irqs =ARRAY_SIZE (tps6594_ext_regulator_irq_types), +}; +static int tps6594_regulator_probe (struct platform_device *pdev) {struct tps6594 *tps =dev_get_drvdata (pdev->dev.parent);
@@ -559,38 +612,32 @@ static int tps6594_regulator_probe(struct platform_device *pdev)struct tps6594_regulator_irq_data *irq_data;struct tps6594_ext_regulator_irq_data *irq_ext_reg_data;const struct tps6594_regulator_irq_type *irq_type; -const struct tps6594_regulator_irq_type *irq_types;bool buck_configured[BUCK_NB ] = { false };bool buck_multi[MULTI_PHASE_NB ] = { false }; +const struct tps6594_regulator_desc *desc; +const struct regulator_desc *multi_regs;static const char *npname;int error, i, irq, multi;int irq_idx =0 ;int buck_idx =0 ; -int nr_ldo; -int nr_buck; -int nr_types; -unsigned int irq_count; -unsigned int multi_phase_cnt;size_t reg_irq_nb; -const struct tps6594_regulator_irq_type **bucks_irq_types; -const struct regulator_desc *multi_regs; -const struct tps6594_regulator_irq_type **ldos_irq_types; -const struct regulator_desc *ldo_regs; -if (tps->chip_id ==TPS65224 ) { - bucks_irq_types = tps65224_bucks_irq_types; - multi_regs = tps65224_multi_regs; - ldos_irq_types = tps65224_ldos_irq_types; - ldo_regs = tps65224_ldo_regs; - multi_phase_cnt =ARRAY_SIZE (tps65224_multi_regs); - }else { - bucks_irq_types = tps6594_bucks_irq_types; - multi_regs = tps6594_multi_regs; - ldos_irq_types = tps6594_ldos_irq_types; - ldo_regs = tps6594_ldo_regs; - multi_phase_cnt =ARRAY_SIZE (tps6594_multi_regs); - } +switch (tps->chip_id) { +case TPS65224 : + desc = &tps65224_reg_desc; +break ; +case TPS6594 : +case TPS6593 : + desc = &tps6594_reg_desc; +break ; +case LP8764 : + desc = &lp8764_reg_desc; +break ; +default : +dev_err (tps->dev,"unknown chip_id %lu\n" , tps->chip_id); +return -EINVAL ; + };enum {MULTI_BUCK12 ,
@@ -611,13 +658,14 @@ static int tps6594_regulator_probe(struct platform_device *pdev)* In case of Multiphase configuration, value should be defined for * buck_configured to avoid creating bucks for every buck in multiphase */ -for (multi =0 ; multi < multi_phase_cnt; multi++) { - np =of_find_node_by_name (tps->dev->of_node, multi_regs[multi].supply_name); +for (multi =0 ; multi < desc->num_multi_phase_regs; multi++) { + multi_regs = &desc->multi_phase_regs[multi]; + np =of_find_node_by_name (tps->dev->of_node, multi_regs->supply_name); npname =of_node_full_name (np); np_pmic_parent =of_get_parent (of_get_parent (np));if (of_node_cmp (of_node_full_name (np_pmic_parent), tps->dev->of_node->full_name))continue ; -if (strcmp (npname, multi_regs[multi].supply_name) ==0 ) { +if (strcmp (npname, multi_regs->supply_name) ==0 ) {switch (multi) {case MULTI_BUCK12 : buck_multi[0 ] = true;
@@ -650,28 +698,19 @@ static int tps6594_regulator_probe(struct platform_device *pdev) } } -if (tps->chip_id ==TPS65224 ) { - nr_buck =ARRAY_SIZE (tps65224_buck_regs); - nr_ldo =ARRAY_SIZE (tps65224_ldo_regs); - nr_types =TPS65224_REGS_INT_NB ; - }else { - nr_buck =ARRAY_SIZE (buck_regs); - nr_ldo = (tps->chip_id ==LP8764 ) ?0 :ARRAY_SIZE (tps6594_ldo_regs); - nr_types =REGS_INT_NB ; - } - - reg_irq_nb = nr_types * (nr_buck + nr_ldo); + reg_irq_nb = desc->num_irq_types * (desc->num_buck_regs + desc->num_ldo_regs); irq_data =devm_kmalloc_array (tps->dev, reg_irq_nb,sizeof (struct tps6594_regulator_irq_data ),GFP_KERNEL );if (!irq_data)return -ENOMEM ; -for (i =0 ; i < multi_phase_cnt; i++) { +for (i =0 ; i < desc->num_multi_phase_regs; i++) {if (!buck_multi[i])continue ; - rdev =devm_regulator_register (&pdev->dev, &multi_regs[i], &config); + rdev =devm_regulator_register (&pdev->dev, &desc->multi_phase_regs[i], + &config);if (IS_ERR (rdev)) return dev_err_probe(tps->dev, PTR_ERR(rdev), "failed to register %s regulator\n",
@@ -682,89 +721,74 @@ static int tps6594_regulator_probe(struct platform_device *pdev) buck_idx =2 ; error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx], + desc->num_irq_types, &irq_idx);if (error)return error; error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx +1 ], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx +1 ], + desc->num_irq_types, &irq_idx);if (error)return error;if (i ==MULTI_BUCK123 || i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx +2 ], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx +2 ], + desc->num_irq_types, + &irq_idx);if (error)return error; }if (i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx +3 ], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx +3 ], + desc->num_irq_types, + &irq_idx);if (error)return error; } } -for (i =0 ; i < nr_buck; i++) { +for (i =0 ; i < desc->num_buck_regs; i++) {if (buck_configured[i])continue ; -const struct regulator_desc *buck_cfg = (tps->chip_id ==TPS65224 ) ? - tps65224_buck_regs : buck_regs; - - rdev =devm_regulator_register (&pdev->dev, &buck_cfg[i], &config); + rdev =devm_regulator_register (&pdev->dev, &desc->buck_regs[i], &config);if (IS_ERR (rdev))return dev_err_probe (tps->dev,PTR_ERR (rdev),"failed to register %s regulator\n" , pdev->name); error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[i], nr_types, &irq_idx); + desc->bucks_irq_types[i], + desc->num_irq_types, &irq_idx);if (error)return error; } -/* LP8764 doesn't have LDO */ -if (tps->chip_id !=LP8764 ) { -for (i =0 ; i < nr_ldo; i++) { - rdev =devm_regulator_register (&pdev->dev, &ldo_regs[i], &config); -if (IS_ERR (rdev)) -return dev_err_probe (tps->dev,PTR_ERR (rdev), -"failed to register %s regulator\n" , - pdev->name); - - error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - ldos_irq_types[i], nr_types, - &irq_idx); -if (error) -return error; - } - } +for (i =0 ; i < desc->num_ldo_regs; i++) { + rdev =devm_regulator_register (&pdev->dev, &desc->ldo_regs[i], &config); +if (IS_ERR (rdev)) +return dev_err_probe (tps->dev,PTR_ERR (rdev), +"failed to register %s regulator\n" , + pdev->name); -if (tps->chip_id ==TPS65224 ) { - irq_types = tps65224_ext_regulator_irq_types; - irq_count =ARRAY_SIZE (tps65224_ext_regulator_irq_types); - }else { - irq_types = tps6594_ext_regulator_irq_types; -if (tps->chip_id ==LP8764 ) - irq_count =ARRAY_SIZE (tps6594_ext_regulator_irq_types); -else -/* TPS6593 supports only VCCA OV and UV */ - irq_count =2 ; + error =tps6594_request_reg_irqs (pdev, rdev, irq_data, + desc->ldos_irq_types[i], + desc->num_irq_types, &irq_idx); +if (error) +return error; } irq_ext_reg_data =devm_kmalloc_array (tps->dev, - irq_count, + desc->num_ext_irqs,sizeof (struct tps6594_ext_regulator_irq_data ),GFP_KERNEL );if (!irq_ext_reg_data)return -ENOMEM ; -for (i =0 ; i < irq_count; ++i) { - irq_type = &irq_types[i]; +for (i =0 ; i < desc->num_ext_irqs; ++i) { + irq_type = &desc->ext_irq_types[i]; irq =platform_get_irq_byname (pdev, irq_type->irq_name);if (irq <0 )return -EINVAL ;
@@ -782,6 +806,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev)"failed to request %s IRQ %d\n" , irq_type->irq_name, irq); } +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 616/1424 regulator: tps6594: Fix device node reference leaks in multiphase loop
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Khare <[email protected]>
[ Upstream commit 7fd28093b3effc4f92566466df364622830ec608 ]
In tps6594_regulator_probe(), the multi-phase configuration loop calls of_find_node_by_name() to find buck nodes by name, and of_get_parent() twice to navigate to the PMIC parent node. None of the acquired node references (np, intermediate parent, np_pmic_parent) are ever released via of_node_put(), causing a reference leak on every loop iteration.
Additionally, of_find_node_by_name() can return NULL, but the result was immediately passed to of_node_full_name() and of_get_parent() without a NULL check, which could lead to a NULL pointer dereference.
Fix this by:
- Adding a NULL check for np after of_find_node_by_name()
- Storing the intermediate parent node in a local variable np_parent
- Calling of_node_put() on np, np_parent and np_pmic_parent at the end of each loop iteration
--- drivers/regulator/tps6594-regulator.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/regulator/tps6594-regulator.c +15 -4
@@ -659,13 +659,20 @@ static int tps6594_regulator_probe(struct platform_device *pdev)* buck_configured to avoid creating bucks for every buck in multiphase */ for (multi =0 ; multi < desc->num_multi_phase_regs; multi++) { +struct device_node *np_parent; + multi_regs = &desc->multi_phase_regs[multi]; np =of_find_node_by_name (tps->dev->of_node, multi_regs->supply_name); - npname =of_node_full_name (np); - np_pmic_parent =of_get_parent (of_get_parent (np)); -if (of_node_cmp (of_node_full_name (np_pmic_parent), tps->dev->of_node->full_name)) +if (!np)continue ; -if (strcmp (npname, multi_regs->supply_name) ==0 ) { + + npname =of_node_full_name (np); + np_parent =of_get_parent (np); + np_pmic_parent =of_get_parent (np_parent); + +if (np_pmic_parent && + !of_node_cmp (of_node_full_name (np_pmic_parent), tps->dev->of_node->full_name) && +strcmp (npname, multi_regs->supply_name) ==0 ) {switch (multi) {case MULTI_BUCK12 : buck_multi[0 ] = true;
@@ -696,6 +703,10 @@ static int tps6594_regulator_probe(struct platform_device *pdev)break ; } } + +of_node_put (np_pmic_parent); +of_node_put (np_parent); +of_node_put (np); } reg_irq_nb = desc->num_irq_types * (desc->num_buck_regs + desc->num_ldo_regs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 617/1424 drm/amdgpu/pm/powerplay: bounds-check voltage index in SMU7 lookup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit 3a8a05477cda6c8293e2b629495b42981dcaba32 ]
vddInd and vddcInd fields from VBIOS-parsed tables are used to index into voltage lookup tables without a bounds check. Return -EINVAL when any index is out of range.
--- .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+)
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +24 -0
@@ -2216,12 +2216,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table(if (data->vdd_gfx_control ==SMU7_VOLTAGE_CONTROL_BY_SVID2 ) {for (entry_id =0 ; entry_id < sclk_table->count; ++entry_id) { voltage_id = sclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddgfx_lookup_table->count) { +pr_err ("amdgpu: sclk[%u] vddgfx index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddgfx_lookup_table->count); +return -EINVAL ; + } sclk_table->entries[entry_id].vddgfx = table_info->vddgfx_lookup_table->entries[voltage_id].us_vdd; } }else {for (entry_id =0 ; entry_id < sclk_table->count; ++entry_id) { voltage_id = sclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: sclk[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } sclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }
@@ -2229,12 +2241,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table(for (entry_id =0 ; entry_id < mclk_table->count; ++entry_id) { voltage_id = mclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }for (entry_id =0 ; entry_id < mm_table->count; ++entry_id) { voltage_id = mm_table->entries[entry_id].vddcInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mm_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 618/1424 drm/amdgpu/pm/powerplay: bounds-check voltage index in Vega10 lookup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit 6fa33f594e46e775a94097f71b486d7b006b6917 ]
vddInd, vddciInd and mvddInd from VBIOS-parsed tables index into vddc, vddci and vddmem lookup tables without bounds checks across nine sites. Return -EINVAL when any index is out of range.
--- .../drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +34 -1
@@ -685,10 +685,18 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table(case 3 : vdt = table_info->vdd_dep_on_pixclk;break ;case 4 : vdt = table_info->vdd_dep_on_dispclk;break ;case 5 : vdt = table_info->vdd_dep_on_phyclk;break ; +default : +continue ; }for (entry_id =0 ; entry_id < vdt->count; entry_id++) { voltage_id = vdt->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: clk_dep[%u][%u] vddc index %u out of bounds (%u)\n" , + i, entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } vdt->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }
@@ -696,23 +704,48 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table(for (entry_id =0 ; entry_id < mm_table->count; ++entry_id) { voltage_id = mm_table->entries[entry_id].vddcInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mm_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }for (entry_id =0 ; entry_id < mclk_table->count; ++entry_id) { voltage_id = mclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; + voltage_id = mclk_table->entries[entry_id].vddciInd; +if (voltage_id >= table_info->vddci_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddci index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddci_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].vddci = table_info->vddci_lookup_table->entries[voltage_id].us_vdd; + voltage_id = mclk_table->entries[entry_id].mvddInd; +if (voltage_id >= table_info->vddmem_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddmem index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddmem_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].mvdd = table_info->vddmem_lookup_table->entries[voltage_id].us_vdd; } -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 619/1424 tools/bpf/bpftool: Reset vmlinux BTF after map commands
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 66d7e39e49b0dd57610c9b63afc65b4d5690983b ]
get_map_kv_btf() caches the vmlinux BTF object when a map uses btf_vmlinux_value_type_id. map dump released that object when the command completed, but left the global pointer stale.
The same cached object can also be returned to print_key_value(), which freed it directly. That leaves btf_vmlinux dangling before the command cleanup path runs.
Use free_map_kv_btf() for per-entry cleanup, and reset the cached btf_vmlinux pointer when the map command releases the object. This keeps batch mode from reusing a freed BTF object.
--- tools/bpf/bpftool/map.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
tools/bpf/bpftool/map.c +9 -3
@@ -787,6 +787,12 @@ static int maps_have_btf(int *fds, int nb_fds)static struct btf *btf_vmlinux; +static void free_btf_vmlinux (void ) +{ +btf__free (btf_vmlinux); + btf_vmlinux =NULL ; +} +static int get_map_kv_btf (const struct bpf_map_info *info,struct btf **btf) {int err =0 ;
@@ -955,7 +961,7 @@ static int do_dump(int argc, char **argv)close (fds[i]); exit_free:free (fds); -btf__free (btf_vmlinux); +free_btf_vmlinux ();return err; }
@@ -1046,7 +1052,7 @@ static void print_key_value(struct bpf_map_info *info, void *key, btf_wtr =get_btf_writer ();if (!btf_wtr) {p_info ("failed to create json writer for btf. falling back to plain output" ); -btf__free (btf); +free_map_kv_btf (btf); btf =NULL ;print_entry_plain (info, key, value); }else {
@@ -1062,7 +1068,7 @@ static void print_key_value(struct bpf_map_info *info, void *key, }else {print_entry_plain (info, key, value); } -btf__free (btf); +free_map_kv_btf (btf); }static int do_lookup (int argc,char **argv)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 620/1424 tools/bpf/bpftool: Reset vmlinux BTF after struct_ops commands
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit f7f540e19751face50c68bb9ce58460fcb46c293 ]
struct_ops frees the global btf_vmlinux object.
In batch mode, a later struct_ops command can reuse stale state.
Reset the BTF pointer and cached map info state.
--- tools/bpf/bpftool/struct_ops.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/bpf/bpftool/struct_ops.c +4 -0
@@ -637,6 +637,10 @@ int do_struct_ops(int argc, char **argv) err =cmd_select (cmds, argc, argv, do_help);btf__free (btf_vmlinux); + btf_vmlinux =NULL ; + map_info_type =NULL ; + map_info_alloc_len =0 ; + map_info_type_id =0 ;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 621/1424 bpf: Copy per-CPU map value padding in copy_map_value_long()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
[ Upstream commit 7cf9cd98cf6f0df3befc167ca6b54c07014d71de ]
In kernel, per-CPU map elements are stored with round_up(map->value_size, 8) bytes. On UAPI lookup paths, it copies the rounded size for each CPU into a temporary buffer.
However, copy_map_value_long() passes 'map->value_size' to bpf_obj_memcpy(). When the map has special fields, bpf_obj_memcpy() copies around those fields with memcpy(), and does not copy the tail padding between 'map->value_size' and round_up(map->value_size, 8).
The temporary UAPI lookup buffers are allocated without __GFP_ZERO. As a result, when the per-CPU map's value size is not equal to round_up(map->value_size, 8), UAPI LOOKUP_ELEM and its variants can return stale heap contents from that padding to user space. The same issue applies to bpf_iter for per-CPU maps.
Pass round_up(map->value_size, 8) to bpf_obj_memcpy() from copy_map_value_long(), so per-CPU maps both with and without special fields copy the entire per-CPU slot. Remove the now redundant round_up() from bpf_obj_memcpy()'s long_memcpy path.
--- include/linux/bpf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/bpf.h +2 -2
@@ -482,7 +482,7 @@ static inline void bpf_obj_memcpy(struct btf_record *rec,if (IS_ERR_OR_NULL (rec)) {if (long_memcpy) -bpf_long_memcpy (dst, src,round_up (size,8 )); +bpf_long_memcpy (dst, src, size);else memcpy (dst, src, size);return ;
@@ -505,7 +505,7 @@ static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)static inline void copy_map_value_long (struct bpf_map *map,void *dst,void *src) { -bpf_obj_memcpy (map->record, dst, src, map->value_size, true); +bpf_obj_memcpy (map->record, dst, src,round_up (map->value_size,8 ), true); }static inline void bpf_obj_memzero (struct btf_record *rec,void *dst,u32 size)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 622/1424 dmaengine: mediatek: mtk-uart-apdma: Return -ENOMEM on memory allocation failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit 467265c750edd7ab43803deeafe7d3120a791d32 ]
If dynamic memory allocation in driver's probe function execution fails, it should be reported to the driver's framework with -ENOMEM error code.
--- drivers/dma/mediatek/mtk-uart-apdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/mediatek/mtk-uart-apdma.c +1 -1
@@ -530,7 +530,7 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev)for (i =0 ; i < mtkd->dma_requests; i++) { c =devm_kzalloc (mtkd->ddev.dev,sizeof (*c),GFP_KERNEL );if (!c) { - rc = -ENODEV ; + rc = -ENOMEM ; goto err_no_dma; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 623/1424 dmaengine: xilinx_dma: Fix channel idle state management in AXIDMA and MCDMA interrupt handlers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suraj Gupta <[email protected]>
[ Upstream commit 0b6d055edb55ecadadf54e930c2b4fab76fa9a5a ]
Fix a race condition in AXIDMA and MCDMA irq handlers where the channel could be incorrectly marked as idle and attempt spurious transfers when descriptors are still being processed.
The issue occurs when:
1. Multiple descriptors are queued and active.
2. An interrupt fires after completing some descriptors.
3. xilinx_dma_complete_descriptor() moves completed descriptors to done_list.
4. Channel is marked idle and start_transfer() is called even though active_list still contains unprocessed descriptors.
5. This leads to premature transfer attempts and potential descriptor corruption or missed completions.
Only mark the channel as idle and start new transfers when the active list is actually empty, ensuring proper channel state management and avoiding spurious transfer attempts.
--- drivers/dma/xilinx/xilinx_dma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/dma/xilinx/xilinx_dma.c +8 -4
@@ -1867,8 +1867,10 @@ static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data)if (status &XILINX_MCDMA_IRQ_IOC_MASK ) {spin_lock (&chan->lock);xilinx_dma_complete_descriptor (chan); - chan->idle = true; - chan->start_transfer (chan); +if (list_empty (&chan->active_list)) { + chan->idle = true; + chan->start_transfer (chan); + }spin_unlock (&chan->lock); }
@@ -1924,8 +1926,10 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data) XILINX_DMA_DMASR_DLY_CNT_IRQ)) {spin_lock (&chan->lock);xilinx_dma_complete_descriptor (chan); - chan->idle = true; - chan->start_transfer (chan); +if (list_empty (&chan->active_list)) { + chan->idle = true; + chan->start_transfer (chan); + }spin_unlock (&chan->lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 624/1424 dmaengine: hisilicon: Return -ENOMEM on dynamic memory allocation in probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit cbabdd6ce1b313b5877c7fbb2f5e2f7936564d2f ]
Out of memory situation on driver's probe is expected to be reported to the driver's framework with a proper -ENOMEM error code.
--- drivers/dma/hisi_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/hisi_dma.c +1 -1
@@ -983,7 +983,7 @@ static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) hdma_dev =devm_kzalloc (dev,struct_size (hdma_dev, chan, chan_num),GFP_KERNEL );if (!hdma_dev) -return -EINVAL ; +return -ENOMEM ; hdma_dev->base =pcim_iomap_table (pdev)[PCI_BAR_2 ]; hdma_dev->pdev = pdev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 625/1424 soundwire: qcom: Fix port exhaustion check in stream_alloc_ports
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <[email protected]>
[ Upstream commit 6ccec91c3535b07310e12d32fe9c67ff8d31d965 ]
find_first_zero_bit(mask, n) returns n (not n+1) when all bits are set, so the guard pn > maxport is never true on exhaustion. The driver would silently call set_bit(maxport, port_mask) and assign the out-of-range port instead of returning -EBUSY. Fix the comparison to pn >= maxport.
--- drivers/soundwire/qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/soundwire/qcom.c +1 -1
@@ -1168,7 +1168,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,else pn =find_first_zero_bit (port_mask, maxport); -if (pn > maxport) { +if (pn >= maxport) {dev_err (ctrl->dev,"All ports busy\n" ); ret = -EBUSY ; goto err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 626/1424 iio: orientation: hid-sensor-rotation: Avoid race between callback setup and device exposure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanjay Chitroda <[email protected]>
[ Upstream commit 0e32649a7cf3cd784862f8dc0c68a5134731bfff ]
The driver currently exposes the IIO device to userspace before completing sensor hub callback registration, and similarly removes callbacks while the device can still be accessed during teardown.
This creates a timing window where userspace may enable the buffer before callbacks are available. In such cases:
- samples can be dropped,
- buffered reads may observe stale or no data.
Reorder probe and remove paths to ensure callbacks are active before device exposure and are removed after device is no longer accessible.
This avoids a race window leading to data loss.
--- drivers/iio/orientation/hid-sensor-rotation.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
drivers/iio/orientation/hid-sensor-rotation.c +10 -10
@@ -337,12 +337,6 @@ static int hid_dev_rot_probe(struct platform_device *pdev)return ret; } - ret =iio_device_register (indio_dev); -if (ret) { -dev_err (&pdev->dev,"device register failed\n" ); - goto error_remove_trigger; - } - rot_state->callbacks.send_event = dev_rot_proc_event; rot_state->callbacks.capture_sample = dev_rot_capture_sample; rot_state->callbacks.pdev = pdev;
@@ -350,13 +344,19 @@ static int hid_dev_rot_probe(struct platform_device *pdev) &rot_state->callbacks);if (ret) {dev_err (&pdev->dev,"callback reg failed\n" ); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret =iio_device_register (indio_dev); +if (ret) { +dev_err (&pdev->dev,"device register failed\n" ); + goto error_remove_callback; }return 0 ; -error_iio_unreg: -iio_device_unregister (indio_dev); +error_remove_callback: +sensor_hub_remove_callback (hsdev, hsdev->usage); error_remove_trigger:hid_sensor_remove_trigger (indio_dev, &rot_state->common_attributes);return ret;
@@ -369,8 +369,8 @@ static int hid_dev_rot_remove(struct platform_device *pdev)struct iio_dev *indio_dev =platform_get_drvdata (pdev);struct dev_rot_state *rot_state =iio_priv (indio_dev); -sensor_hub_remove_callback (hsdev, hsdev->usage);iio_device_unregister (indio_dev); +sensor_hub_remove_callback (hsdev, hsdev->usage);hid_sensor_remove_trigger (indio_dev, &rot_state->common_attributes);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 627/1424 csky: Fix a4/a5 restoration in syscall trace path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hanlin Song <[email protected]>
[ Upstream commit abb81e5ce7d995baa41556b8125fa59e28ba3be8 ]
The syscall trace path reloads syscall arguments from pt_regs before calling the syscall handler. On C-SKY ABIv2, the 5th and 6th syscall arguments are prepared as stack arguments before invoking syscallid.
The current code adjusts sp before loading LSAVE_A4 and LSAVE_A5. Since those offsets are relative to the original pt_regs base, loading them after changing sp fetches the wrong slots. As a result, traced syscalls that use the 5th or 6th argument may receive corrupted arguments.
This is visible with mmap2(), which takes six arguments. A small PTRACE_SYSCALL reproducer opens a file and maps one page with:
mmap(NULL, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0)
Before the fix, the traced child fails the mmap and exits with 12. After the fix, the mapping succeeds and the child exits with 0.
Fix the trace path by loading a4/a5 from pt_regs before changing sp.
Tested on: ck860f, linux-4.19.15, C-SKY abiv2
--- arch/csky/kernel/entry.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/csky/kernel/entry.S +3 -3
@@ -93,11 +93,11 @@ csky_syscall_trace: ldw a2, (sp, LSAVE_A2) ldw a3, (sp, LSAVE_A3) #if defined(__CSKYABIV2__) - subi sp, 8 ldw r9, (sp, LSAVE_A4) + ldw r10, (sp, LSAVE_A5) + subi sp, 8 stw r9, (sp, 0x0) - ldw r9, (sp, LSAVE_A5) - stw r9, (sp, 0x4) + stw r10, (sp, 0x4) jsr syscallid /* Do system call */ addi sp, 8 #else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 628/1424 selftests/rseq: Replace glibc-specific __GNUC_PREREQ with portable check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hisam Mehboob <[email protected]>
[ Upstream commit d7b2769f8dba3e5f40d2a8a11988812d51160b17 ]
Building the rseq selftests against musl libc fails because musl's <features.h> does not provide the glibc-specific __GNUC_PREREQ macro:
error: missing binary operator before token '('
Replace __GNUC_PREREQ(11, 1) with an equivalent check using __GNUC__ and __GNUC_MINOR__ directly. This pattern is portable across all C library implementations and is already used elsewhere in the tools/ tree (e.g., tools/include/linux/string.h).
This also allows removing the #include <features.h>, which was only needed for __GNUC_PREREQ.
--- tools/testing/selftests/rseq/rseq-x86-thread-pointer.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
tools/testing/selftests/rseq/rseq-x86-thread-pointer.h +1 -3
@@ -8,13 +8,11 @@ #ifndef _RSEQ_X86_THREAD_POINTER #define _RSEQ_X86_THREAD_POINTER -#include <features.h> - #ifdef __cplusplus extern "C" { #endif -#if __GNUC_PREREQ (11, 1) +#if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 1) static inline void *rseq_thread_pointer(void) { return __builtin_thread_pointer();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 629/1424 platform/chrome: sensorhub: Fix memory overread in ring handler
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit d1ceb2b2324717fa30b44d56ef0c52813e239569 ]
max_response and sensor_num are read from different EC commands:
- max_response is from cros_ec_get_proto_info().
ec_dev->max_response = info->max_response_packet_size -
sizeof(struct ec_host_response);- sensor_num is from cros_ec_get_sensor_count().
sensor_num = cros_ec_get_sensor_count(ec);
With a malfunctioning EC firmware, it is possible that the msg->insize (i.e., fifo_info_length in the context) could be clamped in cros_ec_cmd_xfer() because msg->insize is greater than max_response.
int fifo_info_length =
sizeof(struct ec_response_motion_sense_fifo_info) + sizeof(u16) * sensorhub->sensor_num;
This means the number of read bytes could be less than expected. As a result, the subsequent memcpy() in cros_ec_sensorhub_ring_handler() overreads the resp->fifo_info buffer.
Check the return value of cros_ec_cmd_xfer_status() and abort if the number of bytes read does not match the expected length.
--- drivers/platform/chrome/cros_ec_sensorhub_ring.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/platform/chrome/cros_ec_sensorhub_ring.c +8 -1
@@ -797,8 +797,15 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) sensorhub->msg->outsize =1 ; sensorhub->msg->insize = fifo_info_length; -if (cros_ec_cmd_xfer_status (ec->ec_dev, sensorhub->msg) <0 ) + ret =cros_ec_cmd_xfer_status (ec->ec_dev, sensorhub->msg); +if (ret <0 ) + goto error; +if (ret != fifo_info_length) { +dev_warn_ratelimited (sensorhub->dev, +"Mismatch read length: size %d - expected %d\n" , + ret, fifo_info_length); goto error; + }memcpy (fifo_info, &sensorhub->resp->fifo_info, fifo_info_length);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 630/1424 wifi: rtw89: fix HE extended capability length check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 2aba608a86e9b099c9af2ea70b620552dee2b628 ]
rtw89_mac_check_he_obss_narrow_bw_ru_iter() reads extended capability byte 10, but rejects only datalen values below 10. Byte 10 requires at least 11 bytes.
Require datalen >= 11 before reading data[10].
--- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/realtek/rtw89/mac.c +1 -1
@@ -4223,7 +4223,7 @@ static void rtw89_mac_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, elem =cfg80211_find_elem (WLAN_EID_EXT_CAPABILITY , ies->data, ies->len); -if (!elem || elem->datalen <10 || +if (!elem || elem->datalen <11 || !(elem->data[10 ] &WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT )) *tolerated = false;rcu_read_unlock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 631/1424 perf cs-etm: Fix incorrect or missing decoder for raw trace
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Besar Wicaksono <[email protected]>
[ Upstream commit a16afcc58a8c5ebc65c852faf001f8f61f05e4ef ]
The decoder creation for raw trace uses metadata from the first CPU. On per-cpu mode, this metadata is incorrectly used for every decoder. On per-process/per-thread traces, the first CPU is CPU0. If CPU0 trace is not enabled, its metadata will be marked unused and the decoder is not created. Perf report dump skips the decoding part because the decoder is missing.
To fix this, use metadata of the CPU associated with sample object.
Stable-dep-of: 50cd0d54f1f6 ("perf cs-etm: Fix thread leaks on trace queue init failure")
--- tools/perf/util/cs-etm.c | 106 ++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 41 deletions(-)
tools/perf/util/cs-etm.c +65 -41
@@ -283,22 +283,31 @@ static int cs_etm__metadata_set_trace_id(u8 trace_chan_id, u64 *cpu_metadata) }/* -* Get a metadata for a specific cpu from an array. +* Get a metadata index for a specific cpu from an array. * */ -static u64 *get_cpu_data (struct cs_etm_auxtrace *etm,int cpu) +static int get_cpu_data_idx (struct cs_etm_auxtrace *etm,int cpu) {int i; -u64 *metadata =NULL ;for (i =0 ; i < etm->num_cpu; i++) {if (etm->metadata[i][CS_ETM_CPU ] == (u64 )cpu) { - metadata = etm->metadata[i]; -break ; +return i; } } -return metadata; +return -1 ; +} + +/* +* Get a metadata for a specific cpu from an array. +* +*/ +static u64 *get_cpu_data (struct cs_etm_auxtrace *etm,int cpu) +{ +int idx =get_cpu_data_idx (etm, cpu); + +return (idx !=-1 ) ? etm->metadata[idx] :NULL ; }/*
@@ -641,66 +650,80 @@ static void cs_etm__packet_dump(const char *pkt_string) }static void cs_etm__set_trace_param_etmv3 (struct cs_etm_trace_params *t_params, -struct cs_etm_auxtrace *etm,int idx, -u32 etmidr) +struct cs_etm_auxtrace *etm,int t_idx, +int m_idx,u32 etmidr) {u64 **metadata = etm->metadata; - t_params[idx].protocol =cs_etm__get_v7_protocol_version (etmidr); - t_params[idx].etmv3.reg_ctrl = metadata[idx][CS_ETM_ETMCR ]; - t_params[idx].etmv3.reg_trc_id = metadata[idx][CS_ETM_ETMTRACEIDR ]; + t_params[t_idx].protocol =cs_etm__get_v7_protocol_version (etmidr); + t_params[t_idx].etmv3.reg_ctrl = metadata[m_idx][CS_ETM_ETMCR ]; + t_params[t_idx].etmv3.reg_trc_id = metadata[m_idx][CS_ETM_ETMTRACEIDR ]; }static void cs_etm__set_trace_param_etmv4 (struct cs_etm_trace_params *t_params, -struct cs_etm_auxtrace *etm,int idx) +struct cs_etm_auxtrace *etm,int t_idx, +int m_idx) {u64 **metadata = etm->metadata; - t_params[idx].protocol = CS_ETM_PROTO_ETMV4i; - t_params[idx].etmv4.reg_idr0 = metadata[idx][CS_ETMV4_TRCIDR0 ]; - t_params[idx].etmv4.reg_idr1 = metadata[idx][CS_ETMV4_TRCIDR1 ]; - t_params[idx].etmv4.reg_idr2 = metadata[idx][CS_ETMV4_TRCIDR2 ]; - t_params[idx].etmv4.reg_idr8 = metadata[idx][CS_ETMV4_TRCIDR8 ]; - t_params[idx].etmv4.reg_configr = metadata[idx][CS_ETMV4_TRCCONFIGR ]; - t_params[idx].etmv4.reg_traceidr = metadata[idx][CS_ETMV4_TRCTRACEIDR ]; + t_params[t_idx].protocol = CS_ETM_PROTO_ETMV4i; + t_params[t_idx].etmv4.reg_idr0 = metadata[m_idx][CS_ETMV4_TRCIDR0 ]; + t_params[t_idx].etmv4.reg_idr1 = metadata[m_idx][CS_ETMV4_TRCIDR1 ]; + t_params[t_idx].etmv4.reg_idr2 = metadata[m_idx][CS_ETMV4_TRCIDR2 ]; + t_params[t_idx].etmv4.reg_idr8 = metadata[m_idx][CS_ETMV4_TRCIDR8 ]; + t_params[t_idx].etmv4.reg_configr = metadata[m_idx][CS_ETMV4_TRCCONFIGR ]; + t_params[t_idx].etmv4.reg_traceidr = metadata[m_idx][CS_ETMV4_TRCTRACEIDR ]; }static void cs_etm__set_trace_param_ete (struct cs_etm_trace_params *t_params, -struct cs_etm_auxtrace *etm,int idx) +struct cs_etm_auxtrace *etm,int t_idx, +int m_idx) {u64 **metadata = etm->metadata; - t_params[idx].protocol =CS_ETM_PROTO_ETE ; - t_params[idx].ete.reg_idr0 = metadata[idx][CS_ETE_TRCIDR0 ]; - t_params[idx].ete.reg_idr1 = metadata[idx][CS_ETE_TRCIDR1 ]; - t_params[idx].ete.reg_idr2 = metadata[idx][CS_ETE_TRCIDR2 ]; - t_params[idx].ete.reg_idr8 = metadata[idx][CS_ETE_TRCIDR8 ]; - t_params[idx].ete.reg_configr = metadata[idx][CS_ETE_TRCCONFIGR ]; - t_params[idx].ete.reg_traceidr = metadata[idx][CS_ETE_TRCTRACEIDR ]; - t_params[idx].ete.reg_devarch = metadata[idx][CS_ETE_TRCDEVARCH ]; + t_params[t_idx].protocol =CS_ETM_PROTO_ETE ; + t_params[t_idx].ete.reg_idr0 = metadata[m_idx][CS_ETE_TRCIDR0 ]; + t_params[t_idx].ete.reg_idr1 = metadata[m_idx][CS_ETE_TRCIDR1 ]; + t_params[t_idx].ete.reg_idr2 = metadata[m_idx][CS_ETE_TRCIDR2 ]; + t_params[t_idx].ete.reg_idr8 = metadata[m_idx][CS_ETE_TRCIDR8 ]; + t_params[t_idx].ete.reg_configr = metadata[m_idx][CS_ETE_TRCCONFIGR ]; + t_params[t_idx].ete.reg_traceidr = metadata[m_idx][CS_ETE_TRCTRACEIDR ]; + t_params[t_idx].ete.reg_devarch = metadata[m_idx][CS_ETE_TRCDEVARCH ]; }static int cs_etm__init_trace_params (struct cs_etm_trace_params *t_params,struct cs_etm_auxtrace *etm, +bool formatted, +int sample_cpu,int decoders) { -int i; +int t_idx, m_idx;u32 etmidr;u64 architecture; -for (i =0 ; i < decoders; i++) { - architecture = etm->metadata[i][CS_ETM_MAGIC ]; +for (t_idx =0 ; t_idx < decoders; t_idx++) { +if (formatted) + m_idx = t_idx; +else { + m_idx =get_cpu_data_idx (etm, sample_cpu); +if (m_idx ==-1 ) { +pr_warning ("CS_ETM: unknown CPU, falling back to first metadata\n" ); + m_idx =0 ; + } + } + + architecture = etm->metadata[m_idx][CS_ETM_MAGIC ];switch (architecture) {case __perf_cs_etmv3_magic: - etmidr = etm->metadata[i][CS_ETM_ETMIDR ]; -cs_etm__set_trace_param_etmv3 (t_params, etm, i, etmidr); + etmidr = etm->metadata[m_idx][CS_ETM_ETMIDR ]; +cs_etm__set_trace_param_etmv3 (t_params, etm, t_idx, m_idx, etmidr);break ;case __perf_cs_etmv4_magic: -cs_etm__set_trace_param_etmv4 (t_params, etm, i); +cs_etm__set_trace_param_etmv4 (t_params, etm, t_idx, m_idx);break ;case __perf_cs_ete_magic: -cs_etm__set_trace_param_ete (t_params, etm, i); +cs_etm__set_trace_param_ete (t_params, etm, t_idx, m_idx);break ;default :return -EINVAL ;
@@ -1016,7 +1039,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, }static struct cs_etm_queue *cs_etm__alloc_queue (struct cs_etm_auxtrace *etm, -bool formatted) +bool formatted,int sample_cpu) {struct cs_etm_decoder_params d_params;struct cs_etm_trace_params *t_params =NULL ;
@@ -1041,7 +1064,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,if (!t_params) goto out_free; -if (cs_etm__init_trace_params (t_params, etm, decoders)) +if (cs_etm__init_trace_params (t_params, etm, formatted, sample_cpu, decoders)) goto out_free;/* Set decoder parameters to decode trace packets */
@@ -1081,14 +1104,15 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,static int cs_etm__setup_queue (struct cs_etm_auxtrace *etm,struct auxtrace_queue *queue,unsigned int queue_nr, -bool formatted) +bool formatted, +int sample_cpu) {struct cs_etm_queue *etmq = queue->priv;if (list_empty (&queue->head) || etmq)return 0 ; - etmq =cs_etm__alloc_queue (etm, formatted); + etmq =cs_etm__alloc_queue (etm, formatted, sample_cpu);if (!etmq)return -ENOMEM ;
@@ -2827,7 +2851,7 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,* formatted in piped mode (true). */ err =cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, true); + idx, true,-1 );if (err)return err;
@@ -3033,7 +3057,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o idx = auxtrace_event->idx; formatted = !(aux_event->flags &PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW );return cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, formatted); + idx, formatted, sample->cpu); }/* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 632/1424 perf cs-etm: Create decoders after both AUX and HW_ID search passes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit b6aa0de9a53a231eb068ce1e62b5e7ec9e30e627 ]
Both of these passes gather information about how to create the decoders. AUX records determine formatted/unformatted, and the HW_IDs determine the traceID/metadata mappings.
Therefore it makes sense to cache the information and wait until both passes are over until creating the decoders, rather than creating them at the first HW_ID found.
This will allow a simplification of the creation process where cs_etm_queue->traceid_list will exclusively used to create the decoders, rather than the current two methods depending on whether the trace is formatted or not.
Previously the sample CPU from the AUX record was used to initialize the decoder CPU, but actually sample CPU == AUX queue index in per-CPU mode, so saving the sample CPU isn't required.
Similarly formatted/unformatted was used upfront to create the decoders, but now it's cached until later.
Stable-dep-of: 50cd0d54f1f6 ("perf cs-etm: Fix thread leaks on trace queue init failure")
--- tools/perf/util/cs-etm.c | 182 ++++++++++++++++++++++++--------------- 1 file changed, 113 insertions(+), 69 deletions(-)
tools/perf/util/cs-etm.c +113 -69
@@ -97,12 +97,19 @@ struct cs_etm_traceid_queue {struct cs_etm_packet_queue packet_queue; }; +enum cs_etm_format { +UNSET , +FORMATTED , +UNFORMATTED +}; +struct cs_etm_queue {struct cs_etm_auxtrace *etm;struct cs_etm_decoder *decoder;struct auxtrace_buffer *buffer;unsigned int queue_nr;u8 pending_timestamp_chan_id; +enum cs_etm_format format;u64 offset;const unsigned char *buf;size_t buf_len, buf_used;
@@ -693,7 +700,7 @@ static void cs_etm__set_trace_param_ete(struct cs_etm_trace_params *t_params,static int cs_etm__init_trace_params (struct cs_etm_trace_params *t_params,struct cs_etm_auxtrace *etm, -bool formatted, +enum cs_etm_format format,int sample_cpu,int decoders) {
@@ -702,7 +709,7 @@ static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,u64 architecture;for (t_idx =0 ; t_idx < decoders; t_idx++) { -if (formatted) +if (format ==FORMATTED ) m_idx = t_idx;else { m_idx =get_cpu_data_idx (etm, sample_cpu);
@@ -735,8 +742,7 @@ static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,static int cs_etm__init_decoder_params (struct cs_etm_decoder_params *d_params,struct cs_etm_queue *etmq, -enum cs_etm_decoder_operation mode, -bool formatted) +enum cs_etm_decoder_operation mode) {int ret = -EINVAL ;
@@ -746,7 +752,7 @@ static int cs_etm__init_decoder_params(struct cs_etm_decoder_params *d_params, d_params->packet_printer = cs_etm__packet_dump; d_params->operation = mode; d_params->data = etmq; - d_params->formatted = formatted; + d_params->formatted = etmq->format ==FORMATTED ; d_params->fsyncs = false; d_params->hsyncs = false; d_params->frame_aligned = true;
@@ -1038,81 +1044,34 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,return ret; } -static struct cs_etm_queue *cs_etm__alloc_queue (struct cs_etm_auxtrace *etm, -bool formatted,int sample_cpu) +static struct cs_etm_queue *cs_etm__alloc_queue (void ) { -struct cs_etm_decoder_params d_params; -struct cs_etm_trace_params *t_params =NULL ; -struct cs_etm_queue *etmq; -/* -* Each queue can only contain data from one CPU when unformatted, so only one decoder is -* needed. -*/ -int decoders = formatted ? etm->num_cpu :1 ; - - etmq =zalloc (sizeof (*etmq)); +struct cs_etm_queue *etmq =zalloc (sizeof (*etmq));if (!etmq)return NULL ; etmq->traceid_queues_list =intlist__new (NULL );if (!etmq->traceid_queues_list) - goto out_free; - -/* Use metadata to fill in trace parameters for trace decoder */ - t_params =zalloc (sizeof (*t_params) * decoders); - -if (!t_params) - goto out_free; - -if (cs_etm__init_trace_params (t_params, etm, formatted, sample_cpu, decoders)) - goto out_free; - -/* Set decoder parameters to decode trace packets */ -if (cs_etm__init_decoder_params (&d_params, etmq, - dump_trace ?CS_ETM_OPERATION_PRINT : -CS_ETM_OPERATION_DECODE , - formatted)) - goto out_free; - - etmq->decoder =cs_etm_decoder__new (decoders, &d_params, - t_params); - -if (!etmq->decoder) - goto out_free; - -/* -* Register a function to handle all memory accesses required by -* the trace decoder library. -*/ -if (cs_etm_decoder__add_mem_access_cb (etmq->decoder, -0x0L , ((u64) -1L ), - cs_etm__mem_access)) - goto out_free_decoder; +free (etmq); -zfree (&t_params);return etmq; - -out_free_decoder: -cs_etm_decoder__free (etmq->decoder); -out_free: -intlist__delete (etmq->traceid_queues_list); -free (etmq); - -return NULL ; }static int cs_etm__setup_queue (struct cs_etm_auxtrace *etm,struct auxtrace_queue *queue, -unsigned int queue_nr, -bool formatted, -int sample_cpu) +unsigned int queue_nr,enum cs_etm_format format) {struct cs_etm_queue *etmq = queue->priv; +if (etmq && format != etmq->format) { +pr_err ("CS_ETM: mixed formatted and unformatted trace not supported\n" ); +return -EINVAL ; + } +if (list_empty (&queue->head) || etmq)return 0 ; - etmq =cs_etm__alloc_queue (etm, formatted, sample_cpu); + etmq =cs_etm__alloc_queue ();if (!etmq)return -ENOMEM ;
@@ -1120,7 +1079,9 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm, queue->priv = etmq; etmq->etm = etm; etmq->queue_nr = queue_nr; + queue->cpu = queue_nr;/* Placeholder, may be reset to -1 in per-thread mode */ etmq->offset =0 ; + etmq->format = format;return 0 ; }
@@ -2851,7 +2812,7 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,* formatted in piped mode (true). */ err =cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, true,-1 ); + idx,FORMATTED );if (err)return err;
@@ -2972,7 +2933,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_ounion perf_event auxtrace_fragment;__u64 aux_offset, aux_size;__u32 idx; -bool formatted; +enum cs_etm_format format; struct cs_etm_auxtrace *etm = container_of(session->auxtrace, struct cs_etm_auxtrace,
@@ -3055,9 +3016,10 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_oreturn err; idx = auxtrace_event->idx; - formatted = !(aux_event->flags &PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW ); -return cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, formatted, sample->cpu); + format = (aux_event->flags &PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW ) ? +UNFORMATTED :FORMATTED ; + +return cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], idx, format); }/* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
@@ -3241,6 +3203,84 @@ static int cs_etm__clear_unused_trace_ids_metadata(int num_cpu, u64 **metadata)return 0 ; } +/* +* Use the data gathered by the peeks for HW_ID (trace ID mappings) and AUX +* (formatted or not) packets to create the decoders. +*/ +static int cs_etm__create_queue_decoders (struct cs_etm_queue *etmq) +{ +struct cs_etm_decoder_params d_params; + +/* +* Each queue can only contain data from one CPU when unformatted, so only one decoder is +* needed. +*/ +int decoders = etmq->format ==FORMATTED ? etmq->etm->num_cpu :1 ; + +/* Use metadata to fill in trace parameters for trace decoder */ +struct cs_etm_trace_params *t_params =zalloc (sizeof (*t_params) * decoders); + +if (!t_params) + goto out_free; + +if (cs_etm__init_trace_params (t_params, etmq->etm, etmq->format, + etmq->queue_nr, decoders)) + goto out_free; + +/* Set decoder parameters to decode trace packets */ +if (cs_etm__init_decoder_params (&d_params, etmq, + dump_trace ?CS_ETM_OPERATION_PRINT : +CS_ETM_OPERATION_DECODE )) + goto out_free; + + etmq->decoder =cs_etm_decoder__new (decoders, &d_params, + t_params); + +if (!etmq->decoder) + goto out_free; + +/* +* Register a function to handle all memory accesses required by +* the trace decoder library. +*/ +if (cs_etm_decoder__add_mem_access_cb (etmq->decoder, +0x0L , ((u64) -1L ), + cs_etm__mem_access)) + goto out_free_decoder; + +zfree (&t_params); +return 0 ; + +out_free_decoder: +cs_etm_decoder__free (etmq->decoder); +out_free: +zfree (&t_params); +return -EINVAL ; +} + +static int cs_etm__create_decoders (struct cs_etm_auxtrace *etm) +{ +struct auxtrace_queues *queues = &etm->queues; + +for (unsigned int i =0 ; i < queues->nr_queues; i++) { +bool empty =list_empty (&queues->queue_array[i].head); +struct cs_etm_queue *etmq = queues->queue_array[i].priv; +int ret; + +/* +* Don't create decoders for empty queues, mainly because +* etmq->format is unknown for empty queues. +*/ +if (empty) +continue ; + + ret =cs_etm__create_queue_decoders (etmq); +if (ret) +return ret; + } +return 0 ; +} +int cs_etm__process_auxtrace_info_full (union perf_event *event,struct perf_session *session) {
@@ -3389,6 +3429,10 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,if (err) goto err_free_queues; + err =cs_etm__queue_aux_records (session); +if (err) + goto err_free_queues; +/* * Map Trace ID values to CPU metadata. *
@@ -3411,7 +3455,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,* flags if present. */ -/* first scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */ +/* Scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */ aux_hw_id_found =0 ; err = perf_session__peek_events(session, session->header.data_offset, session->header.data_size,
@@ -3429,7 +3473,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,if (err) goto err_free_queues; - err =cs_etm__queue_aux_records (session); + err =cs_etm__create_decoders (etm);if (err) goto err_free_queues;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 633/1424 perf cs-etm: Queue context packets for frontend
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 68ca50bc0fa64841cd73b8a1538df1d7f7eb4108 ]
PE_CONTEXT elements update the context ID and exception level, but the decoder may still have prior packets cached for frontend processing. Updating the context immediately in the decoder backend can make those cached packets get consumed with the wrong thread or EL state.
Add a CS_ETM_CONTEXT packet carrying the TID and EL to the frontend, this keeps context changes ordered with the rest of the packet stream and avoids mismatches when synthesizing samples from cached packets.
Separate the memory access function into one for the frontend and one for decoding. The frontend also needs memory access to attach the instruction to samples. Because the frontend does memory access for both previous and current packets, change all the frontend memory access function signatures to take both a tidq and packet. But backend always uses the current backend EL and thread from the tidq.
Treat context packets as a boundary for branch sample generation and remove tidq->prev_packet_thread because it's not possible to branch to a different thread, so only tracking the current thread is required for sample generation.
Stable-dep-of: 50cd0d54f1f6 ("perf cs-etm: Fix thread leaks on trace queue init failure")
--- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 21 +- tools/perf/util/cs-etm.c | 236 +++++++++++------- tools/perf/util/cs-etm.h | 8 +- 3 files changed, 163 insertions(+), 102 deletions(-)
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +16 -5
@@ -398,6 +398,8 @@ cs_etm_decoder__buffer_packet(struct cs_etm_packet_queue *packet_queue, packet_queue->packet_buffer[et].flags =0 ; packet_queue->packet_buffer[et].exception_number =UINT32_MAX ; packet_queue->packet_buffer[et].trace_chan_id = trace_chan_id; + packet_queue->packet_buffer[et].el = ocsd_EL_unknown; + packet_queue->packet_buffer[et].tid =-1 ;if (packet_queue->packet_count ==CS_ETM_PACKET_MAX_BUFFER -1 )return OCSD_RESP_WAIT ;
@@ -445,6 +447,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_queue *etmq, packet->last_instr_type = elem->last_i_type; packet->last_instr_subtype = elem->last_i_subtype; packet->last_instr_cond = elem->last_instr_cond; + packet->el = elem->context.exception_level;if (elem->last_i_type ==OCSD_INSTR_BR || elem->last_i_type ==OCSD_INSTR_BR_INDIRECT ) packet->last_instr_taken_branch = elem->last_instr_exec;
@@ -518,7 +521,9 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,const ocsd_generic_trace_elem *elem, const uint8_t trace_chan_id) { + struct cs_etm_packet *packet;pid_t tid =-1 ; +int ret;/* * Process the PE_CONTEXT packets if we have a valid contextID or VMID.
@@ -539,12 +544,18 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,break ; } -if (cs_etm__etmq_set_tid_el (etmq, tid, trace_chan_id, - elem->context.exception_level)) +if (cs_etm__etmq_update_decode_context (etmq, trace_chan_id, + elem->context.exception_level, tid))return OCSD_RESP_FATAL_SYS_ERR ; -if (tid ==-1 ) -return OCSD_RESP_CONT ; + ret =cs_etm_decoder__buffer_packet (etmq, packet_queue, trace_chan_id, +CS_ETM_CONTEXT ); +if (ret !=OCSD_RESP_CONT && ret !=OCSD_RESP_WAIT ) +return ret; + + packet = &packet_queue->packet_buffer[packet_queue->tail]; + packet->tid = tid; + packet->el = elem->context.exception_level;/* * A timestamp is generated after a PE_CONTEXT element so make sure
@@ -552,7 +563,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,*/ cs_etm_decoder__reset_timestamp (packet_queue); -return OCSD_RESP_CONT ; +return ret; } static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
tools/perf/util/cs-etm.c +141 -95
533 lines not on this page · raw message
tools/perf/util/cs-etm.h +6 -2
@@ -158,6 +158,7 @@ enum cs_etm_sample_type {CS_ETM_DISCONTINUITY ,CS_ETM_EXCEPTION ,CS_ETM_EXCEPTION_RET , + CS_ETM_CONTEXT, }; enum cs_etm_isa {
@@ -184,6 +185,8 @@ struct cs_etm_packet {u8 last_instr_size;u8 trace_chan_id;int cpu; +int el; +pid_t tid; };#define CS_ETM_PACKET_MAX_BUFFER 1024
@@ -254,8 +257,9 @@ enum cs_etm_pid_fmt {#include <opencsd/ocsd_if_types.h> int cs_etm__get_cpu (u8 trace_chan_id,int *cpu);enum cs_etm_pid_fmt cs_etm__get_pid_fmt (struct cs_etm_queue *etmq); -int cs_etm__etmq_set_tid_el (struct cs_etm_queue *etmq,pid_t tid, -u8 trace_chan_id,ocsd_ex_level el); +int cs_etm__etmq_update_decode_context (struct cs_etm_queue *etmq, +u8 trace_chan_id,ocsd_ex_level el, +pid_t tid);bool cs_etm__etmq_is_timeless (struct cs_etm_queue *etmq);void cs_etm__etmq_set_traceid_queue_timestamp (struct cs_etm_queue *etmq,u8 trace_chan_id);
Signature · 1 line
2.53.0
PATCH 1/1 perf cs-etm: fix a compilation issue in cs_etm_decoder__set_tid()
When compiling coresight tool with the command:
make -C tools/perf CORESIGHT=1 all
The following build issue occurs:util/cs-etm-decoder/cs-etm-decoder.c:551:15: error: too many arguments to function 'cs_etm_decoder__buffer_packet'
551 | ret = cs_etm_decoder__buffer_packet(etmq, packet_queue,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fix this by removing the parameter "etmq" from function call to match its declaration:
cs_etm_decoder__buffer_packet(struct cs_etm_packet_queue *packet_queue,
const u8 trace_chan_id,
enum cs_etm_sample_type sample_type)
--- tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +1 -1
@@ -548,7 +548,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq, elem->context.exception_level, tid))return OCSD_RESP_FATAL_SYS_ERR ; - ret =cs_etm_decoder__buffer_packet (etmq, packet_queue, trace_chan_id, + ret =cs_etm_decoder__buffer_packet (packet_queue, trace_chan_id,CS_ETM_CONTEXT );if (ret !=OCSD_RESP_CONT && ret !=OCSD_RESP_WAIT )return ret;
Signature · 1 line
2.43.0
Re: [PATCH 6.6.y] perf cs-etm: fix a compilation issue in cs_etm_decoder__set_tid()
Quoted 26 lines · Valentin Caron
When compiling coresight tool with the command:
make -Ctools/perfCORESIGHT=1 allThe following build issue occurs:
util/cs-etm-decoder/cs-etm-decoder.c:551:15: error: too many arguments to function 'cs_etm_decoder__buffer_packet'
551 | ret = cs_etm_decoder__buffer_packet(etmq,packet_queue,| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~Fix this by removing the parameter "etmq" from function call to match its declaration:
cs_etm_decoder__buffer_packet(structcs_etm_packet_queue*packet_queue,
const u8trace_chan_id,
enumcs_etm_sample_typesample_type)Fixes 99d324594165 ("perf cs-etm: Queue context packets for frontend")Signed-off-by Valentin Caron <[email protected]>--- tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +0
-0
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c cs_etm_decoder__set_tid(struct cs_etm_queue *etmq, · line 554
Quoted 8 lines
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +1
-1@@ -548,7 +548,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq, elem->context.exception_level, tid))return OCSD_RESP_FATAL_SYS_ERR ; - ret =cs_etm_decoder__buffer_packet (etmq, packet_queue, trace_chan_id, + ret =cs_etm_decoder__buffer_packet (packet_queue, trace_chan_id,CS_ETM_CONTEXT );if (ret !=OCSD_RESP_CONT && ret !=OCSD_RESP_WAIT )return ret;
I tested Coresight decoding on the 6.6.y branch in case there was some other non-obvious dependency missing, but this is the only fix that's required. Thanks!
Re: [PATCH 6.6.y] perf cs-etm: fix a compilation issue in cs_etm_decoder__set_tid()
In reply to Valentin CaronQuoted 1 line
perf cs-etm: fix a compilation issue in
cs_etm_decoder__set_tid()
Queued for 6.6, thanks.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 634/1424 perf cs-etm: Fix thread leaks on trace queue init failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit 50cd0d54f1f6dd9b3de7c0ad101bd41d06206ace ]
cs_etm__init_traceid_queue() allocates the frontend and decode threads, if a later allocation fails, the error path does not drop thread reference that was already acquired.
Release both thread pointers with thread__zput() on the error path, so does not leak thread references or leave stale pointers behind.
--- tools/perf/util/cs-etm.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/util/cs-etm.c +4 -0
@@ -501,6 +501,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, queue->tid); tidq->decode_thread =machine__findnew_thread (&etm->session->machines.host,-1 , queue->tid); +if (!tidq->frontend_thread || !tidq->decode_thread) + goto out; tidq->packet =zalloc (sizeof (struct cs_etm_packet ));if (!tidq->packet)
@@ -535,6 +537,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,zfree (&tidq->prev_packet);zfree (&tidq->packet); out: +thread__zput (tidq->frontend_thread); +thread__zput (tidq->decode_thread);return rc; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 635/1424 perf/x86/amd/uncore: Refactor uncore management
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sandipan Das <[email protected]>
[ Upstream commit d6389d3ccc136a4229a8d497899c64f80fd3c5b3 ]
Since struct amd_uncore is used to manage per-cpu contexts, rename it to amd_uncore_ctx in order to better reflect its purpose. Add a new struct amd_uncore_pmu to encapsulate all attributes which are shared by per-cpu contexts for a corresponding PMU. These include the number of counters, active mask, MSR and RDPMC base addresses, etc. Since the struct pmu is now embedded, the corresponding amd_uncore_pmu for a given event can be found by simply using container_of().
Finally, move all PMU-specific code to separate functions. While the original event management functions continue to provide the base functionality, all PMU-specific quirks and customizations are applied in separate functions.
The motivation is to simplify the management of uncore PMUs.
Stable-dep-of: edda9051e267 ("perf/x86/amd/uncore: Add group validation")
--- arch/x86/events/amd/uncore.c | 737 ++++++++++++++++++----------------- 1 file changed, 379 insertions(+), 358 deletions(-)
arch/x86/events/amd/uncore.c +379 -358
@@ -27,56 +27,41 @@#define COUNTER_SHIFT 16 +#define NUM_UNCORES_MAX 2/* DF (or NB) and L3 (or L2) */ +#define UNCORE_NAME_LEN 16 +#undef pr_fmt#define pr_fmt (fmt) "amd_uncore: " fmtstatic int pmu_version; -static int num_counters_llc; -static int num_counters_nb; -static bool l3_mask;static HLIST_HEAD (uncore_unused_list); -struct amd_uncore { +struct amd_uncore_ctx {int id;int refcnt;int cpu; -int num_counters; -int rdpmc_base; -u32 msr_base; -cpumask_t *active_mask; -struct pmu *pmu;struct perf_event **events;struct hlist_node node; }; -static struct amd_uncore *__percpu *amd_uncore_nb; -static struct amd_uncore *__percpu *amd_uncore_llc; - -static struct pmu amd_nb_pmu; -static struct pmu amd_llc_pmu; - -static cpumask_t amd_nb_active_mask; -static cpumask_t amd_llc_active_mask; - -static bool is_nb_event (struct perf_event *event) -{ -return event->pmu->type == amd_nb_pmu.type; -} +struct amd_uncore_pmu { +char name[UNCORE_NAME_LEN ]; +int num_counters; +int rdpmc_base; +u32 msr_base; +cpumask_t active_mask; +struct pmu pmu; +struct amd_uncore_ctx *__percpu *ctx; +int (*id)(unsigned int cpu); +}; -static bool is_llc_event (struct perf_event *event) -{ -return event->pmu->type == amd_llc_pmu.type; -} +static struct amd_uncore_pmu pmus[NUM_UNCORES_MAX ]; +static int num_pmus__read_mostly ; -static struct amd_uncore *event_to_amd_uncore (struct perf_event *event) +static struct amd_uncore_pmu *event_to_amd_uncore_pmu (struct perf_event *event) { -if (is_nb_event (event) && amd_uncore_nb) -return *per_cpu_ptr (amd_uncore_nb, event->cpu); -else if (is_llc_event (event) && amd_uncore_llc) -return *per_cpu_ptr (amd_uncore_llc, event->cpu); - -return NULL ; + return container_of(event->pmu, struct amd_uncore_pmu, pmu); }static void amd_uncore_read (struct perf_event *event)
@@ -118,7 +103,7 @@ static void amd_uncore_stop(struct perf_event *event, int flags) hwc->state |=PERF_HES_STOPPED ;if ((flags &PERF_EF_UPDATE ) && !(hwc->state &PERF_HES_UPTODATE )) { -amd_uncore_read (event); + event->pmu->read (event); hwc->state |=PERF_HES_UPTODATE ; } }
@@ -126,15 +111,16 @@ static void amd_uncore_stop(struct perf_event *event, int flags)static int amd_uncore_add (struct perf_event *event,int flags) {int i; -struct amd_uncore *uncore =event_to_amd_uncore (event); +struct amd_uncore_pmu *pmu =event_to_amd_uncore_pmu (event); +struct amd_uncore_ctx *ctx = *per_cpu_ptr (pmu->ctx, event->cpu);struct hw_perf_event *hwc = &event->hw;/* are we already assigned? */ -if (hwc->idx !=-1 && uncore->events[hwc->idx] == event) +if (hwc->idx !=-1 && ctx->events[hwc->idx] == event) goto out; -for (i =0 ; i < uncore->num_counters; i++) { -if (uncore->events[i] == event) { +for (i =0 ; i < pmu->num_counters; i++) { +if (ctx->events[i] == event) { hwc->idx = i; goto out; }
@@ -142,8 +128,8 @@ static int amd_uncore_add(struct perf_event *event, int flags)/* if not, take the first available counter */ hwc->idx =-1 ; -for (i =0 ; i < uncore->num_counters; i++) { -if (cmpxchg (&uncore->events[i],NULL , event) ==NULL ) { +for (i =0 ; i < pmu->num_counters; i++) { +if (cmpxchg (&ctx->events[i],NULL , event) ==NULL ) { hwc->idx = i;break ; }
@@ -153,23 +139,13 @@ static int amd_uncore_add(struct perf_event *event, int flags)if (hwc->idx ==-1 )return -EBUSY ; - hwc->config_base = uncore->msr_base + (2 * hwc->idx); - hwc->event_base = uncore->msr_base +1 + (2 * hwc->idx); - hwc->event_base_rdpmc = uncore->rdpmc_base + hwc->idx; + hwc->config_base = pmu->msr_base + (2 * hwc->idx); + hwc->event_base = pmu->msr_base +1 + (2 * hwc->idx); + hwc->event_base_rdpmc = pmu->rdpmc_base + hwc->idx; hwc->state =PERF_HES_UPTODATE |PERF_HES_STOPPED ; -/* -* The first four DF counters are accessible via RDPMC index 6 to 9 -* followed by the L3 counters from index 10 to 15. For processors -* with more than four DF counters, the DF RDPMC assignments become -* discontiguous as the additional counters are accessible starting -* from index 16. -*/ -if (is_nb_event (event) && hwc->idx >=NUM_COUNTERS_NB ) - hwc->event_base_rdpmc +=NUM_COUNTERS_L3 ; -if (flags &PERF_EF_START ) -amd_uncore_start (event,PERF_EF_RELOAD ); + event->pmu->start (event,PERF_EF_RELOAD );return 0 ; }
@@ -177,55 +153,36 @@ static int amd_uncore_add(struct perf_event *event, int flags)static void amd_uncore_del (struct perf_event *event,int flags) {int i; -struct amd_uncore *uncore =event_to_amd_uncore (event); +struct amd_uncore_pmu *pmu =event_to_amd_uncore_pmu (event); +struct amd_uncore_ctx *ctx = *per_cpu_ptr (pmu->ctx, event->cpu);struct hw_perf_event *hwc = &event->hw; -amd_uncore_stop (event,PERF_EF_UPDATE ); + event->pmu->stop (event,PERF_EF_UPDATE ); -for (i =0 ; i < uncore->num_counters; i++) { -if (cmpxchg (&uncore->events[i], event,NULL ) == event) +for (i =0 ; i < pmu->num_counters; i++) { +if (cmpxchg (&ctx->events[i], event,NULL ) == event)break ; } hwc->idx =-1 ; } -/* -* Return a full thread and slice mask unless user -* has provided them -*/ -static u64 l3_thread_slice_mask (u64 config) -{ -if (boot_cpu_data.x86 <=0x18 ) -return ((config &AMD64_L3_SLICE_MASK ) ? :AMD64_L3_SLICE_MASK ) | - ((config &AMD64_L3_THREAD_MASK ) ? :AMD64_L3_THREAD_MASK ); - -/* -* If the user doesn't specify a threadmask, they're not trying to -* count core 0, so we enable all cores & threads. -* We'll also assume that they want to count slice 0 if they specify -* a threadmask and leave sliceid and enallslices unpopulated. -*/ -if (!(config &AMD64_L3_F19H_THREAD_MASK )) -return AMD64_L3_F19H_THREAD_MASK |AMD64_L3_EN_ALL_SLICES | -AMD64_L3_EN_ALL_CORES ; - -return config & (AMD64_L3_F19H_THREAD_MASK |AMD64_L3_SLICEID_MASK | -AMD64_L3_EN_ALL_CORES |AMD64_L3_EN_ALL_SLICES | -AMD64_L3_COREID_MASK ); -} -static int amd_uncore_event_init (struct perf_event *event) { -struct amd_uncore *uncore; +struct amd_uncore_pmu *pmu; +struct amd_uncore_ctx *ctx;struct hw_perf_event *hwc = &event->hw; -u64 event_mask =AMD64_RAW_EVENT_MASK_NB ;if (event->attr.type != event->pmu->type)return -ENOENT ; -if (pmu_version >=2 &&is_nb_event (event)) - event_mask =AMD64_PERFMON_V2_RAW_EVENT_MASK_NB ; +if (event->cpu <0 ) +return -EINVAL ; + + pmu =event_to_amd_uncore_pmu (event); + ctx = *per_cpu_ptr (pmu->ctx, event->cpu); +if (!ctx) +return -ENODEV ;/* * NB and Last level cache counters (MSRs) are shared across all cores
@@ -235,28 +192,14 @@ static int amd_uncore_event_init(struct perf_event *event)* out. So we do not support sampling and per-thread events via * CAP_NO_INTERRUPT, and we do not enable counter overflow interrupts: */ - hwc->config = event->attr.config & event_mask; + hwc->config = event->attr.config; hwc->idx =-1 ; -if (event->cpu <0 ) -return -EINVAL ; - -/* -* SliceMask and ThreadMask need to be set for certain L3 events. -* For other events, the two fields do not affect the count. -*/ -if (l3_mask &&is_llc_event (event)) - hwc->config |=l3_thread_slice_mask (event->attr.config); - - uncore =event_to_amd_uncore (event); -if (!uncore) -return -ENODEV ; -/* * since request can come in to any of the shared cores, we will remap * to a single common cpu. */ - event->cpu = uncore->cpu; + event->cpu = ctx->cpu;return 0 ; }
@@ -278,17 +221,10 @@ static ssize_t amd_uncore_attr_show_cpumask(struct device *dev,struct device_attribute *attr, char *buf) { - cpumask_t *active_mask; -struct pmu *pmu =dev_get_drvdata (dev); - -if (pmu->type == amd_nb_pmu.type) - active_mask = &amd_nb_active_mask; -else if (pmu->type == amd_llc_pmu.type) - active_mask = &amd_llc_active_mask; -else -return 0 ; + struct pmu *ptr = dev_get_drvdata(dev); + struct amd_uncore_pmu *pmu = container_of(ptr, struct amd_uncore_pmu, pmu); -return cpumap_print_to_pagebuf (true, buf, active_mask); +return cpumap_print_to_pagebuf (true, buf, &pmu->active_mask); } static DEVICE_ATTR(cpumask, S_IRUGO, amd_uncore_attr_show_cpumask, NULL);
@@ -396,113 +332,57 @@ static const struct attribute_group *amd_uncore_l3_attr_update[] = { NULL, }; -static struct pmu amd_nb_pmu = { - .task_ctx_nr = perf_invalid_context, - .attr_groups = amd_uncore_df_attr_groups, - .name ="amd_nb" , - .event_init = amd_uncore_event_init, - .add = amd_uncore_add, - .del = amd_uncore_del, - .start = amd_uncore_start, - .stop = amd_uncore_stop, - .read = amd_uncore_read, - .capabilities =PERF_PMU_CAP_NO_EXCLUDE |PERF_PMU_CAP_NO_INTERRUPT , - .module =THIS_MODULE , -}; - -static struct pmu amd_llc_pmu = { - .task_ctx_nr = perf_invalid_context, - .attr_groups = amd_uncore_l3_attr_groups, - .attr_update = amd_uncore_l3_attr_update, - .name ="amd_l2" , - .event_init = amd_uncore_event_init, - .add = amd_uncore_add, - .del = amd_uncore_del, - .start = amd_uncore_start, - .stop = amd_uncore_stop, - .read = amd_uncore_read, - .capabilities =PERF_PMU_CAP_NO_EXCLUDE |PERF_PMU_CAP_NO_INTERRUPT , - .module =THIS_MODULE , -}; - -static struct amd_uncore *amd_uncore_alloc (unsigned int cpu) -{ -return kzalloc_node (sizeof (struct amd_uncore ),GFP_KERNEL , -cpu_to_node (cpu)); -} - -static inline struct perf_event ** -amd_uncore_events_alloc (unsigned int num,unsigned int cpu) -{ -return kzalloc_node (sizeof (struct perf_event *) * num,GFP_KERNEL , -cpu_to_node (cpu)); -} -static int amd_uncore_cpu_up_prepare (unsigned int cpu) { -struct amd_uncore *uncore_nb =NULL , *uncore_llc =NULL ; - -if (amd_uncore_nb) { - *per_cpu_ptr (amd_uncore_nb, cpu) =NULL ; - uncore_nb =amd_uncore_alloc (cpu); -if (!uncore_nb) - goto fail; - uncore_nb->cpu = cpu; - uncore_nb->num_counters = num_counters_nb; - uncore_nb->rdpmc_base =RDPMC_BASE_NB ; - uncore_nb->msr_base =MSR_F15H_NB_PERF_CTL ; - uncore_nb->active_mask = &amd_nb_active_mask; - uncore_nb->pmu = &amd_nb_pmu; - uncore_nb->events =amd_uncore_events_alloc (num_counters_nb, cpu); -if (!uncore_nb->events) +struct amd_uncore_pmu *pmu; +struct amd_uncore_ctx *ctx; +int node =cpu_to_node (cpu), i; + +for (i =0 ; i < num_pmus; i++) { + pmu = &pmus[i]; + *per_cpu_ptr (pmu->ctx, cpu) =NULL ; + ctx =kzalloc_node (sizeof (struct amd_uncore_ctx ),GFP_KERNEL , + node); +if (!ctx) goto fail; - uncore_nb->id =-1 ; - *per_cpu_ptr (amd_uncore_nb, cpu) = uncore_nb; - } -if (amd_uncore_llc) { - *per_cpu_ptr (amd_uncore_llc, cpu) =NULL ; - uncore_llc =amd_uncore_alloc (cpu); -if (!uncore_llc) - goto fail; - uncore_llc->cpu = cpu; - uncore_llc->num_counters = num_counters_llc; - uncore_llc->rdpmc_base =RDPMC_BASE_LLC ; - uncore_llc->msr_base =MSR_F16H_L2I_PERF_CTL ; - uncore_llc->active_mask = &amd_llc_active_mask; - uncore_llc->pmu = &amd_llc_pmu; - uncore_llc->events =amd_uncore_events_alloc (num_counters_llc, cpu); -if (!uncore_llc->events) + ctx->cpu = cpu; + ctx->events =kzalloc_node (sizeof (struct perf_event *) * + pmu->num_counters,GFP_KERNEL , + node); +if (!ctx->events) goto fail; - uncore_llc->id =-1 ; - *per_cpu_ptr (amd_uncore_llc, cpu) = uncore_llc; + + ctx->id =-1 ; + *per_cpu_ptr (pmu->ctx, cpu) = ctx; }return 0 ; fail: -if (uncore_nb) { -kfree (uncore_nb->events); -kfree (uncore_nb); - } +/* Rollback */ +for (; i >=0 ; i--) { + pmu = &pmus[i]; + ctx = *per_cpu_ptr (pmu->ctx, cpu); +if (!ctx) +continue ; -if (uncore_llc) { -kfree (uncore_llc->events); -kfree (uncore_llc); +kfree (ctx->events); +kfree (ctx); }return -ENOMEM ; } -static struct amd_uncore * -amd_uncore_find_online_sibling (struct amd_uncore *this, -struct amd_uncore *__percpu *uncores) +static struct amd_uncore_ctx * +amd_uncore_find_online_sibling (struct amd_uncore_ctx *this, +struct amd_uncore_pmu *pmu) {unsigned int cpu; -struct amd_uncore *that; +struct amd_uncore_ctx *that;for_each_online_cpu (cpu) { - that = *per_cpu_ptr (uncores, cpu); + that = *per_cpu_ptr (pmu->ctx, cpu);if (!that)continue ;
@@ -523,24 +403,16 @@ amd_uncore_find_online_sibling(struct amd_uncore *this,static int amd_uncore_cpu_starting (unsigned int cpu) { -unsigned int eax, ebx, ecx, edx; -struct amd_uncore *uncore; - -if (amd_uncore_nb) { - uncore = *per_cpu_ptr (amd_uncore_nb, cpu); -cpuid (0x8000001e , &eax, &ebx, &ecx, &edx); - uncore->id = ecx &0xff ; - - uncore =amd_uncore_find_online_sibling (uncore, amd_uncore_nb); - *per_cpu_ptr (amd_uncore_nb, cpu) = uncore; - } - -if (amd_uncore_llc) { - uncore = *per_cpu_ptr (amd_uncore_llc, cpu); - uncore->id =get_llc_id (cpu); +struct amd_uncore_pmu *pmu; +struct amd_uncore_ctx *ctx; +int i; - uncore =amd_uncore_find_online_sibling (uncore, amd_uncore_llc); - *per_cpu_ptr (amd_uncore_llc, cpu) = uncore; +for (i =0 ; i < num_pmus; i++) { + pmu = &pmus[i]; + ctx = *per_cpu_ptr (pmu->ctx, cpu); + ctx->id = pmu->id (cpu); + ctx =amd_uncore_find_online_sibling (ctx, pmu); + *per_cpu_ptr (pmu->ctx, cpu) = ctx; }return 0 ;
@@ -548,195 +420,359 @@ static int amd_uncore_cpu_starting(unsigned int cpu)static void uncore_clean_online (void ) { -struct amd_uncore *uncore; +struct amd_uncore_ctx *ctx;struct hlist_node *n; -hlist_for_each_entry_safe (uncore, n, &uncore_unused_list, node) { -hlist_del (&uncore->node); -kfree (uncore->events); -kfree (uncore); +hlist_for_each_entry_safe (ctx, n, &uncore_unused_list, node) { +hlist_del (&ctx->node); +kfree (ctx->events); +kfree (ctx); } } -static void uncore_online (unsigned int cpu, -struct amd_uncore *__percpu *uncores) +static int amd_uncore_cpu_online (unsigned int cpu) { -struct amd_uncore *uncore = *per_cpu_ptr (uncores, cpu); +struct amd_uncore_pmu *pmu; +struct amd_uncore_ctx *ctx; +int i;uncore_clean_online (); -if (cpu == uncore->cpu) -cpumask_set_cpu (cpu, uncore->active_mask); +for (i =0 ; i < num_pmus; i++) { + pmu = &pmus[i]; + ctx = *per_cpu_ptr (pmu->ctx, cpu); +if (cpu == ctx->cpu) +cpumask_set_cpu (cpu, &pmu->active_mask); + } + +return 0 ; } -static int amd_uncore_cpu_online (unsigned int cpu) +static int amd_uncore_cpu_down_prepare (unsigned int cpu) { -if (amd_uncore_nb) -uncore_online (cpu, amd_uncore_nb); +struct amd_uncore_ctx *this, *that; +struct amd_uncore_pmu *pmu; +int i, j; + +for (i =0 ; i < num_pmus; i++) { + pmu = &pmus[i]; + this = *per_cpu_ptr (pmu->ctx, cpu); + +/* this cpu is going down, migrate to a shared sibling if possible */ +for_each_online_cpu (j) { + that = *per_cpu_ptr (pmu->ctx, j); + +if (cpu == j) +continue ; + +if (this == that) { +perf_pmu_migrate_context (&pmu->pmu, cpu, j); +cpumask_clear_cpu (cpu, &pmu->active_mask); +cpumask_set_cpu (j, &pmu->active_mask); + that->cpu = j; +break ; + } + } + } -if (amd_uncore_llc) -uncore_online (cpu, amd_uncore_llc); +return 0 ; +} + +static int amd_uncore_cpu_dead (unsigned int cpu) +{ +struct amd_uncore_ctx *ctx; +struct amd_uncore_pmu *pmu; +int i; + +for (i =0 ; i < num_pmus; i++) { + pmu = &pmus[i]; + ctx = *per_cpu_ptr (pmu->ctx, cpu); +if (cpu == ctx->cpu) +cpumask_clear_cpu (cpu, &pmu->active_mask); + +if (!--ctx->refcnt) { +kfree (ctx->events); +kfree (ctx); + } + + *per_cpu_ptr (pmu->ctx, cpu) =NULL ; + }return 0 ; } -static void uncore_down_prepare (unsigned int cpu, -struct amd_uncore *__percpu *uncores) +static int amd_uncore_df_id (unsigned int cpu) { -unsigned int i; -struct amd_uncore *this = *per_cpu_ptr (uncores, cpu); +unsigned int eax, ebx, ecx, edx; -if (this->cpu != cpu) -return ; +cpuid (0x8000001e , &eax, &ebx, &ecx, &edx); -/* this cpu is going down, migrate to a shared sibling if possible */ -for_each_online_cpu (i) { -struct amd_uncore *that = *per_cpu_ptr (uncores, i); +return ecx &0xff ; +} -if (cpu == i) -continue ; +static int amd_uncore_df_event_init (struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; +int ret =amd_uncore_event_init (event); -if (this == that) { -perf_pmu_migrate_context (this->pmu, cpu, i); -cpumask_clear_cpu (cpu, that->active_mask); -cpumask_set_cpu (i, that->active_mask); - that->cpu = i; -break ; - } - } +if (ret || pmu_version <2 ) +return ret; + + hwc->config = event->attr.config & + (pmu_version >=2 ?AMD64_PERFMON_V2_RAW_EVENT_MASK_NB : +AMD64_RAW_EVENT_MASK_NB ); + +return 0 ; } -static int amd_uncore_cpu_down_prepare (unsigned int cpu) +static int amd_uncore_df_add (struct perf_event *event,int flags) { -if (amd_uncore_nb) -uncore_down_prepare (cpu, amd_uncore_nb); +int ret =amd_uncore_add (event, flags & ~PERF_EF_START ); +struct hw_perf_event *hwc = &event->hw; + +if (ret) +return ret; + +/* +* The first four DF counters are accessible via RDPMC index 6 to 9 +* followed by the L3 counters from index 10 to 15. For processors +* with more than four DF counters, the DF RDPMC assignments become +* discontiguous as the additional counters are accessible starting +* from index 16. +*/ +if (hwc->idx >=NUM_COUNTERS_NB ) + hwc->event_base_rdpmc +=NUM_COUNTERS_L3 ; -if (amd_uncore_llc) -uncore_down_prepare (cpu, amd_uncore_llc); +/* Delayed start after rdpmc base update */ +if (flags &PERF_EF_START ) +amd_uncore_start (event,PERF_EF_RELOAD );return 0 ; } -static void uncore_dead (unsigned int cpu,struct amd_uncore *__percpu *uncores) +static int amd_uncore_df_init (void ) { -struct amd_uncore *uncore = *per_cpu_ptr (uncores, cpu); +struct attribute **df_attr = amd_uncore_df_format_attr; +struct amd_uncore_pmu *pmu = &pmus[num_pmus]; +union cpuid_0x80000022_ebx ebx; +int ret; -if (cpu == uncore->cpu) -cpumask_clear_cpu (cpu, uncore->active_mask); +if (!boot_cpu_has (X86_FEATURE_PERFCTR_NB )) +return 0 ; -if (!--uncore->refcnt) { -kfree (uncore->events); -kfree (uncore); +/* +* For Family 17h and above, the Northbridge counters are repurposed +* as Data Fabric counters. The PMUs are exported based on family as +* either NB or DF. +*/ +strscpy (pmu->name, boot_cpu_data.x86 >=0x17 ?"amd_df" :"amd_nb" , +sizeof (pmu->name)); + + pmu->num_counters =NUM_COUNTERS_NB ; + pmu->msr_base =MSR_F15H_NB_PERF_CTL ; + pmu->rdpmc_base =RDPMC_BASE_NB ; + pmu->id = amd_uncore_df_id; + +if (pmu_version >=2 ) { + *df_attr++ = &format_attr_event14v2.attr; + *df_attr++ = &format_attr_umask12.attr; + ebx.full =cpuid_ebx (EXT_PERFMON_DEBUG_FEATURES ); + pmu->num_counters = ebx.split.num_df_pmc; + }else if (boot_cpu_data.x86 >=0x17 ) { + *df_attr = &format_attr_event14.attr; + } + + pmu->ctx = alloc_percpu(struct amd_uncore_ctx *); +if (!pmu->ctx) +return -ENOMEM ; + + pmu->pmu = (struct pmu ) { + .task_ctx_nr = perf_invalid_context, + .attr_groups = amd_uncore_df_attr_groups, + .name = pmu->name, + .event_init = amd_uncore_df_event_init, + .add = amd_uncore_df_add, + .del = amd_uncore_del, + .start = amd_uncore_start, + .stop = amd_uncore_stop, + .read = amd_uncore_read, + .capabilities =PERF_PMU_CAP_NO_EXCLUDE |PERF_PMU_CAP_NO_INTERRUPT , + .module =THIS_MODULE , + }; + + ret =perf_pmu_register (&pmu->pmu, pmu->pmu.name,-1 ); +if (ret) { +free_percpu (pmu->ctx); + pmu->ctx =NULL ; +return ret; } - *per_cpu_ptr (uncores, cpu) =NULL ; +pr_info ("%d %s %s counters detected\n" , pmu->num_counters, + boot_cpu_data.x86_vendor ==X86_VENDOR_HYGON ?"HYGON" :"" , + pmu->pmu.name); + + num_pmus++; + +return 0 ; } -static int amd_uncore_cpu_dead (unsigned int cpu) +static int amd_uncore_l3_id (unsigned int cpu) { -if (amd_uncore_nb) -uncore_dead (cpu, amd_uncore_nb); +return get_llc_id (cpu); +} + +static int amd_uncore_l3_event_init (struct perf_event *event) +{ +int ret =amd_uncore_event_init (event); +struct hw_perf_event *hwc = &event->hw; +u64 config = event->attr.config; +u64 mask; + + hwc->config = config &AMD64_RAW_EVENT_MASK_NB ; + +/* +* SliceMask and ThreadMask need to be set for certain L3 events. +* For other events, the two fields do not affect the count. +*/ +if (ret || boot_cpu_data.x86 <0x17 ) +return ret; + + mask = config & (AMD64_L3_F19H_THREAD_MASK |AMD64_L3_SLICEID_MASK | +AMD64_L3_EN_ALL_CORES |AMD64_L3_EN_ALL_SLICES | +AMD64_L3_COREID_MASK ); + +if (boot_cpu_data.x86 <=0x18 ) + mask = ((config &AMD64_L3_SLICE_MASK ) ? :AMD64_L3_SLICE_MASK ) | + ((config &AMD64_L3_THREAD_MASK ) ? :AMD64_L3_THREAD_MASK ); + +/* +* If the user doesn't specify a ThreadMask, they're not trying to +* count core 0, so we enable all cores & threads. +* We'll also assume that they want to count slice 0 if they specify +* a ThreadMask and leave SliceId and EnAllSlices unpopulated. +*/ +else if (!(config &AMD64_L3_F19H_THREAD_MASK )) + mask =AMD64_L3_F19H_THREAD_MASK |AMD64_L3_EN_ALL_SLICES | +AMD64_L3_EN_ALL_CORES ; -if (amd_uncore_llc) -uncore_dead (cpu, amd_uncore_llc); + hwc->config |= mask;return 0 ; } -static int __init amd_uncore_init (void ) +static int amd_uncore_l3_init (void ) { -struct attribute **df_attr = amd_uncore_df_format_attr;struct attribute **l3_attr = amd_uncore_l3_format_attr; -union cpuid_0x80000022_ebx ebx; -int ret = -ENODEV ; +struct amd_uncore_pmu *pmu = &pmus[num_pmus]; +int ret; -if (boot_cpu_data.x86_vendor !=X86_VENDOR_AMD && - boot_cpu_data.x86_vendor !=X86_VENDOR_HYGON ) -return -ENODEV ; +if (!boot_cpu_has (X86_FEATURE_PERFCTR_LLC )) +return 0 ; -if (!boot_cpu_has (X86_FEATURE_TOPOEXT )) -return -ENODEV ; +/* +* For Family 17h and above, L3 cache counters are available instead +* of L2 cache counters. The PMUs are exported based on family as +* either L2 or L3. +*/ +strscpy (pmu->name, boot_cpu_data.x86 >=0x17 ?"amd_l3" :"amd_l2" , +sizeof (pmu->name)); -if (boot_cpu_has (X86_FEATURE_PERFMON_V2 )) - pmu_version =2 ; + pmu->num_counters =NUM_COUNTERS_L2 ; + pmu->msr_base =MSR_F16H_L2I_PERF_CTL ; + pmu->rdpmc_base =RDPMC_BASE_LLC ; + pmu->id = amd_uncore_l3_id; - num_counters_nb =NUM_COUNTERS_NB ; - num_counters_llc =NUM_COUNTERS_L2 ;if (boot_cpu_data.x86 >=0x17 ) { -/* -* For F17h and above, the Northbridge counters are -* repurposed as Data Fabric counters. Also, L3 -* counters are supported too. The PMUs are exported -* based on family as either L2 or L3 and NB or DF. -*/ - num_counters_llc =NUM_COUNTERS_L3 ; - amd_nb_pmu.name ="amd_df" ; - amd_llc_pmu.name ="amd_l3" ; - l3_mask = true; + *l3_attr++ = &format_attr_event8.attr; + *l3_attr++ = &format_attr_umask8.attr; + *l3_attr++ = boot_cpu_data.x86 >=0x19 ? + &format_attr_threadmask2.attr : + &format_attr_threadmask8.attr; + pmu->num_counters =NUM_COUNTERS_L3 ; } -if (boot_cpu_has (X86_FEATURE_PERFCTR_NB )) { -if (pmu_version >=2 ) { - *df_attr++ = &format_attr_event14v2.attr; - *df_attr++ = &format_attr_umask12.attr; - }else if (boot_cpu_data.x86 >=0x17 ) { - *df_attr = &format_attr_event14.attr; - } + pmu->ctx = alloc_percpu(struct amd_uncore_ctx *); +if (!pmu->ctx) +return -ENOMEM ; + + pmu->pmu = (struct pmu ) { + .task_ctx_nr = perf_invalid_context, + .attr_groups = amd_uncore_l3_attr_groups, + .attr_update = amd_uncore_l3_attr_update, + .name = pmu->name, + .event_init = amd_uncore_l3_event_init, + .add = amd_uncore_add, + .del = amd_uncore_del, + .start = amd_uncore_start, + .stop = amd_uncore_stop, + .read = amd_uncore_read, + .capabilities =PERF_PMU_CAP_NO_EXCLUDE |PERF_PMU_CAP_NO_INTERRUPT , + .module =THIS_MODULE , + }; + + ret =perf_pmu_register (&pmu->pmu, pmu->pmu.name,-1 ); +if (ret) { +free_percpu (pmu->ctx); + pmu->ctx =NULL ; +return ret; + } - amd_uncore_nb = alloc_percpu(struct amd_uncore *); -if (!amd_uncore_nb) { - ret = -ENOMEM ; - goto fail_nb; - } - ret =perf_pmu_register (&amd_nb_pmu, amd_nb_pmu.name,-1 ); -if (ret) - goto fail_nb; +pr_info ("%d %s %s counters detected\n" , pmu->num_counters, + boot_cpu_data.x86_vendor ==X86_VENDOR_HYGON ?"HYGON" :"" , + pmu->pmu.name); -if (pmu_version >=2 ) { - ebx.full =cpuid_ebx (EXT_PERFMON_DEBUG_FEATURES ); - num_counters_nb = ebx.split.num_df_pmc; - } + num_pmus++; -pr_info ("%d %s %s counters detected\n" , num_counters_nb, - boot_cpu_data.x86_vendor ==X86_VENDOR_HYGON ?"HYGON" :"" , - amd_nb_pmu.name); +return 0 ; +} - ret =0 ; - } +static void uncore_free (void ) +{ +struct amd_uncore_pmu *pmu; +int i; -if (boot_cpu_has (X86_FEATURE_PERFCTR_LLC )) { -if (boot_cpu_data.x86 >=0x19 ) { - *l3_attr++ = &format_attr_event8.attr; - *l3_attr++ = &format_attr_umask8.attr; - *l3_attr++ = &format_attr_threadmask2.attr; - }else if (boot_cpu_data.x86 >=0x17 ) { - *l3_attr++ = &format_attr_event8.attr; - *l3_attr++ = &format_attr_umask8.attr; - *l3_attr++ = &format_attr_threadmask8.attr; - } +for (i =0 ; i < num_pmus; i++) { + pmu = &pmus[i]; +if (!pmu->ctx) +continue ; - amd_uncore_llc = alloc_percpu(struct amd_uncore *); -if (!amd_uncore_llc) { - ret = -ENOMEM ; - goto fail_llc; - } - ret =perf_pmu_register (&amd_llc_pmu, amd_llc_pmu.name,-1 ); -if (ret) - goto fail_llc; - -pr_info ("%d %s %s counters detected\n" , num_counters_llc, - boot_cpu_data.x86_vendor ==X86_VENDOR_HYGON ?"HYGON" :"" , - amd_llc_pmu.name); - ret =0 ; +perf_pmu_unregister (&pmu->pmu); +free_percpu (pmu->ctx); + pmu->ctx =NULL ; } + num_pmus =0 ; +} + +static int __init amd_uncore_init (void ) +{ +int ret; + +if (boot_cpu_data.x86_vendor !=X86_VENDOR_AMD && + boot_cpu_data.x86_vendor !=X86_VENDOR_HYGON ) +return -ENODEV ; + +if (!boot_cpu_has (X86_FEATURE_TOPOEXT )) +return -ENODEV ; + +if (boot_cpu_has (X86_FEATURE_PERFMON_V2 )) + pmu_version =2 ; + + ret =amd_uncore_df_init (); +if (ret) + goto fail; + + ret =amd_uncore_l3_init (); +if (ret) + goto fail; +/* * Install callbacks. Core will call them for each online cpu. */ if (cpuhp_setup_state (CPUHP_PERF_X86_AMD_UNCORE_PREP ,"perf/x86/amd/uncore:prepare" , amd_uncore_cpu_up_prepare, amd_uncore_cpu_dead)) - goto fail_llc; + goto fail; if (cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING, "perf/x86/amd/uncore:starting",
@@ -753,12 +789,8 @@ static int __init amd_uncore_init(void)cpuhp_remove_state (CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING ); fail_prep:cpuhp_remove_state (CPUHP_PERF_X86_AMD_UNCORE_PREP ); -fail_llc: -if (boot_cpu_has (X86_FEATURE_PERFCTR_NB )) -perf_pmu_unregister (&amd_nb_pmu); -free_percpu (amd_uncore_llc); -fail_nb: -free_percpu (amd_uncore_nb); +fail: +uncore_free ();return ret; }
@@ -768,18 +800,7 @@ static void __exit amd_uncore_exit(void)cpuhp_remove_state (CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE );cpuhp_remove_state (CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING );cpuhp_remove_state (CPUHP_PERF_X86_AMD_UNCORE_PREP ); - -if (boot_cpu_has (X86_FEATURE_PERFCTR_LLC )) { -perf_pmu_unregister (&amd_llc_pmu); -free_percpu (amd_uncore_llc); - amd_uncore_llc =NULL ; - } - -if (boot_cpu_has (X86_FEATURE_PERFCTR_NB )) { -perf_pmu_unregister (&amd_nb_pmu); -free_percpu (amd_uncore_nb); - amd_uncore_nb =NULL ; - } +uncore_free (); }module_init (amd_uncore_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 636/1424 perf/x86/amd/uncore: Add group validation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sandipan Das <[email protected]>
[ Upstream commit edda9051e267b7390c7ce24b1b71434414ad156e ]
The amd_uncore driver currently does not validate event groups and allows creation of groups with more events than the number of available hardware counters. Because of this, pmu->event_init() succeeds but counter assignment fails later in pmu->add() which returns -EBUSY once all counters are exhausted.
Address this by introducing group validation in the pmu->event_init() path. Since the uncore PMUs have no per-event constraints and all counters of a PMU are interchangeable, validation is reduced to just counting the group members that target a PMU and ensuring that they fit within the available set of counters.
--- arch/x86/events/amd/uncore.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
arch/x86/events/amd/uncore.c +31 -0
@@ -167,6 +167,29 @@ static void amd_uncore_del(struct perf_event *event, int flags) hwc->idx =-1 ; } +static bool amd_uncore_group_valid (struct perf_event *event) +{ +struct amd_uncore_pmu *pmu =event_to_amd_uncore_pmu (event); +struct perf_event *leader = event->group_leader; +struct perf_event *sibling; +int counters =0 ; + +if (leader->pmu == event->pmu) + counters++; + +for_each_sibling_event (sibling, leader) { +if (sibling->pmu == event->pmu && + sibling->state >PERF_EVENT_STATE_OFF ) + counters++; + } + +/* +* When pmu->event_init() is called, the event is yet to be linked to +* its leader's sibling list, so it is counted separately +*/ +return (counters +1 ) <= pmu->num_counters; +} +static int amd_uncore_event_init (struct perf_event *event) {struct amd_uncore_pmu *pmu;
@@ -184,6 +207,14 @@ static int amd_uncore_event_init(struct perf_event *event)if (!ctx)return -ENODEV ; +/* +* Ensure that all events in a group can be scheduled together so that +* a failure can be reported at perf_event_open() time rather than +* silently at pmu->add() time when no free counter is found +*/ +if (event->group_leader != event && !amd_uncore_group_valid (event)) +return -EINVAL ; +/* * NB and Last level cache counters (MSRs) are shared across all cores * that share the same NB / Last level cache. On family 16h and below,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 637/1424 crypto: qat - clear AES key schedule from stack
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Giovanni Cabiddu <[email protected]>
[ Upstream commit d41a9fcfb7f9ee36e4a4aaf5e7996bca6be1e7a9 ]
qat_alg_xts_reverse_key() expands the forward XTS AES key on the stack. That schedule contains key material and can remain in the stack frame.
Clear the temporary crypto_aes_ctx with memzero_explicit() after the copy.
--- drivers/crypto/intel/qat/qat_common/qat_algs.c | 1 + 1 file changed, 1 insertion(+)
drivers/crypto/intel/qat/qat_common/qat_algs.c +1 -0
@@ -481,6 +481,7 @@ static void qat_alg_xts_reverse_key(const u8 *key_forward, unsigned int keylen,memcpy (key_reverse +AES_BLOCK_SIZE , key -AES_BLOCK_SIZE ,AES_BLOCK_SIZE ); } +memzero_explicit (&aes_expanded,sizeof (aes_expanded)); } static void qat_alg_skcipher_init_dec(struct qat_alg_skcipher_ctx *ctx,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 638/1424 crypto: atmel-ecc - replace min_t with min
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 5b085b2a038a1458f9398cb3b3b03cba6e38e1e0 ]
Use the simpler min() macro since the values are all unsigned and compatible.
Stable-dep-of: f240f9b588f4 ("crypto: atmel-ecc - reject hardware ECDH without a public key")
--- drivers/crypto/atmel-ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/atmel-ecc.c +2 -2
@@ -56,7 +56,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, goto free_work_data;/* might want less than we've got */ - n_sz =min_t (size_t,ATMEL_ECC_NIST_P256_N_SIZE , req->dst_len); + n_sz =min (ATMEL_ECC_NIST_P256_N_SIZE , req->dst_len);/* copy the shared secret */ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz),
@@ -150,7 +150,7 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req)return -EINVAL ;/* might want less than we've got */ - nbytes =min_t (size_t,ATMEL_ECC_PUBKEY_SIZE , req->dst_len); + nbytes =min (ATMEL_ECC_PUBKEY_SIZE , req->dst_len);/* public key was saved at private key generation */ copied = sg_copy_from_buffer(req->dst,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 639/1424 crypto: atmel-ecc - clean up and improve ECDH comments
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 3e84fb698abada239d3e35ed3d52a24dbfda5f6a ]
Improve the kerneldoc for struct atmel_ecdh_ctx by removing the stale "unsupported curves" wording, since the device only supports a single curve (P-256), and move the set_secret() constraint to the description.
In atmel_ecdh_set_secret(), clarify that the device generates the private key, and drop the redundant "only supports NIST P256" comment.
In atmel_ecdh_done() and atmel_ecdh_generate_public_key(), clarify the truncation comments. Also note that a P-256 public key consists of two 32-byte coordinates in atmel_ecdh_compute_shared_secret(), and remove the unnecessary fall-through comment and other redundant comments.
Stable-dep-of: f240f9b588f4 ("crypto: atmel-ecc - reject hardware ECDH without a public key")
--- drivers/crypto/atmel-ecc.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/crypto/atmel-ecc.c +14 -24
@@ -27,15 +27,14 @@ static struct atmel_ecc_driver_data driver_data;/** * struct atmel_ecdh_ctx - transformation context -* @client : pointer to i2c client device -* @fallback : used for unsupported curves or when user wants to use its own -* private key. -* @public_key : generated when calling set_secret(). It's the responsibility -* of the user to not call set_secret() while -* generate_public_key() or compute_shared_secret() are in flight. -* @curve_id : elliptic curve id -* @do_fallback: true when the device doesn't support the curve or when the user -* wants to use its own private key. +* @client: I2C client device +* @fallback: ECDH fallback used for caller-provided private keys +* @public_key: cached public key for the device-generated private key +* @curve_id: elliptic curve id +* @do_fallback: true when ECDH operations should use @fallback +* +* The caller must not invoke set_secret() while generate_public_key() +* or compute_shared_secret() are in flight. */ struct atmel_ecdh_ctx {struct i2c_client *client;
@@ -55,7 +54,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,if (status) goto free_work_data; -/* might want less than we've got */ +/* copy only as much as requested, capped at 32 bytes */ n_sz =min (ATMEL_ECC_NIST_P256_N_SIZE , req->dst_len);/* copy the shared secret */
@@ -64,15 +63,15 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,if (copied != n_sz) status = -EINVAL ; -/* fall through */ free_work_data:kfree_sensitive (work_data);kpp_request_complete (req, status); }/* -* A random private key is generated and stored in the device. The device -* returns the pair public key. +* If no private key is provided, generate one in the device and cache +* the corresponding public key. The generated private key never leaves +* the device. */ static int atmel_ecdh_set_secret (struct crypto_kpp *tfm,const void *buf,unsigned int len)
@@ -83,9 +82,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,struct ecdh params;int ret = -ENOMEM ; -/* free the old public key, if any */ kfree (ctx->public_key); -/* make sure you don't free the old public key twice */ ctx->public_key =NULL ;if (crypto_ecdh_decode_key (buf, len, ¶ms) <0 ) {
@@ -94,7 +91,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, }if (params.key_size) { -/* fallback to ecdh software implementation */ ctx->do_fallback = true;return crypto_kpp_set_secret (ctx->fallback, buf, len); }
@@ -103,11 +99,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,if (!cmd)return -ENOMEM ; -/* -* The device only supports NIST P256 ECC keys. The public key size will -* always be the same. Use a macro for the key size to avoid unnecessary -* computations. -*/ public_key =kmalloc (ATMEL_ECC_PUBKEY_SIZE ,GFP_KERNEL );if (!public_key) goto free_cmd;
@@ -120,7 +111,6 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,if (ret) goto free_public_key; -/* save the public key */ memcpy (public_key, &cmd->data[RSP_DATA_IDX ],ATMEL_ECC_PUBKEY_SIZE ); ctx->public_key = public_key;
@@ -149,7 +139,7 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req)if (!ctx->public_key)return -EINVAL ; -/* might want less than we've got */ +/* copy only as much as requested, capped at 64 bytes */ nbytes =min (ATMEL_ECC_PUBKEY_SIZE , req->dst_len);/* public key was saved at private key generation */
@@ -175,7 +165,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)return crypto_kpp_compute_shared_secret (req); } -/* must have exactly two points to be on the curve */ +/* A P-256 public key must contain two 32-byte coordinates */ if (req->src_len !=ATMEL_ECC_PUBKEY_SIZE )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 640/1424 crypto: atmel-ecc - reject hardware ECDH without a public key
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit f240f9b588f4e2de89822adebf560a96b5d263ed ]
The hardware ECDH path in atmel_ecdh_compute_shared_secret() uses the private key stored in the device. However, the public key is cached only after atmel_ecdh_set_secret() successfully generated that private key for the current tfm.
atmel_ecdh_generate_public_key() already rejects requests when no public key is cached. Add the same check to atmel_ecdh_compute_shared_secret() to prevent the device from using a private key that was not generated for the current tfm.
--- drivers/crypto/atmel-ecc.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/crypto/atmel-ecc.c +3 -0
@@ -165,6 +165,9 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)return crypto_kpp_compute_shared_secret (req); } +if (!ctx->public_key) +return -EINVAL ; +/* A P-256 public key must contain two 32-byte coordinates */ if (req->src_len !=ATMEL_ECC_PUBKEY_SIZE )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 641/1424 crypto: atmel-sha204a - fix heap info leak on I2C transfer failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lothar Rubusch <[email protected]>
[ Upstream commit 72bbf11ba14bd7d5fbf31a1ec42fff608b657f74 ]
The nonblocking RNG path allocates a work_data structure to track the state of an in-flight asynchronous I2C request. This pointer is stored in rng->priv and later consumed by the read path once the transaction completes.
If the underlying I2C transfer fails, the completion callback is invoked with a non-zero status. In this case, the allocated work_data is not usable for producing RNG output and must not remain associated with the hwrng state.
Previously, the failure path only logged a warning but left the pointer state uncleared, which can result in subsequent read attempts observing stale state and interpreting it as valid completion data.
Fix this by freeing the pending work_data. The I2C transaction reports an error. This ensures that failed requests do not leave residual state behind that could be interpreted as valid RNG data on later reads. Clearing rng->priv is done at the subsequent call to nonblocking read.
--- drivers/crypto/atmel-sha204a.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/crypto/atmel-sha204a.c +5 -1
@@ -30,10 +30,14 @@ static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;struct hwrng *rng = areq; -if (status) +if (status) {dev_warn_ratelimited (&i2c_priv->client->dev,"i2c transaction failed (%d)\n" , status); +kfree (work_data); +atomic_dec (&i2c_priv->tfm_count); +return ; + } rng->priv = (unsigned long )work_data;atomic_dec (&i2c_priv->tfm_count);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 642/1424 crypto: sa2ul - stop probe if context pool creation fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit d03f980a25853f6a380895119a572a3bb1194e8d ]
sa_ul_probe() calls sa_init_mem() to create the DMA pool used for security context buffers, but ignores its return value. If pool creation fails, probe still continues with DMA setup, algorithm registration and child population even though later request setup depends on that pool.
Stop probing when sa_init_mem() fails, and route that failure to the PM cleanup path without attempting to destroy an uncreated DMA pool.
--- drivers/crypto/sa2ul.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/crypto/sa2ul.c +5 -1
@@ -2426,7 +2426,10 @@ static int sa_ul_probe(struct platform_device *pdev)return ret; } -sa_init_mem (dev_data); + ret =sa_init_mem (dev_data); +if (ret) + goto disable_pm; + ret =sa_dma_init (dev_data);if (ret) goto destroy_dma_pool;
@@ -2461,6 +2464,7 @@ static int sa_ul_probe(struct platform_device *pdev) destroy_dma_pool:dma_pool_destroy (dev_data->sc_pool); +disable_pm:pm_runtime_put_sync (dev);pm_runtime_disable (dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 643/1424 crypto: rk3288 - fail ahash requests on HASH idle timeout
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit ae150db7826f21e8d19e54fb6243169628809c4d ]
rk_hash_run() waits for RK_CRYPTO_HASH_STS to become idle after the final DMA transfer, but ignores the poll result. If the hash engine never becomes idle, the driver still reads the digest registers and finalizes the request with the previous success value.
Store the poll result and finalize the request with the timeout error before reading the digest registers.
--- drivers/crypto/rockchip/rk3288_crypto_ahash.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/crypto/rockchip/rk3288_crypto_ahash.c +6 -1
@@ -322,7 +322,12 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)* efficiency, and make it response quickly when dma * complete. */ -readl_poll_timeout (rkc->reg +RK_CRYPTO_HASH_STS , v, v ==0 ,10 ,1000 ); + err =readl_poll_timeout (rkc->reg +RK_CRYPTO_HASH_STS , v, + v ==0 ,10 ,1000 ); +if (err) { +dev_err (rkc->dev,"HASH idle timeout\n" ); + goto theend; + }for (i =0 ; i <crypto_ahash_digestsize (tfm) /4 ; i++) { v =readl (rkc->reg +RK_CRYPTO_HASH_DOUT_0 + i *4 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 644/1424 crypto: keembay - Fix AEAD unregister count in error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit e264401ce4776a288524e5b87593d4d864147115 ]
register_aes_algs() registers the AEAD algorithms before registering the skcipher algorithms. If skcipher registration fails, the function unwinds the earlier AEAD registration with crypto_engine_unregister_aeads(), but it passes ARRAY_SIZE(algs), which is the skcipher table size.
Use ARRAY_SIZE(algs_aead) for the AEAD unwind path so the unregister helper iterates over the same table that was registered. Also clarify the nearby
comment: the crypto registration helpers clean up algorithms registered within the same call, while this function must still unwind earlier successful registration steps.
--- drivers/crypto/intel/keembay/keembay-ocs-aes-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/intel/keembay/keembay-ocs-aes-core.c +2 -2
@@ -1541,7 +1541,7 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev)/* * If any algorithm fails to register, all preceding algorithms that -* were successfully registered will be automatically unregistered. +* were registered in the same call are automatically unregistered. */ ret =crypto_engine_register_aeads (algs_aead,ARRAY_SIZE (algs_aead));if (ret)
@@ -1549,7 +1549,7 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev) ret =crypto_engine_register_skciphers (algs,ARRAY_SIZE (algs));if (ret) -crypto_engine_unregister_aeads (algs_aead,ARRAY_SIZE (algs)); +crypto_engine_unregister_aeads (algs_aead,ARRAY_SIZE (algs_aead));return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 645/1424 nvme-apple: Use acquire/release for queue enabled state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gui-Dong Han <[email protected]>
[ Upstream commit f61c934aa084b7440fec681be3f4b481eb5a8609 ]
apple_nvme_init_queue() initializes queue state and then marks the queue enabled. The interrupt and request paths check enabled before using that queue state.
The old wmb() after WRITE_ONCE(enabled, true) does not publish the earlier initialization before enabled becomes visible. Use a release store when enabling the queue and acquire loads when testing it.
Although the shutdown-side enabled accesses are not used for publishing queue initialization, use helpers for them as well for consistency.
--- drivers/nvme/host/apple.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-)
drivers/nvme/host/apple.c +23 -7
@@ -149,6 +149,23 @@ struct apple_nvme_queue {bool enabled; }; +static inline bool apple_nvme_queue_enabled (struct apple_nvme_queue *q) +{ +/* Pair with apple_nvme_enable_queue(). */ +return smp_load_acquire (&q->enabled); +} + +static inline void apple_nvme_enable_queue (struct apple_nvme_queue *q) +{ +/* Publish queue initialization before setting q->enabled. */ +smp_store_release (&q->enabled, true); +} + +static inline void apple_nvme_disable_queue (struct apple_nvme_queue *q) +{ +WRITE_ONCE (q->enabled, false); +} +/* * The apple_nvme_iod describes the data in an I/O. *
@@ -644,7 +661,7 @@ static bool apple_nvme_handle_cq(struct apple_nvme_queue *q, bool force)bool found;DEFINE_IO_COMP_BATCH (iob); -if (!READ_ONCE (q->enabled) && !force) +if (!apple_nvme_queue_enabled (q) && !force)return false; found =apple_nvme_poll_cq (q, &iob);
@@ -747,7 +764,7 @@ static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx,* We should not need to do this, but we're still using this to * ensure we can drain requests on a dying queue. */ -if (unlikely (!READ_ONCE (q->enabled))) +if (unlikely (!apple_nvme_queue_enabled (q)))return BLK_STS_IOERR ;if (!nvme_check_ready (&anv->ctrl, req, true))
@@ -824,7 +841,7 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)nvme_quiesce_io_queues (&anv->ctrl);if (!dead) { -if (READ_ONCE (anv->ioq.enabled)) { +if (apple_nvme_queue_enabled (&anv->ioq)) {apple_nvme_remove_sq (anv);apple_nvme_remove_cq (anv); }
@@ -848,8 +865,8 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)nvme_disable_ctrl (&anv->ctrl, false); } -WRITE_ONCE (anv->ioq.enabled, false); -WRITE_ONCE (anv->adminq.enabled, false); +apple_nvme_disable_queue (&anv->ioq); +apple_nvme_disable_queue (&anv->adminq);mb ();/* ensure that nvme_queue_rq() sees that enabled is cleared */ nvme_quiesce_admin_queue (&anv->ctrl);
@@ -974,8 +991,7 @@ static void apple_nvme_init_queue(struct apple_nvme_queue *q)memset (q->tcbs,0 ,APPLE_ANS_MAX_QUEUE_DEPTH *sizeof (struct apple_nvmmu_tcb ));memset (q->cqes,0 , depth *sizeof (struct nvme_completion )); -WRITE_ONCE (q->enabled, true); -wmb ();/* ensure the first interrupt sees the initialization */ +apple_nvme_enable_queue (q); }static void apple_nvme_reset_work (struct work_struct *work)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 646/1424 nvmet-rdma: avoid circular locking dependency on install_queue()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hannes Reinecke <[email protected]>
[ Upstream commit 31deaeb11ba7a885116c9c30892b9f763c04d59c ]
nvmet_rdma_install_queue() is driven from the ->io_work workqueue function, but will call flush_workqueue() which might trigger ->release_work() which in itself calls flush_work on ->io_work.
To avoid that check for pending queue in disconnecting status, and return 'controller busy' when we reached a certain threshold.
Stable-dep-of: 0114dd303b37 ("nvmet-rdma: fix response resource leak on queue teardown")
--- drivers/nvme/target/rdma.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/nvme/target/rdma.c +16 -3
@@ -37,6 +37,8 @@#define NVMET_RDMA_MAX_MDTS 8#define NVMET_RDMA_MAX_METADATA_MDTS 5 +#define NVMET_RDMA_BACKLOG 128 +struct nvmet_rdma_srq ;struct nvmet_rdma_cmd {
@@ -1590,8 +1592,19 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id, }if (queue->host_qid ==0 ) { -/* Let inflight controller teardown complete */ -flush_workqueue (nvmet_wq); +struct nvmet_rdma_queue *q; +int pending =0 ; + +/* Check for pending controller teardown */ +mutex_lock (&nvmet_rdma_queue_mutex); +list_for_each_entry (q, &nvmet_rdma_queue_list, queue_list) { +if (q->nvme_sq.ctrl == queue->nvme_sq.ctrl && + q->state ==NVMET_RDMA_Q_DISCONNECTING ) + pending++; + } +mutex_unlock (&nvmet_rdma_queue_mutex); +if (pending >NVMET_RDMA_BACKLOG ) +return NVME_SC_CONNECT_CTRL_BUSY ; } ret =nvmet_rdma_cm_accept (cm_id, queue, &event->param.conn);
@@ -1887,7 +1900,7 @@ static int nvmet_rdma_enable_port(struct nvmet_rdma_port *port) goto out_destroy_id; } - ret =rdma_listen (cm_id,128 ); + ret =rdma_listen (cm_id,NVMET_RDMA_BACKLOG );if (ret) {pr_err ("listening to %pISpcs failed (%d)\n" , addr, ret); goto out_destroy_id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 647/1424 nvmet-rdma: use sbitmap to replace rsp free list
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 40f0e5dc2f3c866bef3fccf398114b90c6136dfa ]
We can use sbitmap to manage all the nvmet_rdma_rsp instead of using free lists and spinlock, and we can use an additional tag to determine whether the nvmet_rdma_rsp is extra allocated.
In addition, performance has improved:
1. testing environment is local rxe rdma devie and mem-based backstore device.
2. fio command, test the average 5 times:
fio -filename=/dev/nvme0n1 --ioengine=libaio -direct=1 -size=1G -name=1 -thread -runtime=60 -time_based -rw=read -numjobs=16 -iodepth=128 -bs=4k -group_reporting
3. Before: 241k IOPS, After: 256k IOPS, an increase of about 5%.
Stable-dep-of: 0114dd303b37 ("nvmet-rdma: fix response resource leak on queue teardown")
--- drivers/nvme/target/rdma.c | 56 ++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 29 deletions(-)
drivers/nvme/target/rdma.c +27 -29
@@ -39,6 +39,8 @@#define NVMET_RDMA_BACKLOG 128 +#define NVMET_RDMA_DISCRETE_RSP_TAG -1 +struct nvmet_rdma_srq ;struct nvmet_rdma_cmd {
@@ -76,7 +78,7 @@ struct nvmet_rdma_rsp {u32 invalidate_rkey;struct list_head wait_list; -struct list_head free_list; +int tag; };enum nvmet_rdma_queue_state {
@@ -99,8 +101,7 @@ struct nvmet_rdma_queue {struct nvmet_sq nvme_sq;struct nvmet_rdma_rsp *rsps; -struct list_head free_rsps; -spinlock_t rsps_lock; +struct sbitmap rsp_tags;struct nvmet_rdma_cmd *cmds;struct work_struct release_work;
@@ -173,7 +174,8 @@ static void nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue);static void nvmet_rdma_free_rsp (struct nvmet_rdma_device *ndev,struct nvmet_rdma_rsp *r);static int nvmet_rdma_alloc_rsp (struct nvmet_rdma_device *ndev, -struct nvmet_rdma_rsp *r); +struct nvmet_rdma_rsp *r, +int tag);static const struct nvmet_fabrics_ops nvmet_rdma_ops;
@@ -211,15 +213,12 @@ static inline bool nvmet_rdma_need_data_out(struct nvmet_rdma_rsp *rsp)static inline struct nvmet_rdma_rsp *nvmet_rdma_get_rsp (struct nvmet_rdma_queue *queue) { -struct nvmet_rdma_rsp *rsp; -unsigned long flags; +struct nvmet_rdma_rsp *rsp =NULL ; +int tag; -spin_lock_irqsave (&queue->rsps_lock, flags); - rsp =list_first_entry_or_null (&queue->free_rsps, - struct nvmet_rdma_rsp, free_list); -if (likely (rsp)) -list_del (&rsp->free_list); -spin_unlock_irqrestore (&queue->rsps_lock, flags); + tag =sbitmap_get (&queue->rsp_tags); +if (tag >=0 ) + rsp = &queue->rsps[tag];if (unlikely (!rsp)) {int ret;
@@ -227,13 +226,12 @@ nvmet_rdma_get_rsp(struct nvmet_rdma_queue *queue) rsp =kzalloc (sizeof (*rsp),GFP_KERNEL );if (unlikely (!rsp))return NULL ; - ret =nvmet_rdma_alloc_rsp (queue->dev, rsp); + ret =nvmet_rdma_alloc_rsp (queue->dev, rsp, +NVMET_RDMA_DISCRETE_RSP_TAG );if (unlikely (ret)) {kfree (rsp);return NULL ; } - - rsp->allocated = true; }return rsp;
@@ -242,17 +240,13 @@ nvmet_rdma_get_rsp(struct nvmet_rdma_queue *queue)static inline void nvmet_rdma_put_rsp (struct nvmet_rdma_rsp *rsp) { -unsigned long flags; - -if (unlikely (rsp->allocated)) { +if (unlikely (rsp->tag ==NVMET_RDMA_DISCRETE_RSP_TAG )) {nvmet_rdma_free_rsp (rsp->queue->dev, rsp);kfree (rsp);return ; } -spin_lock_irqsave (&rsp->queue->rsps_lock, flags); -list_add_tail (&rsp->free_list, &rsp->queue->free_rsps); -spin_unlock_irqrestore (&rsp->queue->rsps_lock, flags); +sbitmap_clear_bit (&rsp->queue->rsp_tags, rsp->tag); } static void nvmet_rdma_free_inline_pages(struct nvmet_rdma_device *ndev,
@@ -405,7 +399,7 @@ static void nvmet_rdma_free_cmds(struct nvmet_rdma_device *ndev, }static int nvmet_rdma_alloc_rsp (struct nvmet_rdma_device *ndev, -struct nvmet_rdma_rsp *r) +struct nvmet_rdma_rsp *r,int tag) {/* NVMe CQE / RDMA SEND */ r->req.cqe =kmalloc (sizeof (*r->req.cqe),GFP_KERNEL );
@@ -433,6 +427,7 @@ static int nvmet_rdma_alloc_rsp(struct nvmet_rdma_device *ndev, r->read_cqe.done = nvmet_rdma_read_data_done;/* Data Out / RDMA WRITE */ r->write_cqe.done = nvmet_rdma_write_data_done; + r->tag = tag;return 0 ;
@@ -455,21 +450,23 @@ nvmet_rdma_alloc_rsps(struct nvmet_rdma_queue *queue) {struct nvmet_rdma_device *ndev = queue->dev;int nr_rsps = queue->recv_queue_size *2 ; -int ret = -EINVAL , i; +int ret = -ENOMEM , i; + +if (sbitmap_init_node (&queue->rsp_tags, nr_rsps,-1 ,GFP_KERNEL , +NUMA_NO_NODE , false, true)) + goto out; queue->rsps =kcalloc (nr_rsps,sizeof (struct nvmet_rdma_rsp ),GFP_KERNEL );if (!queue->rsps) - goto out; + goto out_free_sbitmap;for (i =0 ; i < nr_rsps; i++) {struct nvmet_rdma_rsp *rsp = &queue->rsps[i]; - ret =nvmet_rdma_alloc_rsp (ndev, rsp); + ret =nvmet_rdma_alloc_rsp (ndev, rsp, i);if (ret) goto out_free; - -list_add_tail (&rsp->free_list, &queue->free_rsps); }return 0 ;
@@ -478,6 +475,8 @@ nvmet_rdma_alloc_rsps(struct nvmet_rdma_queue *queue)while (--i >=0 )nvmet_rdma_free_rsp (ndev, &queue->rsps[i]);kfree (queue->rsps); +out_free_sbitmap: +sbitmap_free (&queue->rsp_tags); out:return ret; }
@@ -490,6 +489,7 @@ static void nvmet_rdma_free_rsps(struct nvmet_rdma_queue *queue)for (i =0 ; i < nr_rsps; i++)nvmet_rdma_free_rsp (ndev, &queue->rsps[i]);kfree (queue->rsps); +sbitmap_free (&queue->rsp_tags); } static int nvmet_rdma_post_recv(struct nvmet_rdma_device *ndev,
@@ -1464,8 +1464,6 @@ nvmet_rdma_alloc_queue(struct nvmet_rdma_device *ndev,INIT_LIST_HEAD (&queue->rsp_wait_list);INIT_LIST_HEAD (&queue->rsp_wr_wait_list);spin_lock_init (&queue->rsp_wr_wait_lock); -INIT_LIST_HEAD (&queue->free_rsps); -spin_lock_init (&queue->rsps_lock);INIT_LIST_HEAD (&queue->queue_list); queue->idx =ida_alloc (&nvmet_rdma_queue_ida,GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 648/1424 nvmet-rdma: factor out response resource cleanup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shin'ichiro Kawasaki <[email protected]>
[ Upstream commit 90096175473f7c86e39c3f74f10343f965f5a05d ]
Move the RDMA read/write context teardown and the request SGL freeing out of nvmet_rdma_release_rsp() into a new helper function nvmet_rdma_free_rsp_resources().
This is a refactoring with no functional change, in preparation for the following patch that uses nvmet_rdma_free_rsp_resources().
Stable-dep-of: 0114dd303b37 ("nvmet-rdma: fix response resource leak on queue teardown")
--- drivers/nvme/target/rdma.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/nvme/target/rdma.c +10 -3
@@ -659,18 +659,25 @@ static void nvmet_rdma_rw_ctx_destroy(struct nvmet_rdma_rsp *rsp) req->sg, req->sg_cnt, nvmet_data_dir(req)); } -static void nvmet_rdma_release_rsp (struct nvmet_rdma_rsp *rsp) +static void nvmet_rdma_free_rsp_resources (struct nvmet_rdma_rsp *rsp) {struct nvmet_rdma_queue *queue = rsp->queue; -atomic_add (1 + rsp->n_rdma, &queue->sq_wr_avail); -if (rsp->n_rdma)nvmet_rdma_rw_ctx_destroy (rsp);if (rsp->req.sg < rsp->cmd->inline_sg || rsp->req.sg >= rsp->cmd->inline_sg + queue->dev->inline_page_count)nvmet_req_free_sgls (&rsp->req); +} + +static void nvmet_rdma_release_rsp (struct nvmet_rdma_rsp *rsp) +{ +struct nvmet_rdma_queue *queue = rsp->queue; + +atomic_add (1 + rsp->n_rdma, &queue->sq_wr_avail); + +nvmet_rdma_free_rsp_resources (rsp);if (unlikely (!list_empty_careful (&queue->rsp_wr_wait_list)))nvmet_rdma_process_wr_wait_list (queue);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 649/1424 nvmet-rdma: fix response resource leak on queue teardown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shin'ichiro Kawasaki <[email protected]>
[ Upstream commit 0114dd303b373522dea06053aabae34bdd33a7c4 ]
When an nvme target with rdma transport is removed while I/Os are in flight, a response can be posted but its send completion is never delivered before the connection is torn down. As a result nvmet_rdma_send_done() and nvmet_rdma_release_rsp() are never called for the response, and this leaks the allocated RDMA read/write context and request SGLs.
These leaks are recreated by running blktests nvme/061 with the rdma transport and the siw driver. Kernel kmemleak feature reports them as follows:
unreferenced object 0xffff88812bc490c0 (size 32):
comm "kworker/2:1H", pid 409, jiffies 4307744490
backtrace (crc 89afd339):
__kmalloc_noprof+0x5f9/0x890
sgl_alloc_order+0x7b/0x380
nvmet_req_alloc_sgls+0x290/0x4f0 [nvmet]
nvmet_rdma_map_sgl_keyed+0x241/0x12e0 [nvmet_rdma]
nvmet_rdma_handle_command+0x73e/0xb80 [nvmet_rdma]
__ib_process_cq+0x149/0x4c0 [ib_core]
ib_cq_poll_work+0x49/0x160 [ib_core]
process_one_work+0x8b2/0x1640
worker_thread+0x5fd/0xfe0
kthread+0x367/0x460
ret_from_fork+0x655/0x9d0
ret_from_fork_asm+0x1a/0x30 unreferenced object 0xffff88814bd05e80 (size 64):
comm "kworker/3:1H", pid 148, jiffies 4295195428
backtrace (crc e35510cb):
__kmalloc_noprof+0x5f9/0x890
rdma_rw_ctx_init+0x333/0x1fa0 [ib_core]
nvmet_rdma_map_sgl_keyed+0x5c8/0x12e0 [nvmet_rdma]
nvmet_rdma_handle_command+0x73e/0xb80 [nvmet_rdma]
__ib_process_cq+0x149/0x4c0 [ib_core]
ib_cq_poll_work+0x49/0x160 [ib_core]
process_one_work+0x8b2/0x1640
worker_thread+0x5fd/0xfe0
kthread+0x367/0x460
ret_from_fork+0x655/0x9d0
ret_from_fork_asm+0x1a/0x30To avoid the memory leaks, reclaim the memory of the in-flight responses when the queue QP is torn down. Call nvmet_rdma_free_rsp_resources() that frees up the RDMA read/write context and the request SGLs of such responses.
--- drivers/nvme/target/rdma.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
drivers/nvme/target/rdma.c +18 -0
@@ -1349,9 +1349,27 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue) goto out; } +static bool nvmet_rdma_reclaim_rsp (struct sbitmap *sb,unsigned int bitnr, +void *data) +{ +struct nvmet_rdma_queue *queue = data; + +nvmet_rdma_free_rsp_resources (&queue->rsps[bitnr]); + +return true; +} +static void nvmet_rdma_destroy_queue_ib (struct nvmet_rdma_queue *queue) {ib_drain_qp (queue->qp); + +/* +* Reclaim resources of a response that is still in-flight when the +* queue is being torn down. This happens when the connection was +* forcefully disconnected while an I/O is in flight. +*/ +sbitmap_for_each_set (&queue->rsp_tags, nvmet_rdma_reclaim_rsp, queue); +if (queue->cm_id)rdma_destroy_id (queue->cm_id);ib_destroy_qp (queue->qp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 650/1424 bus: ti-sysc: Fix /chosen node reference leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 6342de0aed216b6df460b492ddb532b3e0ed16f1 ]
sysc_init_stdout_path() gets the /chosen node with of_find_node_by_path() to read stdout-path. The function then overwrites the local node pointer with the stdout-path lookup result, or exits on error, without dropping the /chosen reference.
Keep the /chosen node in a separate variable and put it after the stdout-path value has been used for the lookup. The successful stdout node lookup remains referenced by the cached stdout_path pointer.
--- drivers/bus/ti-sysc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/bus/ti-sysc.c +8 -4
@@ -672,6 +672,7 @@ static struct device_node *stdout_path;static void sysc_init_stdout_path (struct sysc *ddata) { +struct device_node *chosen;struct device_node *np =NULL ;const char *uart;
@@ -681,15 +682,18 @@ static void sysc_init_stdout_path(struct sysc *ddata)if (stdout_path)return ; - np =of_find_node_by_path ("/chosen" ); -if (!np) + chosen =of_find_node_by_path ("/chosen" ); +if (!chosen) goto err; - uart =of_get_property (np,"stdout-path" ,NULL ); -if (!uart) + uart =of_get_property (chosen,"stdout-path" ,NULL ); +if (!uart) { +of_node_put (chosen); goto err; + } np =of_find_node_by_path (uart); +of_node_put (chosen);if (!np) goto err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 651/1424 PM: sleep: Fix off-by-one in wakelocks number limit check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haowen Tu <[email protected]>
[ Upstream commit 6058646587dded0ce0ba91bd5a6afbf14fe42055 ]
CONFIG_PM_WAKELOCKS_LIMIT is documented as the maximum number of user-space wakeup sources, but the limit check is performed before the counter is incremented and only rejects new wakeup sources when the current number is greater than the limit. This allows one extra wakeup source to be created.
Reject new wakeup sources once the counter has reached the limit.
--- kernel/power/wakelock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/power/wakelock.c +1 -1
@@ -63,7 +63,7 @@ static unsigned int number_of_wakelocks;static inline bool wakelocks_limit_exceeded (void ) { -return number_of_wakelocks >CONFIG_PM_WAKELOCKS_LIMIT ; +return number_of_wakelocks >=CONFIG_PM_WAKELOCKS_LIMIT ; }static inline void increment_wakelocks_number (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 652/1424 arm64: dts: qcom: sm7225-fairphone-fp4: Fix address in fb node name
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luca Weiss <[email protected]>
[ Upstream commit f6e65005fe55c3d09287851523de06367cbf0bc2 ]
'reg' is 0xa0000000 so the node name is missing a zero. Add it, so that the reg and address in the node name matches.
No functional impact.
--- arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +1 -1
@@ -41,7 +41,7 @@ chosen { stdout-path = "serial0:115200n8"; - framebuffer0: framebuffer@a000000 { + framebuffer0: framebuffer@a0000000 { compatible = "simple-framebuffer"; reg = <0 0xa0000000 0 (2340 * 1080 * 4)>; width = <1080>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 653/1424 bus: qcom-ebi2: Simplify with scoped for each OF child loop
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Kozlowski <[email protected]>
[ Upstream commit 9c252f3c8f390fae4ca09de36c9262a35ae88ace ]
Use scoped for-each loop when iterating over device nodes to make code a bit simpler.
Stable-dep-of: 64774dea5896 ("bus: qcom-ebi2: Fix clock leak on probe failure")
--- drivers/bus/qcom-ebi2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/bus/qcom-ebi2.c +2 -5
@@ -292,7 +292,6 @@ static void qcom_ebi2_setup_chipselect(struct device_node *np,static int qcom_ebi2_probe (struct platform_device *pdev) {struct device_node *np = pdev->dev.of_node; -struct device_node *child;struct device *dev = &pdev->dev;struct resource *res;void __iomem *ebi2_base;
@@ -348,15 +347,13 @@ static int qcom_ebi2_probe(struct platform_device *pdev)writel (val, ebi2_base);/* Walk over the child nodes and see what chipselects we use */ -for_each_available_child_of_node (np, child) { +for_each_available_child_of_node_scoped (np, child) {u32 csindex;/* Figure out the chipselect */ ret =of_property_read_u32 (child,"reg" , &csindex); -if (ret) { -of_node_put (child); +if (ret)return ret; - }if (csindex >5 ) { dev_err(dev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 654/1424 bus: qcom-ebi2: Fix clock leak on probe failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 64774dea58969194ea5c27fa639954e551a87024 ]
qcom_ebi2_probe() enables the EBI2X and EBI2 clocks before it walks child nodes and populates child devices. If reading a child node's reg property fails, or if of_platform_default_populate() fails, probe returns without disabling either clock.
Route those failure paths through the existing clock cleanup labels so a failed probe does not leave the clocks prepared and enabled.
--- drivers/bus/qcom-ebi2.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/bus/qcom-ebi2.c +7 -3
@@ -353,7 +353,7 @@ static int qcom_ebi2_probe(struct platform_device *pdev)/* Figure out the chipselect */ ret =of_property_read_u32 (child,"reg" , &csindex);if (ret) -return ret; + goto err_disable_clk;if (csindex >5 ) { dev_err(dev,
@@ -372,8 +372,12 @@ static int qcom_ebi2_probe(struct platform_device *pdev) have_children = true; } -if (have_children) -return of_platform_default_populate (np,NULL , dev); +if (have_children) { + ret =of_platform_default_populate (np,NULL , dev); +if (ret) + goto err_disable_clk; + } +return 0 ; err_disable_clk:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 655/1424 wifi: mac80211_hwsim: avoid NULL skb in stop queue drain
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 158438cd6ad69d6dd7d871582c38baf22169fede ]
mac80211_hwsim_stop() drops any frames left in data->pending. The loop currently checks skb_queue_empty() and then dequeues separately.
That split is racy with TX status handling, which can remove a pending frame under the queue lock. If the last entry is removed after the empty check, skb_dequeue() returns NULL and the stop path passes that NULL skb to ieee80211_free_txskb().
Use skb_dequeue() as the loop condition instead. The dequeue result is the object that stop owns and frees, and a concurrent status completion that empties the queue simply makes the loop terminate.
--- drivers/net/wireless/virtual/mac80211_hwsim.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/wireless/virtual/mac80211_hwsim.c +3 -2
@@ -2084,6 +2084,7 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw)static void mac80211_hwsim_stop (struct ieee80211_hw *hw) {struct mac80211_hwsim_data *data = hw->priv; +struct sk_buff *skb;int i; data->started = false;
@@ -2091,8 +2092,8 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)for (i =0 ; i <ARRAY_SIZE (data->link_data); i++)hrtimer_cancel (&data->link_data[i].beacon_timer); -while (!skb_queue_empty (&data->pending)) -ieee80211_free_txskb (hw,skb_dequeue (&data->pending)); +while ((skb =skb_dequeue (&data->pending))) +ieee80211_free_txskb (hw, skb);wiphy_dbg (hw->wiphy,"%s\n" , __func__); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 656/1424 staging: greybus: audio: correct sscanf() return value check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander A. Klimov <[email protected]>
[ Upstream commit f883fa1a0a0212f63acb18c50e5f900301f3bb1e ]
manager_sysfs_add_store() passes 6 pointers to sscanf(), but required latter to return 7 which always failed the operation. I corrected it to 6.
--- drivers/staging/greybus/audio_manager_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/greybus/audio_manager_sysfs.c +1 -1
@@ -23,7 +23,7 @@ static ssize_t manager_sysfs_add_store(struct kobject *kobj, desc.name, &desc.vid, &desc.pid, &desc.intf_id, &desc.ip_devices, &desc.op_devices); -if (num !=7 ) +if (num !=6 )return -EINVAL ; num =gb_audio_manager_add (&desc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 657/1424 staging: sm750fb: gate dualview dataflow using g_dualview
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmet Sezgin Duran <[email protected]>
[ Upstream commit d352778979d2eed09e266ed0f3a5e3ccd3983940 ]
In sm750fb_setup and sm750fb_set_drv functions, the dualview related code is guarded by sm750_dev->fb_count > 1 condition. That value is updated only after each framebuffer is registered, while both guards are used before any increment.
Current flow:
lynxfb_pci_probe()
sm750fb_setup() // fb_count is 0
for each fb:
sm750fb_framebuffer_alloc()
lynxfb_set_fbinfo()
sm750fb_set_drv() // fb_count is 0 or 1
register_framebuffer()
sm750_dev->fb_count++; // fb_count is incrementedThus even if dualview=1 parameter is passed down to the driver, fb_count is never > 1 at either check, so dualview dataflows are not selected and crtc->vidmem_size is never halved.
Use g_dualview global variable instead of fb_count > 1 to correctly enable dualview capabilities.
--- drivers/staging/sm750fb/sm750.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/sm750fb/sm750.c +2 -2
@@ -599,7 +599,7 @@ static int sm750fb_set_drv(struct lynxfb_par *par) crtc = &par->crtc; crtc->vidmem_size = sm750_dev->vidmem_size; -if (sm750_dev->fb_count >1 ) +if (g_dualview) crtc->vidmem_size >>=1 ;/* setup crtc and output member */
@@ -927,7 +927,7 @@ static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src) NO_PARAM:if (sm750_dev->revid !=SM750LE_REVISION_ID ) { -if (sm750_dev->fb_count >1 ) { +if (g_dualview) {if (swap) sm750_dev->dataflow = sm750_dual_swap;else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 658/1424 greybus: audio: bound the topology section sizes against the fetched size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit 33d8c7b794d2a30637c9d3fcb478f1d3222bef1e ]
gb_audio_gb_get_topology() fetches a topology blob of a module-supplied size, and gbaudio_tplg_parse_data() then walks it by adding the module-supplied size_dais, size_controls and size_widgets fields to form the control, widget and route section offsets. Those le32 sizes are never checked against the fetched blob, so a module reporting a small topology size but large section sizes makes the offsets point past the allocation, and parsing reads out of bounds.
Reject a topology whose section sizes do not fit within the fetched size before it is parsed.
--- drivers/staging/greybus/audio_gb.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/staging/greybus/audio_gb.c +13 -0
@@ -37,6 +37,19 @@ int gb_audio_gb_get_topology(struct gb_connection *connection,return ret; } +/* +* The size_* fields are supplied by the module and are used by +* gbaudio_tplg_parse_data() to compute offsets into the blob; make +* sure the sections fit within the fetched topology, so walking it +* cannot read out of bounds. +*/ +if ((u64 )le32_to_cpu (topo->size_dais) +le32_to_cpu (topo->size_controls) + +le32_to_cpu (topo->size_widgets) +le32_to_cpu (topo->size_routes) > + size -sizeof (*topo)) { +kfree (topo); +return -EINVAL ; + } + *topology = topo;return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 659/1424 staging: fbtft: Use sysfs_emit_at() to print to sysfs file
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 221192a784c25e28b489a7e75fabf59be4f63d57 ]
This scnprintf() uses the wrong limit. It should be "PAGE_SIZE - len" instead of just PAGE_SIZE. We're not going to hit the limit in real life since we are printing at most FBTFT_GAMMA_MAX_VALUES_TOTAL (128) u32 values, however, it's still worth fixing.
Use sysfs_emit_at() to fix this since this is a sysfs file.
--- drivers/staging/fbtft/fbtft-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/fbtft/fbtft-sysfs.c +1 -1
@@ -102,7 +102,7 @@ sprintf_gamma(struct fbtft_par *par, u32 *curves, char *buf)mutex_lock (&par->gamma.lock);for (i =0 ; i < par->gamma.num_curves; i++) {for (j =0 ; j < par->gamma.num_values; j++) - len +=scnprintf (&buf[len],PAGE_SIZE , + len +=sysfs_emit_at (buf, len,"%04x " , curves[i * par->gamma.num_values + j]); buf[len -1 ] ='\n' ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 660/1424 staging: octeon: add missing tasklet_kill in cvm_oct_tx_shutdown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ayush Mukkanwar <[email protected]>
[ Upstream commit b9af44b0d20b2247c4eb0ea5cfca907d643eea50 ]
The TX cleanup tasklet can be scheduled by the watchdog IRQ handler to execute cvm_oct_tx_do_cleanup. There can be a pending tasklet in the queue which might run after the cvm_oct_remove() frees net_device structures, causing a use-after-free in cvm_oct_tx_do_cleanup() as it iterates cvm_oct_device[] which is an array of netdevice pointers. Add tasklet_kill() after free_irq() to ensure the tasklet is no longer scheduled or running before teardown proceeds.
--- drivers/staging/octeon/ethernet-tx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/staging/octeon/ethernet-tx.c +2 -0
@@ -711,4 +711,6 @@ void cvm_oct_tx_shutdown(void) {/* Free the interrupt handler */ free_irq (OCTEON_IRQ_TIMER1 , cvm_oct_device); + +tasklet_kill (&cvm_oct_tx_cleanup_tasklet); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 661/1424 staging: octeon: fix free_irq dev_id mismatch in cvm_oct_rx_shutdown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuvraj Singh Chauhan <[email protected]>
[ Upstream commit 41db5b76eeb4cc11a1097384caba7cfc659f7293 ]
In cvm_oct_rx_initialize(), request_irq() is called with &oct_rx_group[i].napi as the dev_id:
request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0, "Ethernet", &oct_rx_group[i].napi);
However, cvm_oct_rx_shutdown() passes cvm_oct_device (an array of struct net_device pointers) as the dev_id to free_irq():
free_irq(oct_rx_group[i].irq, cvm_oct_device);
Since __free_irq() matches the action to remove by comparing dev_id pointers, the mismatched cookie means the IRQ handler is never found, triggering a WARN and leaving the IRQ line permanently allocated. This prevents proper driver cleanup on module removal.
Fix the mismatch by passing &oct_rx_group[i].napi as the dev_id to free_irq(), matching what was used during request_irq().
Stable-dep-of: c0a9a8586a63 ("staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown")
--- drivers/staging/octeon/ethernet-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/octeon/ethernet-rx.c +1 -1
@@ -535,7 +535,7 @@ void cvm_oct_rx_shutdown(void)cvmx_write_csr (CVMX_POW_WQ_INT_THRX (i),0 );/* Free the interrupt handler */ -free_irq (oct_rx_group[i].irq, cvm_oct_device); +free_irq (oct_rx_group[i].irq, &oct_rx_group[i].napi);netif_napi_del (&oct_rx_group[i].napi); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 662/1424 staging: octeon: ethernet-mem: replace pr_warn with dev_warn in free functions
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ayush Mukkanwar <[email protected]>
[ Upstream commit be5e8d5f61b31105e0ed7f51cd591653aea5054f ]
Add struct platform_device parameter to cvm_oct_free_hw_skbuff, cvm_oct_free_hw_memory and cvm_oct_mem_empty_fpa. Replace pr_warn calls with dev_warn, using &pdev->dev for device-aware logging.
Stable-dep-of: c0a9a8586a63 ("staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown")
--- drivers/staging/octeon/ethernet-mem.c | 31 ++++++++++++++++----------- drivers/staging/octeon/ethernet-mem.h | 5 ++++- drivers/staging/octeon/ethernet.c | 6 +++--- 3 files changed, 25 insertions(+), 17 deletions(-)
drivers/staging/octeon/ethernet-mem.c +18 -13
@@ -5,6 +5,7 @@* Copyright (c) 2003-2010 Cavium Networks */ +#include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/slab.h>
@@ -40,11 +41,13 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)/** * cvm_oct_free_hw_skbuff- free hardware pool skbuffs +* @pdev: Platform device for logging * @pool: Pool to allocate an skbuff for * @size: Size of the buffer needed for the pool * @elements: Number of buffers to allocate */ -static void cvm_oct_free_hw_skbuff (int pool,int size,int elements) +static void cvm_oct_free_hw_skbuff (struct platform_device *pdev, +int pool,int size,int elements) {char *memory;
@@ -59,11 +62,11 @@ static void cvm_oct_free_hw_skbuff(int pool, int size, int elements) }while (memory);if (elements <0 ) -pr_warn ("Freeing of pool %u had too many skbuffs (%d)\n" , - pool, elements); +dev_warn (&pdev->dev,"Freeing of pool %u had too many skbuffs (%d)\n" , + pool, elements);else if (elements >0 ) -pr_warn ("Freeing of pool %u is missing %d skbuffs\n" , - pool, elements); +dev_warn (&pdev->dev,"Freeing of pool %u is missing %d skbuffs\n" , + pool, elements); }/**
@@ -107,11 +110,13 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)/** * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory +* @pdev: Platform device for logging * @pool: FPA pool to free * @size: Size of each buffer in the pool * @elements: Number of buffers that should be in the pool */ -static void cvm_oct_free_hw_memory (int pool,int size,int elements) +static void cvm_oct_free_hw_memory (struct platform_device *pdev, +int pool,int size,int elements) {char *memory;char *fpa;
@@ -127,11 +132,11 @@ static void cvm_oct_free_hw_memory(int pool, int size, int elements) }while (fpa);if (elements <0 ) -pr_warn ("Freeing of pool %u had too many buffers (%d)\n" , - pool, elements); +dev_warn (&pdev->dev,"Freeing of pool %u had too many buffers (%d)\n" , + pool, elements);else if (elements >0 ) -pr_warn ("Warning: Freeing of pool %u is missing %d buffers\n" , - pool, elements); +dev_warn (&pdev->dev,"Freeing of pool %u is missing %d buffers\n" , + pool, elements); }int cvm_oct_mem_fill_fpa (int pool,int size,int elements)
@@ -145,10 +150,10 @@ int cvm_oct_mem_fill_fpa(int pool, int size, int elements)return freed; } -void cvm_oct_mem_empty_fpa (int pool,int size,int elements) +void cvm_oct_mem_empty_fpa (struct platform_device *pdev,int pool,int size,int elements) {if (pool ==CVMX_FPA_PACKET_POOL ) -cvm_oct_free_hw_skbuff (pool, size, elements); +cvm_oct_free_hw_skbuff (pdev, pool, size, elements);else -cvm_oct_free_hw_memory (pool, size, elements); +cvm_oct_free_hw_memory (pdev, pool, size, elements); }
drivers/staging/octeon/ethernet-mem.h +4 -1
@@ -6,4 +6,7 @@*/ int cvm_oct_mem_fill_fpa (int pool,int size,int elements); -void cvm_oct_mem_empty_fpa (int pool,int size,int elements); +struct platform_device ; + +void cvm_oct_mem_empty_fpa (struct platform_device *pdev,int pool,int size, +int elements);
drivers/staging/octeon/ethernet.c +3 -3
@@ -958,12 +958,12 @@ static void cvm_oct_remove(struct platform_device *pdev)cvmx_ipd_free_ptr ();/* Free the HW pools */ -cvm_oct_mem_empty_fpa (CVMX_FPA_PACKET_POOL ,CVMX_FPA_PACKET_POOL_SIZE , +cvm_oct_mem_empty_fpa (pdev,CVMX_FPA_PACKET_POOL ,CVMX_FPA_PACKET_POOL_SIZE , num_packet_buffers); -cvm_oct_mem_empty_fpa (CVMX_FPA_WQE_POOL ,CVMX_FPA_WQE_POOL_SIZE , +cvm_oct_mem_empty_fpa (pdev,CVMX_FPA_WQE_POOL ,CVMX_FPA_WQE_POOL_SIZE , num_packet_buffers);if (CVMX_FPA_OUTPUT_BUFFER_POOL !=CVMX_FPA_PACKET_POOL ) -cvm_oct_mem_empty_fpa (CVMX_FPA_OUTPUT_BUFFER_POOL , +cvm_oct_mem_empty_fpa (pdev,CVMX_FPA_OUTPUT_BUFFER_POOL ,CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE ,128 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 663/1424 staging: octeon: replace pr_warn with dev_warn in fill and rx paths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ayush Mukkanwar <[email protected]>
[ Upstream commit 2191a8dfd1f5a3091e9f388899beb137686c6532 ]
Add struct platform_device parameter to cvm_oct_fill_hw_memory, cvm_oct_mem_fill_fpa, cvm_oct_rx_refill_pool and cvm_oct_rx_initialize to support device-aware logging. Replace pr_warn with dev_warn using &pdev->dev.
To avoid passing these parameters through global state, introduce struct octeon_ethernet_platform to hold per-device state including the rx_refill_work and the oct_rx_group array. This ensures all receive group state and workers are correctly associated with the platform device.
Define struct oct_rx_group and struct octeon_ethernet_platform in octeon-ethernet.h so they are shared across compilation units.
Stable-dep-of: c0a9a8586a63 ("staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown")
--- drivers/staging/octeon/ethernet-mem.c | 12 +++--- drivers/staging/octeon/ethernet-mem.h | 3 +- drivers/staging/octeon/ethernet-rx.c | 49 ++++++++++++------------ drivers/staging/octeon/ethernet-rx.h | 11 ++++-- drivers/staging/octeon/ethernet.c | 37 +++++++++++------- drivers/staging/octeon/octeon-ethernet.h | 14 +++++++ 6 files changed, 78 insertions(+), 48 deletions(-)
drivers/staging/octeon/ethernet-mem.c +7 -5
@@ -71,13 +71,15 @@ static void cvm_oct_free_hw_skbuff(struct platform_device *pdev,/** * cvm_oct_fill_hw_memory - fill a hardware pool with memory. +* @pdev: Platform device for logging * @pool: Pool to populate * @size: Size of each buffer in the pool * @elements: Number of buffers to allocate * * Returns the actual number of buffers allocated. */ -static int cvm_oct_fill_hw_memory (int pool,int size,int elements) +static int cvm_oct_fill_hw_memory (struct platform_device *pdev,int pool,int size, +int elements) {char *memory;char *fpa;
@@ -96,8 +98,8 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)*/ memory =kmalloc (size +256 ,GFP_ATOMIC );if (unlikely (!memory)) { -pr_warn ("Unable to allocate %u bytes for FPA pool %d\n" , - elements * size, pool); +dev_warn (&pdev->dev,"Unable to allocate %u bytes for FPA pool %d\n" , + elements * size, pool);break ; } fpa = (char *)(((unsigned long )memory +256 ) & ~0x7fUL );
@@ -139,14 +141,14 @@ static void cvm_oct_free_hw_memory(struct platform_device *pdev, pool, elements); } -int cvm_oct_mem_fill_fpa (int pool,int size,int elements) +int cvm_oct_mem_fill_fpa (struct platform_device *pdev,int pool,int size,int elements) {int freed;if (pool ==CVMX_FPA_PACKET_POOL ) freed =cvm_oct_fill_hw_skbuff (pool, size, elements);else - freed =cvm_oct_fill_hw_memory (pool, size, elements); + freed =cvm_oct_fill_hw_memory (pdev, pool, size, elements);return freed; }
drivers/staging/octeon/ethernet-mem.h +2 -1
@@ -5,8 +5,9 @@* Copyright (c) 2003-2007 Cavium Networks */ -int cvm_oct_mem_fill_fpa (int pool,int size,int elements);struct platform_device ; +int cvm_oct_mem_fill_fpa (struct platform_device *pdev,int pool,int size, +int elements);void cvm_oct_mem_empty_fpa (struct platform_device *pdev,int pool,int size,int elements);
drivers/staging/octeon/ethernet-rx.c +25 -24
125 lines not on this page · raw message
drivers/staging/octeon/ethernet-rx.h +7 -4
@@ -5,11 +5,14 @@* Copyright (c) 2003-2007 Cavium Networks */ +struct platform_device ; +void cvm_oct_poll_controller (struct net_device *dev); -void cvm_oct_rx_initialize (void ); -void cvm_oct_rx_shutdown (void ); +void cvm_oct_rx_initialize (struct platform_device *pdev); +void cvm_oct_rx_shutdown (struct platform_device *pdev); -static inline void cvm_oct_rx_refill_pool (int fill_threshold) +static inline void cvm_oct_rx_refill_pool (struct platform_device *pdev, +int fill_threshold) {int number_to_free;int num_freed;
@@ -20,7 +23,7 @@ static inline void cvm_oct_rx_refill_pool(int fill_threshold)if (number_to_free > fill_threshold) {cvmx_fau_atomic_add32 (FAU_NUM_PACKET_BUFFERS_TO_FREE , -number_to_free); - num_freed =cvm_oct_mem_fill_fpa (CVMX_FPA_PACKET_POOL , + num_freed =cvm_oct_mem_fill_fpa (pdev,CVMX_FPA_PACKET_POOL ,CVMX_FPA_PACKET_POOL_SIZE , number_to_free);if (num_freed != number_to_free) {
drivers/staging/octeon/ethernet.c +23 -14
@@ -104,11 +104,10 @@ struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];u64 cvm_oct_tx_poll_interval; -static void cvm_oct_rx_refill_worker (struct work_struct *work); -static DECLARE_DELAYED_WORK(cvm_oct_rx_refill_work, cvm_oct_rx_refill_worker); -static void cvm_oct_rx_refill_worker (struct work_struct *work) { +struct octeon_ethernet_platform *plat =container_of (work, + struct octeon_ethernet_platform, rx_refill_work.work);/* * FPA 0 may have been drained, try to refill it if we need * more than num_packet_buffers / 2, otherwise normal receive
@@ -116,10 +115,10 @@ static void cvm_oct_rx_refill_worker(struct work_struct *work)* could be received so cvm_oct_napi_poll would never be * invoked to do the refill. */ -cvm_oct_rx_refill_pool (num_packet_buffers /2 ); +cvm_oct_rx_refill_pool (plat->pdev, num_packet_buffers /2 );if (!atomic_read (&cvm_oct_poll_queue_stopping)) -schedule_delayed_work (&cvm_oct_rx_refill_work,HZ ); +schedule_delayed_work (&plat->rx_refill_work,HZ ); }static void cvm_oct_periodic_worker (struct work_struct *work)
@@ -138,16 +137,16 @@ static void cvm_oct_periodic_worker(struct work_struct *work)schedule_delayed_work (&priv->port_periodic_work,HZ ); } -static void cvm_oct_configure_common_hw (void ) +static void cvm_oct_configure_common_hw (struct platform_device *pdev) {/* Setup the FPA */ cvmx_fpa_enable (); -cvm_oct_mem_fill_fpa (CVMX_FPA_PACKET_POOL ,CVMX_FPA_PACKET_POOL_SIZE , +cvm_oct_mem_fill_fpa (pdev,CVMX_FPA_PACKET_POOL ,CVMX_FPA_PACKET_POOL_SIZE , num_packet_buffers); -cvm_oct_mem_fill_fpa (CVMX_FPA_WQE_POOL ,CVMX_FPA_WQE_POOL_SIZE , +cvm_oct_mem_fill_fpa (pdev,CVMX_FPA_WQE_POOL ,CVMX_FPA_WQE_POOL_SIZE , num_packet_buffers);if (CVMX_FPA_OUTPUT_BUFFER_POOL !=CVMX_FPA_PACKET_POOL ) -cvm_oct_mem_fill_fpa (CVMX_FPA_OUTPUT_BUFFER_POOL , +cvm_oct_mem_fill_fpa (pdev,CVMX_FPA_OUTPUT_BUFFER_POOL ,CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE ,1024 );#ifdef __LITTLE_ENDIAN
@@ -678,6 +677,15 @@ static int cvm_oct_probe(struct platform_device *pdev)int qos;struct device_node *pip;int mtu_overhead =ETH_HLEN +ETH_FCS_LEN ; +struct octeon_ethernet_platform *plat; + + plat =devm_kzalloc (&pdev->dev,sizeof (*plat),GFP_KERNEL ); +if (!plat) +return -ENOMEM ; + + plat->pdev = pdev; +INIT_DELAYED_WORK (&plat->rx_refill_work, cvm_oct_rx_refill_worker); +platform_set_drvdata (pdev, plat);#if IS_ENABLED (CONFIG_VLAN_8021Q ) mtu_overhead +=VLAN_HLEN ;
@@ -689,7 +697,7 @@ static int cvm_oct_probe(struct platform_device *pdev)return -EINVAL ; } -cvm_oct_configure_common_hw (); +cvm_oct_configure_common_hw (pdev);cvmx_helper_initialize_packet_io_global ();
@@ -912,28 +920,29 @@ static int cvm_oct_probe(struct platform_device *pdev) }cvm_oct_tx_initialize (); -cvm_oct_rx_initialize (); +cvm_oct_rx_initialize (pdev);/* * 150 uS: about 10 1500-byte packets at 1GE. */ cvm_oct_tx_poll_interval =150 * (octeon_get_clock_rate () /1000000 ); -schedule_delayed_work (&cvm_oct_rx_refill_work,HZ ); +schedule_delayed_work (&plat->rx_refill_work,HZ );return 0 ; }static void cvm_oct_remove (struct platform_device *pdev) { +struct octeon_ethernet_platform *plat =platform_get_drvdata (pdev);int port;cvmx_ipd_disable ();atomic_inc_return (&cvm_oct_poll_queue_stopping); -cancel_delayed_work_sync (&cvm_oct_rx_refill_work); +cancel_delayed_work_sync (&plat->rx_refill_work); -cvm_oct_rx_shutdown (); +cvm_oct_rx_shutdown (pdev);cvm_oct_tx_shutdown ();cvmx_pko_disable ();
drivers/staging/octeon/octeon-ethernet.h +14 -0
@@ -11,6 +11,7 @@#ifndef OCTEON_ETHERNET_H #define OCTEON_ETHERNET_H +#include <linux/netdevice.h> #include <linux/of.h> #include <linux/phy.h>
@@ -74,6 +75,19 @@ struct octeon_ethernet {struct device_node *of_node; }; +struct oct_rx_group { +int irq; +int group; +struct napi_struct napi; +struct platform_device *pdev; +}; + +struct octeon_ethernet_platform { +struct platform_device *pdev; +struct delayed_work rx_refill_work; +struct oct_rx_group rx_group[16 ]; +}; +int cvm_oct_free_work (void *work_queue_entry);int cvm_oct_rgmii_open (struct net_device *dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 664/1424 staging: octeon: add missing napi_disable in cvm_oct_rx_shutdown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ayush Mukkanwar <[email protected]>
[ Upstream commit c0a9a8586a63fda49e61a6b83360feac2a60d898 ]
cvm_oct_rx_shutdown calls free_irq and netif_napi_del without disabling the napi instance first. As the free_irq only waits for completion of hard interrupt handlers, the napi poll function could still be active. If cvm_oct_remove proceeds to free the plat structure (which holds the NAPI instances), the active poll function will access freed memory, resulting in a use-after-free crash.
--- drivers/staging/octeon/ethernet-rx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/staging/octeon/ethernet-rx.c +2 -0
@@ -535,6 +535,8 @@ void cvm_oct_rx_shutdown(struct platform_device *pdev)else cvmx_write_csr (CVMX_POW_WQ_INT_THRX (i),0 ); +napi_disable (&plat->rx_group[i].napi); +/* Free the interrupt handler */ free_irq (plat->rx_group[i].irq, &plat->rx_group[i].napi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 665/1424 staging: rtl8723bs: fix mismatched free of HalData in rtw_sdio_if1_init()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
[ Upstream commit 264676418b726baca7be49171e306b6aa05cceb0 ]
padapter->HalData is allocated via vzalloc(), but incorrectly freed using kfree() in the rtw_sdio_if1_init() error path. Using kfree() to release this vmalloc-backed buffer can lead to memory corruption.
Use rtw_hal_data_deinit() to pair the free correctly and free HalData with vfree().
The bug was first flagged by an experimental static analysis tool we are developing for kernel memory-management bugs. Manual inspection confirms that the issue is still present in current mainline.
An x86_64 allyesconfig build showed no new warnings. As we do not have suitable RTL8723BS SDIO hardware to test with, no runtime testing was able to be performed.
--- drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/rtl8723bs/os_dep/sdio_intf.c +2 -2
@@ -310,8 +310,8 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct status = _SUCCESS; free_hal_data: -if (status != _SUCCESS && padapter->HalData) -kfree (padapter->HalData); +if (status != _SUCCESS) +rtw_hal_data_deinit (padapter);if (status != _SUCCESS) {rtw_wdev_unregister (padapter->rtw_wdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 666/1424 ALSA: via82xx: Remove unreachable branch in snd_via686_pcm_pointer()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Evgenii Burenchev <[email protected]>
[ Upstream commit cd3447e1b6425efd1704ed07f1f245c842927eb0 ]
The condition
if (count && size < count)
can never evaluate to true.
The VIA DMA count register is masked with 0x00ffffff before use, while the DMA buffer size is limited to 0x00fffffe bytes. As a result, 'count' can never exceed 'size', making the condition permanently false.
This branch has therefore been unreachable since the driver was introduced. Remove the unreachable branch without changing runtime behavior.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- sound/pci/via82xx_modem.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-)
sound/pci/via82xx_modem.c +10 -16
@@ -576,24 +576,18 @@ static inline unsigned int calc_linear_pos(struct via82xx_modem *chip, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count);#endif -if (count && size < count) { +if (! count) +/* bogus count 0 on the DMA boundary? */ + res = viadev->idx_table[idx].offset; +else +/* count register returns full size +* when end of buffer is reached +*/ + res = viadev->idx_table[idx].offset + size; +if (check_invalid_pos (viadev, res)) {dev_dbg (chip->card->dev, -"invalid via82xx_cur_ptr, using last valid pointer\n" ); +"invalid via82xx_cur_ptr (2), using last valid pointer\n" ); res = viadev->lastpos; - }else { -if (! count) -/* bogus count 0 on the DMA boundary? */ - res = viadev->idx_table[idx].offset; -else -/* count register returns full size -* when end of buffer is reached -*/ - res = viadev->idx_table[idx].offset + size; -if (check_invalid_pos (viadev, res)) { -dev_dbg (chip->card->dev, -"invalid via82xx_cur_ptr (2), using last valid pointer\n" ); - res = viadev->lastpos; - } } } viadev->lastpos = res;/* remember the last position */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 667/1424 selftests/bpf: Fix memory leak in msg_alloc_iov error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Malaya Kumar Rout <[email protected]>
[ Upstream commit 0bebfaa39deadec21638f6fba553eae12627a26d ]
In msg_alloc_iov(), when calloc() fails for an individual iov_base allocation, the error path frees all previously allocated iov_base entries but fails to free the iov array itself that was allocated with calloc() at the beginning of the function. This results in a memory leak of the iov array.
Add free(iov) in the unwind_iov error path to ensure proper cleanup of all allocated memory.
--- tools/testing/selftests/bpf/test_sockmap.c | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/test_sockmap.c +1 -0
@@ -514,6 +514,7 @@ static int msg_alloc_iov(struct msghdr *msg, unwind_iov:for (i--; i >=0 ; i--)free (msg->msg_iov[i].iov_base); +free (iov);return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 668/1424 selftests/bpf: Fix memory leak in msg_alloc_iov
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Yang <[email protected]>
[ Upstream commit 602701718649936eb287bf6c7ecf870ec54c6f71 ]
In the msg_alloc_iov function, the iov pointer is only assigned to msg->msg_iov after all memory allocations complete successfully. Therefore, when a calloc failure triggers the unwind_iov cleanup branch, we should use the local variable iov instead of msg->msg_iov.
--- tools/testing/selftests/bpf/test_sockmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/test_sockmap.c +1 -1
@@ -513,7 +513,7 @@ static int msg_alloc_iov(struct msghdr *msg,return 0 ; unwind_iov:for (i--; i >=0 ; i--) -free (msg->msg_iov[i].iov_base); +free (iov[i].iov_base);free (iov);return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 669/1424 irqchip/gic-v3-its: Fix memleak in its_probe_one()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kemeng Shi <[email protected]>
[ Upstream commit 1efffab6fe336a5c4fd3c2886f255cd2f998e65f ]
Fix collection leak when its_init_domain() failed in its_probe_one().
--- drivers/irqchip/irq-gic-v3-its.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +3 -1
@@ -5168,7 +5168,7 @@ static int __init its_probe_one(struct its_node *its) err =its_init_domain (its);if (err) - goto out_free_tables; + goto out_free_collection;raw_spin_lock (&its_lock);list_add (&its->entry, &its_nodes);
@@ -5176,6 +5176,8 @@ static int __init its_probe_one(struct its_node *its)return 0 ; +out_free_collection: +kfree (its->collections); out_free_tables:its_free_tables (its); out_free_cmd:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 670/1424 irqchip/gic-v3-its: Fix its node leak in gic_acpi_parse_madt_its()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kemeng Shi <[email protected]>
[ Upstream commit 698a8648ca8051d34722b09b8a8088c741120ac3 ]
Fix its node leak when its_probe_one() failed ingic_acpi_parse_madt_its().
--- drivers/irqchip/irq-gic-v3-its.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +6 -2
@@ -5586,9 +5586,13 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, } err =its_probe_one (its); -if (!err) -return 0 ; +if (err) + goto probe_err; + +return 0 ; +probe_err: +its_node_destroy (its); node_err:iort_deregister_domain_token (its_entry->translation_id); dom_err:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 671/1424 selftests: timers: leap-a-day: Fix -w option and update usage comment
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangshan Yi <[email protected]>
[ Upstream commit b4b66151a71445f3a71574136ddc82968c7b175e ]
Commit 98b74e1f3104 ("kselftests: timers: leap-a-day: Change default arguments to help test runs") replaced the -s option with -w and made "wait for the leap second" the non-default behaviour, but it only updated the switch/case handling. Two things were left inconsistent:
- The getopt() option string still lists 's' instead of 'w', so passing -w is rejected as an invalid option and the new behaviour cannot be selected at all.
- The file header comment still documents the removed -s option and an outdated default for -i.
Fix the getopt() string to accept 'w' (matching the existing case 'w':
handler) and update the header comment to describe -w, -t and the current -i default.
--- tools/testing/selftests/timers/leap-a-day.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
tools/testing/selftests/timers/leap-a-day.c +11 -8
@@ -9,16 +9,19 @@* kernel's leap-second behavior, as well as how well applications * handle the leap-second discontinuity. * -* Usage: leap-a-day [-s] [-i <num>] +* Usage: leap-a-day [-w] [-i <num>] [-t] * * Options: -* -s: Each iteration, set the date to 10 seconds before midnight GMT. -* This speeds up the number of leapsecond transitions tested, -* but because it calls settimeofday frequently, advancing the -* time by 24 hours every ~16 seconds, it may cause application -* disruption. +* -w: Only set the leap-second flag and wait for the leap second +* each iteration, instead of advancing the time. By default the +* date is set to 10 seconds before midnight GMT, which speeds up +* the number of leapsecond transitions tested, but because it +* calls settimeofday frequently, advancing the time by 24 hours +* every ~16 seconds, it may cause application disruption. * -* -i: Number of iterations to run (default: infinite) +* -i: Number of iterations to run (-1 = infinite, default: 10) +* +* -t: Print TAI time. * * Other notes: Disabling NTP prior to running this is advised, as the two * may conflict in their commands to the kernel.
@@ -186,7 +189,7 @@ int main(int argc, char **argv)int opt;/* Process arguments */ -while ((opt =getopt (argc, argv,"sti:" )) !=-1 ) { +while ((opt =getopt (argc, argv,"wti:" )) !=-1 ) {switch (opt) {case 'w' :printf ("Only setting leap-flag, not changing time. It could take up to a day for leap to trigger.\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 672/1424 clocksource: Unregister subsystem on device registration failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 3dee6537e728bd8137fda6eaf859f26e685943f7 ]
init_clocksource_sysfs() registers the clocksource subsystem before registering the clocksource device. If device_register() fails, the function returns the error while leaving the subsystem registered.
Unregister the clocksource subsystem on that failure path so the successful subsystem registration is unwound before returning.
--- kernel/time/clocksource.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/time/clocksource.c +6 -2
@@ -1482,8 +1482,12 @@ static int __init init_clocksource_sysfs(void) {int error =subsys_system_register (&clocksource_subsys,NULL ); -if (!error) - error =device_register (&device_clocksource); +if (error) +return error; + + error =device_register (&device_clocksource); +if (error) +bus_unregister (&clocksource_subsys);return error; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 673/1424 y2038: uapi: Use 64-bit __kernel_old_timespec::tv_nsec on x32
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
[ Upstream commit 79ced850e549e8c86b772a79ea417a1425b5c04b ]
'struct __kernel_old_timespec' represents the 'native' time ABI of the kernel. On 32-bit systems it uses 32-bit fields and on 64-bit systems it uses 64-bit fields.
However the x86 x32 ABI uses the 64-bit time ABI natively. This is correctly handled for the 'tv_sec' fields, through the typedefs of '__kernel_old_time_t' -> '__kernel_long_t' -> 'long long'. The same treatment was missed for 'tv_nsec'.
In practice this might not make much of a difference as the value of 'tv_nsec' will always fit into 32 bits and the missing bits fall into the padding of the structure.
When introspecting the structure however, a difference can be observed.
Switch to 64-bit tv_nsec on x32. No other architectures or ABIs are affected.
While this could be interpreted as violating the POSIX requirement of 'timespec::tv_nsec' being 'long':
* __kernel_old_timespec is not actually the POSIX timespec type
* the requirement is gone in newer versions of POSIX
* this matches glibc
--- include/uapi/linux/time_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/linux/time_types.h +1 -1
@@ -30,7 +30,7 @@ struct __kernel_old_timeval {struct __kernel_old_timespec {__kernel_old_time_t tv_sec;/* seconds */ -long tv_nsec;/* nanoseconds */ +__kernel_long_t tv_nsec;/* nanoseconds */ };struct __kernel_old_itimerval {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 674/1424 timekeeping: Account for monotonicity adjustment in ntp_error
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Woodhouse <[email protected]>
[ Upstream commit b7befd6d91207cf3f4cecd68fea0c212093906cf ]
timekeeping_apply_adjustment() modifies xtime_nsec to ensure monotonicity when mult changes:
xtime_nsec -= offset
This ensures that the time reported to userspace does not jump when the multiplier is adjusted from one tick to the next. However, the ntp_error accumulator which tracks the difference between intended and actual clock position was not being updated to reflect this additional discrepancy.
An earlier attempt at this compensation existed as:
ntp_error -= (interval - offset) << ntp_error_shift
but was removed in commit c2cda2a5bda9 ("timekeeping/ntp: Don't align NTP frequency adjustments to ticks") because it was a major source of NTP error. That's because (interval - offset) was wrong: the subtraction of "interval" prematurely accounted for the changed xtime_interval of the next tick, which would be correctly accounted in the next accumulation anyway — a double subtraction.
What is actually needed is just the "offset" part: ntp_error must be told that xtime_nsec moved by "offset" without a corresponding change in the intended position. For the normal ±1 mult dithering this is negligible (the adjustments cancel over time), but for larger mult changes — such as when an external reference clock sets a new frequency — the one-time uncompensated offset is significant.
Fix by adjusting ntp_error by the correct amount:
ntp_error += offset << ntp_error_shift
This keeps ntp_error consistent with the actual xtime_nsec position after the adjustment, and ensures the discrepancy is correctly smoothed away over time and the clock returns to where it should have been.
--- kernel/time/timekeeping.c | 6 ++++++ 1 file changed, 6 insertions(+)
kernel/time/timekeeping.c +6 -0
@@ -1983,6 +1983,11 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,* xtime_nsec_2 = xtime_nsec_1 - offset * Which simplifies to: * xtime_nsec -= offset +* +* When subtracting offset from xtime_nsec, the same amount +* (in appropriate units) has to be added to ntp_error, in +* order to correctly track the delta between the time +* reported in xtime_nsec, and the intended time. */ if ((mult_adj >0 ) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {/* NTP adjustment caused clocksource mult overflow */
@@ -1993,6 +1998,7 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk, tk->tkr_mono.mult += mult_adj; tk->xtime_interval += interval; tk->tkr_mono.xtime_nsec -= offset; + tk->ntp_error += offset << tk->ntp_error_shift; }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 675/1424 clk: qcom: gdsc: propagate gdsc_check_status() errors from gdsc_poll_status
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herman van Hazendonk <[email protected]>
[ Upstream commit d69f0c2b8d292b4890c9f0fbe184dfc26c4de86c ]
gdsc_check_status() returns negative errno when the underlying regmap_read() fails -- e.g. when a parent regmap dies during system suspend, a CSR is removed by an HW debug tool, or the bus controller goes into protection. gdsc_poll_status() treats the result as a plain boolean ("is the GDSC in the requested state?"), so any negative error return is truncated to "true" and the poll exits with success even though the rail's real state is unknown:
do {
if (gdsc_check_status(sc, status))
return 0;
} while (ktime_us_delta(ktime_get(), start) < STATUS_POLL_TIMEOUT_US);
if (gdsc_check_status(sc, status))
return 0;
return -ETIMEDOUT;This silently misleads gdsc_toggle_logic() (which writes/un-writes SW_COLLAPSE on the strength of the poll succeeding) and the gdsc_init() sync path (which assumes the readback represents real silicon state).
Latch the return value, propagate negative errno immediately, and only treat a strictly-positive value as "reached the target state". Make the same change in the post-timeout final check so a regmap that comes back after the deadline does not silently degrade to -ETIMEDOUT.
--- drivers/clk/qcom/gdsc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/clk/qcom/gdsc.c +9 -2
@@ -103,14 +103,21 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)static int gdsc_poll_status (struct gdsc *sc,enum gdsc_status status) {ktime_t start; +int ret; start =ktime_get ();do { -if (gdsc_check_status (sc, status)) + ret =gdsc_check_status (sc, status); +if (ret <0 ) +return ret; +if (ret)return 0 ; }while (ktime_us_delta (ktime_get (), start) <STATUS_POLL_TIMEOUT_US ); -if (gdsc_check_status (sc, status)) + ret =gdsc_check_status (sc, status); +if (ret <0 ) +return ret; +if (ret)return 0 ;return -ETIMEDOUT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 676/1424 clk: qcom: gdsc: propagate gdsc_enable() failure for ALWAYS_ON domains
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herman van Hazendonk <[email protected]>
[ Upstream commit eea55fc694e132aacbe2cf4be7f345115e3d1801 ]
GENPD_FLAG_ALWAYS_ON requires the underlying domain to be on at genpd_init() time -- the framework will refuse to register the domain otherwise. When the cold readback in gdsc_init() finds an ALWAYS_ON GDSC powered down, the driver tries to bring it back up:
} else if (sc->flags & ALWAYS_ON) {
/* If ALWAYS_ON GDSCs are not ON, turn them ON */
gdsc_enable(&sc->pd);
on = true;
}but discards the return value: if gdsc_enable() fails (regmap write error, the long-form sequence's status poll times out, or the HW_CTRL hand-off errors) the code still sets on=true and falls through to pm_genpd_init(..., !on) -- which then registers the domain in the ON state and sets GENPD_FLAG_ALWAYS_ON, even though the silicon is actually off. Subsequent consumer probes will see genpd report "on" while accessing dead registers and hang or read garbage.
Catch the failure and surface it: returning the error from gdsc_init() makes the provider probe fail with the underlying errno, which propagates to consumers as -EPROBE_DEFER (or fatal if the hardware really is broken) rather than silently lying about the rail state.
--- drivers/clk/qcom/gdsc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/clk/qcom/gdsc.c +3 -1
@@ -444,7 +444,9 @@ static int gdsc_init(struct gdsc *sc) }else if (sc->flags &ALWAYS_ON ) {/* If ALWAYS_ON GDSCs are not ON, turn them ON */ -gdsc_enable (&sc->pd); + ret =gdsc_enable (&sc->pd); +if (ret) +return ret; on = true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 677/1424 clk: qcom: gdsc: tear down per-domain genpds in gdsc_unregister()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herman van Hazendonk <[email protected]>
[ Upstream commit 86b23609d5e17a770d03037e53c6a443e742a6e6 ]
gdsc_unregister() removes the OF provider entry and tears down the parent/subdomain wiring, but never calls pm_genpd_remove() on the individual generic_pm_domain structures registered by gdsc_init():
void gdsc_unregister(struct gdsc_desc *desc)
{
struct device *dev = desc->dev;
size_t num = desc->num;
gdsc_pm_subdomain_remove(desc, num);
of_genpd_del_provider(dev->of_node);
}That leaves dangling entries on the global gpd_list. After a provider unbind/rebind cycle (deferred-probe replay during early boot, real module unload of a clk driver that owns GDSCs, or an OF-overlay tear- down) the next gdsc_init() will end up trying to re-register a name that is still in the list and pm_genpd_init() returns -EEXIST.
While we are here, flip the order so the consumer-facing OF provider entry is the first thing removed -- otherwise a fresh of_genpd_get_from_provider() call racing with the teardown could attach to a domain that is mid-removal.
Iterate the scs[] array and pm_genpd_remove() each registered domain after the subdomain links are torn down. The regulators stay devm- managed (devm_regulator_get_optional() in gdsc_register()), so the release happens automatically when the underlying device is unbound; just the genpd accounting needs to be undone explicitly.
--- drivers/clk/qcom/gdsc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/clk/qcom/gdsc.c +9 -1
@@ -554,10 +554,18 @@ int gdsc_register(struct gdsc_desc *desc,void gdsc_unregister (struct gdsc_desc *desc) {struct device *dev = desc->dev; +struct gdsc **scs = desc->scs;size_t num = desc->num; +int i; -gdsc_pm_subdomain_remove (desc, num);of_genpd_del_provider (dev->of_node); +gdsc_pm_subdomain_remove (desc, num); + +for (i =0 ; i < num; i++) { +if (!scs[i]) +continue ; +pm_genpd_remove (&scs[i]->pd); + } }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 678/1424 arm64: dts: qcom: sc8180x-primus: Rename regulator nodes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit ae51d9396f9318189e91578878409d8ada152edb ]
The nodes would be sorted correctly, if their names started with "regulator-" (which is the style used in the latest submissions). Touch that up.
Stable-dep-of: 80bf2eb87bfb ("arm64: dts: qcom: sc8180x-primus: Describe the display power net")
--- arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sc8180x-primus.dts +4 -4
@@ -164,7 +164,7 @@ reserved-region@9a500000 { }; }; - vreg_nvme_0p9: nvme-0p9-regulator { + vreg_nvme_0p9: regulator-nvme-0p9 { compatible = "regulator-fixed"; regulator-name = "vreg_nvme_0p9";
@@ -174,7 +174,7 @@ vreg_nvme_0p9: nvme-0p9-regulator { regulator-always-on; }; - vreg_nvme_3p3: nvme-3p3-regulator { + vreg_nvme_3p3: regulator-nvme-3p3 { compatible = "regulator-fixed"; regulator-name = "vreg_nvme_3p3";
@@ -187,7 +187,7 @@ vreg_nvme_3p3: nvme-3p3-regulator { regulator-always-on; }; - vdd_kb_tp_3v3: vdd-kb-tp-3v3-regulator { + vdd_kb_tp_3v3: regulator-vdd-kb-tp-3v3 { compatible = "regulator-fixed"; regulator-name = "vdd_kb_tp_3v3"; regulator-min-microvolt = <3300000>;
@@ -202,7 +202,7 @@ vdd_kb_tp_3v3: vdd-kb-tp-3v3-regulator { pinctrl-0 = <&kb_tp_3v3_en_active_state>; }; - vph_pwr: vph-pwr-regulator { + vph_pwr: regulator-vph-pwr { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; regulator-min-microvolt = <3700000>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 679/1424 arm64: dts: qcom: sc8180x-lenovo-flex-5g: move pinctrl to appropriate nodes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anton Bambura <[email protected]>
[ Upstream commit 0d76ffe33e5eb5b0a7bd09e4fa8a72f7f4cfbc0d ]
Split keyboard and touchpad pinctrl nodes since they are for different devices and move keyboard, touchpad and touchscreen pinctrl references to appropriate nodes.
Stable-dep-of: d5f5c089858f ("arm64: dts: qcom: sc8180x-lenovo-flex-5g: Describe the display power net")
--- .../boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-)
arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +29 -12
@@ -356,7 +356,7 @@ zap-shader { &i2c1 { clock-frequency = <100000>; - pinctrl-0 = <&i2c1_active>, <&i2c1_hid_active>; + pinctrl-0 = <&i2c1_active>; pinctrl-names = "default"; status = "okay";
@@ -367,13 +367,16 @@ hid@10 { hid-descr-addr = <0x1>; interrupts-extended = <&tlmm 122 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&ts_int_default>; + pinctrl-names = "default"; }; }; &i2c7 { clock-frequency = <100000>; - pinctrl-0 = <&i2c7_active>, <&i2c7_hid_active>; + pinctrl-0 = <&i2c7_active>; pinctrl-names = "default"; status = "okay";
@@ -384,6 +387,9 @@ hid@5 { hid-descr-addr = <0x20>; interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&kb_int_default>; + pinctrl-names = "default"; }; hid@2c {
@@ -392,6 +398,9 @@ hid@2c { hid-descr-addr = <0x20>; interrupts-extended = <&tlmm 24 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&tp_int_default>; + pinctrl-names = "default"; }; };
@@ -668,14 +677,6 @@ i2c1_active: i2c1-active-state { drive-strength = <2>; }; - i2c1_hid_active: i2c1-hid-active-state { - pins = "gpio122"; - function = "gpio"; - - bias-pull-up; - drive-strength = <2>; - }; - i2c7_active: i2c7-active-state { pins = "gpio98", "gpio99"; function = "qup7";
@@ -684,8 +685,8 @@ i2c7_active: i2c7-active-state { drive-strength = <2>; }; - i2c7_hid_active: i2c7-hid-active-state { - pins = "gpio37", "gpio24"; + kb_int_default: kb-int-default-state { + pins = "gpio37"; function = "gpio"; bias-pull-up;
@@ -717,6 +718,22 @@ wake-n-pins { }; }; + tp_int_default: tp-int-default-state { + pins = "gpio24"; + function = "gpio"; + + bias-pull-up; + drive-strength = <2>; + }; + + ts_int_default: ts-int-default-state { + pins = "gpio122"; + function = "gpio"; + + bias-pull-up; + drive-strength = <2>; + }; + usbprim_sbu_default: usbprim-sbu-state { oe-n-pins { pins = "gpio152";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 680/1424 arm64: dts: qcom: sc8180x: Enable the power key
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <[email protected]>
[ Upstream commit 3706bcfbdb8aecdb506b80e45e2e5851044f1f28 ]
No input events are generated from the pressing of the power key on either Primus or Flex 5G, because the device node isn't enabled.
Give the power key node a label and enable this for the two devices.
Stable-dep-of: d5f5c089858f ("arm64: dts: qcom: sc8180x-lenovo-flex-5g: Describe the display power net")
--- arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 4 ++++ arch/arm64/boot/dts/qcom/sc8180x-pmics.dtsi | 2 +- arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +4 -0
@@ -475,6 +475,10 @@ &pcie3_phy { status = "okay"; }; +&pmc8180_pwrkey { + status = "okay"; +}; + &pmc8180c_lpg { status = "okay"; };
arch/arm64/boot/dts/qcom/sc8180x-pmics.dtsi +1 -1
@@ -77,7 +77,7 @@ pmc8180_0: pmic@0 { pon: pon@800 { compatible = "qcom,pm8916-pon"; reg = <0x0800>; - pwrkey { + pmc8180_pwrkey: pwrkey { compatible = "qcom,pm8941-pwrkey"; interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>; debounce = <15625>;
arch/arm64/boot/dts/qcom/sc8180x-primus.dts +4 -0
@@ -545,6 +545,10 @@ &pcie1_phy { status = "okay"; }; +&pmc8180_pwrkey { + status = "okay"; +}; + &pmc8180c_lpg { status = "okay"; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 681/1424 arm64: dts: qcom: sc8180x-lenovo-flex-5g: Rename regulator nodes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 0b1c6d2a65fc41aa0d5f6617dd04043384678d61 ]
Align with the contemporary way of naming regulator nodes (regulator- prefix) in preparation for adding more of them.
Reorder the renamed entries to match the expectations of the DT coding style doc.
Stable-dep-of: d5f5c089858f ("arm64: dts: qcom: sc8180x-lenovo-flex-5g: Describe the display power net")
--- .../boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +8 -8
@@ -159,14 +159,7 @@ cdsp_mem: cdsp-region@98900000 { }; }; - vph_pwr: vph-pwr-regulator { - compatible = "regulator-fixed"; - regulator-name = "vph_pwr"; - regulator-min-microvolt = <3700000>; - regulator-max-microvolt = <3700000>; - }; - - vreg_s4a_1p8: pm8150-s4-regulator { + vreg_s4a_1p8: regulator-pm8150-s4 { compatible = "regulator-fixed"; regulator-name = "vreg_s4a_1p8";
@@ -179,6 +172,13 @@ vreg_s4a_1p8: pm8150-s4-regulator { vin-supply = <&vph_pwr>; }; + vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + usbprim-sbu-mux { compatible = "pericom,pi3usb102", "gpio-sbu-mux";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 682/1424 perf data convert json: Fix trace_seq memory leak in process_sample_event()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tanushree Shah <[email protected]>
[ Upstream commit dcb87c88952046ef43cb5ba3a5b95eb29c362a16 ]
Unlike the in-kernel trace_seq which uses a statically allocated buffer, the userspace traceevent library's trace_seq uses a dynamically allocated one. Therefore, every trace_seq_init() call must be paired with a trace_seq_destroy(), otherwise it produces a memory leak.
In process_sample_event(), a trace_seq is initialized for each field when formatting tracepoint raw_data, but the matching trace_seq_destroy() is never called, leaking memory for every field of every sample processed.
Add the missing trace_seq_destroy() after using the trace_seq buffer to properly free the allocated memory.
Detected with Valgrind on a perf.data file with 2,729 tracepoint samples:
Before: definitely lost: 55,537,664 bytes in 13,559 blocks
After: definitely lost: 0 bytes in 0 blocks
--- tools/perf/util/data-convert-json.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/data-convert-json.c +1 -0
@@ -242,6 +242,7 @@ static int process_sample_event(struct perf_tool *tool,trace_seq_init (&s);tep_print_field (&s, sample->raw_data, fields[i]);output_json_key_string (out, true,3 , fields[i]->name, s.buffer); +trace_seq_destroy (&s); i++; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 683/1424 thermal/drivers/rcar: Fix error checking in probe()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit dd04ad1cdabcad51e34b74b4e91b9aeb7180d05d ]
This code accidentally calls thermal_zone_device_enable() before checking whether thermal_zone_device_register_with_trips() failed. Move the call until later to avoid an error pointer dereference of "priv->zone".
The driver works differently depending on if we are using OF thermal or not. We use thermal_add_hwmon_sysfs() if we are using OF thermal and call thermal_zone_device_enable() if not. We can share same error check for if either of these fail.
Moving the thermal_zone_device_enable() call is a bit cleaner as well. The original code used a three step process to cleanup:
1. Call thermal_zone_device_unregister() to cleanup.
2. Set priv->zone to an error pointer to preserve the error code.
3. Set priv->zone to NULL to avoid a second call to thermal_zone_device_unregister() in the rcar_thermal_remove() function.
Now we can just do a direct goto error_unregister and rcar_thermal_remove() handles the cleanup properly.
--- drivers/thermal/rcar_thermal.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-)
drivers/thermal/rcar_thermal.c +5 -10
@@ -494,12 +494,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)"rcar_thermal" , trips,ARRAY_SIZE (trips),0 , priv, &rcar_thermal_zone_ops,NULL ,0 , idle); - - ret =thermal_zone_device_enable (priv->zone); -if (ret) { -thermal_zone_device_unregister (priv->zone); - priv->zone =ERR_PTR (ret); - } }if (IS_ERR (priv->zone)) {dev_err (dev,"can't register thermal zone\n" );
@@ -508,11 +502,12 @@ static int rcar_thermal_probe(struct platform_device *pdev) goto error_unregister; } -if (chip->use_of_thermal) { +if (chip->use_of_thermal) ret =thermal_add_hwmon_sysfs (priv->zone); -if (ret) - goto error_unregister; - } +else + ret =thermal_zone_device_enable (priv->zone); +if (ret) + goto error_unregister;rcar_thermal_irq_enable (priv);
Signature · 1 line
2.53.0