From 018222497abb6c8c4787acc21f956fc9d74870f2 Mon Sep 17 00:00:00 2001 From: Andrew Lukoshko Date: Thu, 11 Jun 2026 12:06:00 +0000 Subject: [PATCH] Recreate RHEL 5.14.0-687.15.1 from CS9/upstream backports Add the RHEL 687.14.1..687.15.1 backports (1270-1284) from centos-stream-9 and upstream stable, on top of 687.13.1. The dpll/zl3073x and ice RSS-queue series are consolidated (they carry RHEL kABI wrapping and RHEL-only files). The mlx5 kabi removal (RHEL-181822) is applied via updated Module.kabi_{aarch64,s390x,x86_64}. Bump pkgrelease and specrelease to 687.15.1. --- ...ack-allocated-node-in-kvm-async-pf-q.patch | 86 + ...se-after-free-in-bond-xmit-broadcast.patch | 86 + ...e-after-free-in-iscsit-dec-conn-usag.patch | 43 + ...se-after-free-in-add-adev-error-path.patch | 69 + ...ire-fix-use-after-free-on-disconnect.patch | 90 + ...lidate-length-in-dlm-search-rsb-tree.patch | 47 + ...from-negative-len-in-dlm-search-rsb-.patch | 69 + ...sure-safe-access-to-master-conntrack.patch | 222 ++ ...fix-double-free-in-rxe-srq-from-init.patch | 59 + ...leasing-netdev-before-teardown-compl.patch | 121 + ...6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch | 51 + SOURCES/1281-ipv6-rpl-headroom.patch | 37 + SOURCES/1282-rdma-mlx4-srq.patch | 37 + SOURCES/1283-dpll-series-RHEL.patch | 3225 +++++++++++++++++ SOURCES/1284-ice-rss-queues-RHEL.patch | 256 ++ SOURCES/Module.kabi_aarch64 | 157 - SOURCES/Module.kabi_s390x | 157 - SOURCES/Module.kabi_x86_64 | 157 - SPECS/kernel.spec | 77 +- 19 files changed, 4573 insertions(+), 473 deletions(-) create mode 100644 SOURCES/1270-x86-kvm-avoid-freeing-stack-allocated-node-in-kvm-async-pf-q.patch create mode 100644 SOURCES/1271-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch create mode 100644 SOURCES/1272-scsi-target-iscsi-fix-use-after-free-in-iscsit-dec-conn-usag.patch create mode 100644 SOURCES/1273-net-mana-fix-use-after-free-in-add-adev-error-path.patch create mode 100644 SOURCES/1274-alsa-6fire-fix-use-after-free-on-disconnect.patch create mode 100644 SOURCES/1275-dlm-validate-length-in-dlm-search-rsb-tree.patch create mode 100644 SOURCES/1276-dlm-fix-buffer-overflow-from-negative-len-in-dlm-search-rsb-.patch create mode 100644 SOURCES/1277-netfilter-ctnetlink-ensure-safe-access-to-master-conntrack.patch create mode 100644 SOURCES/1278-rdma-rxe-fix-double-free-in-rxe-srq-from-init.patch create mode 100644 SOURCES/1279-net-openvswitch-avoid-releasing-netdev-before-teardown-compl.patch create mode 100644 SOURCES/1280-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch create mode 100644 SOURCES/1281-ipv6-rpl-headroom.patch create mode 100644 SOURCES/1282-rdma-mlx4-srq.patch create mode 100644 SOURCES/1283-dpll-series-RHEL.patch create mode 100644 SOURCES/1284-ice-rss-queues-RHEL.patch diff --git a/SOURCES/1270-x86-kvm-avoid-freeing-stack-allocated-node-in-kvm-async-pf-q.patch b/SOURCES/1270-x86-kvm-avoid-freeing-stack-allocated-node-in-kvm-async-pf-q.patch new file mode 100644 index 000000000..21d245b2b --- /dev/null +++ b/SOURCES/1270-x86-kvm-avoid-freeing-stack-allocated-node-in-kvm-async-pf-q.patch @@ -0,0 +1,86 @@ +From c29c799bc106385fe74e3a9a51c58087c8f9e725 Mon Sep 17 00:00:00 2001 +From: Ryosuke Yasuoka +Date: Thu, 15 Jan 2026 13:31:39 +0900 +Subject: [PATCH] x86/kvm: Avoid freeing stack-allocated node in + kvm_async_pf_queue_task + +JIRA: https://issues.redhat.com/browse/RHEL-125085 + +commit 95cc9e7cf03d3646abce4129d5c013af33a7df99 +Author: Ryosuke Yasuoka +Date: Sat Dec 6 23:09:36 2025 +0900 + + x86/kvm: Avoid freeing stack-allocated node in kvm_async_pf_queue_task + + kvm_async_pf_queue_task() can incorrectly try to kfree() a node + allocated on the stack of kvm_async_pf_task_wait_schedule(). + + This occurs when a task requests a PF while another task's PF request + with the same token is still pending. Since the token is derived from + the (u32)address in exc_page_fault(), two different tasks can generate + the same token. + + Currently, kvm_async_pf_queue_task() assumes that any entry found in the + list is a dummy entry and tries to kfree() it. To fix this, add a flag + to the node structure to distinguish stack-allocated nodes, and only + kfree() the node if it is a dummy entry. + + Signed-off-by: Ryosuke Yasuoka + Message-ID: <20251206140939.144038-1-ryasuoka@redhat.com> + Signed-off-by: Paolo Bonzini + +Signed-off-by: Ryosuke Yasuoka + +diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c +index c8b1db5c914c..16d4e504bedf 100644 +--- a/arch/x86/kernel/kvm.c ++++ b/arch/x86/kernel/kvm.c +@@ -86,6 +86,7 @@ struct kvm_task_sleep_node { + struct swait_queue_head wq; + u32 token; + int cpu; ++ bool dummy; + }; + + static struct kvm_task_sleep_head { +@@ -117,15 +118,26 @@ static bool kvm_async_pf_queue_task(u32 token, struct kvm_task_sleep_node *n) + raw_spin_lock(&b->lock); + e = _find_apf_task(b, token); + if (e) { +- /* dummy entry exist -> wake up was delivered ahead of PF */ +- hlist_del(&e->link); ++ struct kvm_task_sleep_node *dummy = NULL; ++ ++ /* ++ * The entry can either be a 'dummy' entry (which is put on the ++ * list when wake-up happens ahead of APF handling completion) ++ * or a token from another task which should not be touched. ++ */ ++ if (e->dummy) { ++ hlist_del(&e->link); ++ dummy = e; ++ } ++ + raw_spin_unlock(&b->lock); +- kfree(e); ++ kfree(dummy); + return false; + } + + n->token = token; + n->cpu = smp_processor_id(); ++ n->dummy = false; + init_swait_queue_head(&n->wq); + hlist_add_head(&n->link, &b->list); + raw_spin_unlock(&b->lock); +@@ -228,6 +240,7 @@ void kvm_async_pf_task_wake(u32 token) + } + dummy->token = token; + dummy->cpu = smp_processor_id(); ++ dummy->dummy = true; + init_swait_queue_head(&dummy->wq); + hlist_add_head(&dummy->link, &b->list); + dummy = NULL; +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1271-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch b/SOURCES/1271-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch new file mode 100644 index 000000000..e15849eca --- /dev/null +++ b/SOURCES/1271-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch @@ -0,0 +1,86 @@ +From 2884bf72fb8f03409e423397319205de48adca16 Mon Sep 17 00:00:00 2001 +From: Xiang Mei +Date: Thu, 26 Mar 2026 00:55:53 -0700 +Subject: [PATCH] net: bonding: fix use-after-free in bond_xmit_broadcast() + +bond_xmit_broadcast() reuses the original skb for the last slave +(determined by bond_is_last_slave()) and clones it for others. +Concurrent slave enslave/release can mutate the slave list during +RCU-protected iteration, changing which slave is "last" mid-loop. +This causes the original skb to be double-consumed (double-freed). + +Replace the racy bond_is_last_slave() check with a simple index +comparison (i + 1 == slaves_count) against the pre-snapshot slave +count taken via READ_ONCE() before the loop. This preserves the +zero-copy optimization for the last slave while making the "last" +determination stable against concurrent list mutations. + +The UAF can trigger the following crash: + +================================================================== +BUG: KASAN: slab-use-after-free in skb_clone +Read of size 8 at addr ffff888100ef8d40 by task exploit/147 + +CPU: 1 UID: 0 PID: 147 Comm: exploit Not tainted 7.0.0-rc3+ #4 PREEMPTLAZY +Call Trace: + + dump_stack_lvl (lib/dump_stack.c:123) + print_report (mm/kasan/report.c:379 mm/kasan/report.c:482) + kasan_report (mm/kasan/report.c:597) + skb_clone (include/linux/skbuff.h:1724 include/linux/skbuff.h:1792 include/linux/skbuff.h:3396 net/core/skbuff.c:2108) + bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5334) + bond_start_xmit (drivers/net/bonding/bond_main.c:5567 drivers/net/bonding/bond_main.c:5593) + dev_hard_start_xmit (include/linux/netdevice.h:5325 include/linux/netdevice.h:5334 net/core/dev.c:3871 net/core/dev.c:3887) + __dev_queue_xmit (include/linux/netdevice.h:3601 net/core/dev.c:4838) + ip6_finish_output2 (include/net/neighbour.h:540 include/net/neighbour.h:554 net/ipv6/ip6_output.c:136) + ip6_finish_output (net/ipv6/ip6_output.c:208 net/ipv6/ip6_output.c:219) + ip6_output (net/ipv6/ip6_output.c:250) + ip6_send_skb (net/ipv6/ip6_output.c:1985) + udp_v6_send_skb (net/ipv6/udp.c:1442) + udpv6_sendmsg (net/ipv6/udp.c:1733) + __sys_sendto (net/socket.c:730 net/socket.c:742 net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + +Allocated by task 147: + +Freed by task 147: + +The buggy address belongs to the object at ffff888100ef8c80 + which belongs to the cache skbuff_head_cache of size 224 +The buggy address is located 192 bytes inside of + freed 224-byte region [ffff888100ef8c80, ffff888100ef8d60) + +Memory state around the buggy address: + ffff888100ef8c00: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc + ffff888100ef8c80: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff888100ef8d00: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc + ^ + ffff888100ef8d80: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb + ffff888100ef8e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== + +Fixes: 4e5bd03ae346 ("net: bonding: fix bond_xmit_broadcast return value error bug") +Reported-by: Weiming Shi +Signed-off-by: Xiang Mei +Link: https://patch.msgid.link/20260326075553.3960562-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni + +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 33f414d03ab9..a5484d11553d 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -5326,7 +5326,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, + if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) + continue; + +- if (bond_is_last_slave(bond, slave)) { ++ if (i + 1 == slaves_count) { + skb2 = skb; + skb_used = true; + } else { +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1272-scsi-target-iscsi-fix-use-after-free-in-iscsit-dec-conn-usag.patch b/SOURCES/1272-scsi-target-iscsi-fix-use-after-free-in-iscsit-dec-conn-usag.patch new file mode 100644 index 000000000..5f52c494c --- /dev/null +++ b/SOURCES/1272-scsi-target-iscsi-fix-use-after-free-in-iscsit-dec-conn-usag.patch @@ -0,0 +1,43 @@ +From 9411a89e9e7135cc459178fa77a3f1d6191ae903 Mon Sep 17 00:00:00 2001 +From: Maurizio Lombardi +Date: Mon, 12 Jan 2026 17:53:51 +0100 +Subject: [PATCH] scsi: target: iscsi: Fix use-after-free in + iscsit_dec_conn_usage_count() + +In iscsit_dec_conn_usage_count(), the function calls complete() while +holding the conn->conn_usage_lock. As soon as complete() is invoked, the +waiter (such as iscsit_close_connection()) may wake up and proceed to free +the iscsit_conn structure. + +If the waiter frees the memory before the current thread reaches +spin_unlock_bh(), it results in a KASAN slab-use-after-free as the function +attempts to release a lock within the already-freed connection structure. + +Fix this by releasing the spinlock before calling complete(). + +Signed-off-by: Maurizio Lombardi +Reported-by: Zhaojuan Guo +Reviewed-by: Mike Christie +Link: https://patch.msgid.link/20260112165352.138606-2-mlombard@redhat.com +Signed-off-by: Martin K. Petersen + +diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c +index 5e6cf34929b5..3319394bf542 100644 +--- a/drivers/target/iscsi/iscsi_target_util.c ++++ b/drivers/target/iscsi/iscsi_target_util.c +@@ -810,8 +810,11 @@ void iscsit_dec_conn_usage_count(struct iscsit_conn *conn) + spin_lock_bh(&conn->conn_usage_lock); + conn->conn_usage_count--; + +- if (!conn->conn_usage_count && conn->conn_waiting_on_uc) ++ if (!conn->conn_usage_count && conn->conn_waiting_on_uc) { ++ spin_unlock_bh(&conn->conn_usage_lock); + complete(&conn->conn_waiting_on_uc_comp); ++ return; ++ } + + spin_unlock_bh(&conn->conn_usage_lock); + } +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1273-net-mana-fix-use-after-free-in-add-adev-error-path.patch b/SOURCES/1273-net-mana-fix-use-after-free-in-add-adev-error-path.patch new file mode 100644 index 000000000..effc80694 --- /dev/null +++ b/SOURCES/1273-net-mana-fix-use-after-free-in-add-adev-error-path.patch @@ -0,0 +1,69 @@ +From d23a5f0e39e18eafc25a9ac4cbc7b26fbfdea21e Mon Sep 17 00:00:00 2001 +From: CKI Backport Bot +Date: Fri, 1 May 2026 19:22:31 +0000 +Subject: [PATCH] net: mana: fix use-after-free in add_adev() error path + +JIRA: https://redhat.atlassian.net/browse/RHEL-172769 +CVE: CVE-2026-43056 + +commit c4ea7d8907cf72b259bf70bd8c2e791e1c4ff70f +Author: Guangshuo Li +Date: Tue Mar 24 00:57:30 2026 +0800 + + net: mana: fix use-after-free in add_adev() error path + + If auxiliary_device_add() fails, add_adev() jumps to add_fail and calls + auxiliary_device_uninit(adev). + + The auxiliary device has its release callback set to adev_release(), + which frees the containing struct mana_adev. Since adev is embedded in + struct mana_adev, the subsequent fall-through to init_fail and access + to adev->id may result in a use-after-free. + + Fix this by saving the allocated auxiliary device id in a local + variable before calling auxiliary_device_add(), and use that saved id + in the cleanup path after auxiliary_device_uninit(). + + Fixes: a69839d4327d ("net: mana: Add support for auxiliary device") + Cc: stable@vger.kernel.org + Reviewed-by: Long Li + Signed-off-by: Guangshuo Li + Link: https://patch.msgid.link/20260323165730.945365-1-lgs201920130244@gmail.com + Signed-off-by: Jakub Kicinski + +Signed-off-by: CKI Backport Bot + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 055a84643d14..a64ef3e227bc 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3196,6 +3196,7 @@ static int add_adev(struct gdma_dev *gd, const char *name) + struct auxiliary_device *adev; + struct mana_adev *madev; + int ret; ++ int id; + + madev = kzalloc(sizeof(*madev), GFP_KERNEL); + if (!madev) +@@ -3205,7 +3206,8 @@ static int add_adev(struct gdma_dev *gd, const char *name) + ret = mana_adev_idx_alloc(); + if (ret < 0) + goto idx_fail; +- adev->id = ret; ++ id = ret; ++ adev->id = id; + + adev->name = name; + adev->dev.parent = gd->gdma_context->dev; +@@ -3231,7 +3233,7 @@ static int add_adev(struct gdma_dev *gd, const char *name) + auxiliary_device_uninit(adev); + + init_fail: +- mana_adev_idx_free(adev->id); ++ mana_adev_idx_free(id); + + idx_fail: + kfree(madev); +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1274-alsa-6fire-fix-use-after-free-on-disconnect.patch b/SOURCES/1274-alsa-6fire-fix-use-after-free-on-disconnect.patch new file mode 100644 index 000000000..c574e9697 --- /dev/null +++ b/SOURCES/1274-alsa-6fire-fix-use-after-free-on-disconnect.patch @@ -0,0 +1,90 @@ +From e3fcfc25d4d21b251685ba9ce984e87b674a0fad Mon Sep 17 00:00:00 2001 +From: CKI Backport Bot +Date: Mon, 4 May 2026 08:31:07 +0000 +Subject: [PATCH] ALSA: 6fire: fix use-after-free on disconnect + +JIRA: https://redhat.atlassian.net/browse/RHEL-172970 +CVE: CVE-2026-31581 + +commit b9c826916fdce6419b94eb0cd8810fdac18c2386 +Author: Berk Cem Goksel +Date: Fri Apr 10 08:13:41 2026 +0300 + + ALSA: 6fire: fix use-after-free on disconnect + + In usb6fire_chip_abort(), the chip struct is allocated as the card's + private data (via snd_card_new with sizeof(struct sfire_chip)). When + snd_card_free_when_closed() is called and no file handles are open, the + card and embedded chip are freed synchronously. The subsequent + chip->card = NULL write then hits freed slab memory. + + Call trace: + usb6fire_chip_abort sound/usb/6fire/chip.c:59 [inline] + usb6fire_chip_disconnect+0x348/0x358 sound/usb/6fire/chip.c:182 + usb_unbind_interface+0x1a8/0x88c drivers/usb/core/driver.c:458 + ... + hub_event+0x1a04/0x4518 drivers/usb/core/hub.c:5953 + + Fix by moving the card lifecycle out of usb6fire_chip_abort() and into + usb6fire_chip_disconnect(). The card pointer is saved in a local + before any teardown, snd_card_disconnect() is called first to prevent + new opens, URBs are aborted while chip is still valid, and + snd_card_free_when_closed() is called last so chip is never accessed + after the card may be freed. + + Fixes: a0810c3d6dd2 ("ALSA: 6fire: Release resources at card release") + Cc: stable@vger.kernel.org + Cc: Andrey Konovalov + Signed-off-by: Berk Cem Goksel + Link: https://patch.msgid.link/20260410051341.1069716-1-berkcgoksel@gmail.com + Signed-off-by: Takashi Iwai + +Signed-off-by: CKI Backport Bot + +diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c +index 5ff78814e687..874f6cd503ca 100644 +--- a/sound/usb/6fire/chip.c ++++ b/sound/usb/6fire/chip.c +@@ -53,11 +53,6 @@ static void usb6fire_chip_abort(struct sfire_chip *chip) + usb6fire_comm_abort(chip); + if (chip->control) + usb6fire_control_abort(chip); +- if (chip->card) { +- snd_card_disconnect(chip->card); +- snd_card_free_when_closed(chip->card); +- chip->card = NULL; +- } + } + } + +@@ -168,6 +163,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, + static void usb6fire_chip_disconnect(struct usb_interface *intf) + { + struct sfire_chip *chip; ++ struct snd_card *card; + + chip = usb_get_intfdata(intf); + if (chip) { /* if !chip, fw upload has been performed */ +@@ -178,8 +174,19 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf) + chips[chip->regidx] = NULL; + } + ++ /* ++ * Save card pointer before teardown. ++ * snd_card_free_when_closed() may free card (and ++ * the embedded chip) immediately, so it must be ++ * called last and chip must not be accessed after. ++ */ ++ card = chip->card; + chip->shutdown = true; ++ if (card) ++ snd_card_disconnect(card); + usb6fire_chip_abort(chip); ++ if (card) ++ snd_card_free_when_closed(card); + } + } + } +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1275-dlm-validate-length-in-dlm-search-rsb-tree.patch b/SOURCES/1275-dlm-validate-length-in-dlm-search-rsb-tree.patch new file mode 100644 index 000000000..b760e3ad8 --- /dev/null +++ b/SOURCES/1275-dlm-validate-length-in-dlm-search-rsb-tree.patch @@ -0,0 +1,47 @@ +From 8b7b77b30a2a8619e3db6aca77b74e527570c458 Mon Sep 17 00:00:00 2001 +From: Alexander Aring +Date: Fri, 8 May 2026 17:19:36 -0400 +Subject: [PATCH] dlm: validate length in dlm_search_rsb_tree + +JIRA: https://issues.redhat.com/browse/RHEL-173996 +CVE: CVE-2026-43125 + +Upstream Status: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + +Conflicts: upstream switched to rhashtables so lookup looks different + +commit 080e5563f878c64e697b89e7439d730d0daad882 +Author: Ezrak1e +Date: Tue Jan 20 10:35:06 2026 -0500 + + dlm: validate length in dlm_search_rsb_tree + + The len parameter in dlm_dump_rsb_name() is not validated and comes + from network messages. When it exceeds DLM_RESNAME_MAXLEN, it can + cause out-of-bounds write in dlm_search_rsb_tree(). + + Add length validation to prevent potential buffer overflow. + + Signed-off-by: Ezrak1e + Signed-off-by: Alexander Aring + Signed-off-by: David Teigland + +Signed-off-by: Alexander Aring + +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index b8059e4c65b7..7fd7ffeb6246 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -449,6 +449,9 @@ int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len, + struct dlm_rsb *r; + int rc; + ++ if (len > DLM_RESNAME_MAXLEN) ++ return -EINVAL; ++ + while (node) { + r = rb_entry(node, struct dlm_rsb, res_hashnode); + rc = rsb_cmp(r, name, len); +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1276-dlm-fix-buffer-overflow-from-negative-len-in-dlm-search-rsb-.patch b/SOURCES/1276-dlm-fix-buffer-overflow-from-negative-len-in-dlm-search-rsb-.patch new file mode 100644 index 000000000..7ac4a2617 --- /dev/null +++ b/SOURCES/1276-dlm-fix-buffer-overflow-from-negative-len-in-dlm-search-rsb-.patch @@ -0,0 +1,69 @@ +From 46fd7c54bd6c4508d25540bdbd1c2f10ba50962a Mon Sep 17 00:00:00 2001 +From: Alexander Aring +Date: Fri, 29 May 2026 10:59:20 -0400 +Subject: [PATCH] dlm: fix buffer overflow from negative len in + dlm_search_rsb_tree + +JIRA: https://issues.redhat.com/browse/RHEL-173996 +CVE: CVE-2026-43125 + +Upstream Status: RHEL only + +Conflicts: This patch is upstream not part "yet" to fix the CVE, but the +initial fix was not enough to fix the CVE-2026-43125 vulnerability. +There are still upstream discussion about how to handle this, thats why +it is RHEL specific. + +commit 823532f62cb6db31b3b0b56de000df5034874d81 +Author: Joseph Qi +Date: Sun May 17 10:03:15 2026 +0800 + + dlm: fix buffer overflow from negative len in dlm_search_rsb_tree + + commit 080e5563f878 only checks for len > DLM_RESNAME_MAXLEN, which does + not catch negative values. While the input 'len' can be negative and a + negative int passed to memcpy() is implicitly converted to a large + size_t, causing a stack buffer overflow on the key[] array. + + Fix this by changing the 'len' parameter type from int to unsigned int. + This ensures negative values from callers are implicitly converted to + large unsigned values that are caught by the existing + len > DLM_RESNAME_MAXLEN check. + + Signed-off-by: Joseph Qi + +Signed-off-by: Alexander Aring + +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 7fd7ffeb6246..dcfa539bd034 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -442,8 +442,8 @@ static int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen) + return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN); + } + +-int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len, +- struct dlm_rsb **r_ret) ++int dlm_search_rsb_tree(struct rb_root *tree, char *name, ++ unsigned int len, struct dlm_rsb **r_ret) + { + struct rb_node *node = tree->rb_node; + struct dlm_rsb *r; +diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h +index 456c6ec3ef6f..8cf81b512f0a 100644 +--- a/fs/dlm/lock.h ++++ b/fs/dlm/lock.h +@@ -30,8 +30,8 @@ void dlm_adjust_timeouts(struct dlm_ls *ls); + int dlm_master_lookup(struct dlm_ls *ls, int nodeid, char *name, int len, + unsigned int flags, int *r_nodeid, int *result); + +-int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len, +- struct dlm_rsb **r_ret); ++int dlm_search_rsb_tree(struct rb_root *tree, char *name, ++ unsigned int len, struct dlm_rsb **r_ret); + + void dlm_recover_purge(struct dlm_ls *ls); + void dlm_purge_mstcpy_locks(struct dlm_rsb *r); +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1277-netfilter-ctnetlink-ensure-safe-access-to-master-conntrack.patch b/SOURCES/1277-netfilter-ctnetlink-ensure-safe-access-to-master-conntrack.patch new file mode 100644 index 000000000..c4cebb02b --- /dev/null +++ b/SOURCES/1277-netfilter-ctnetlink-ensure-safe-access-to-master-conntrack.patch @@ -0,0 +1,222 @@ +From 3cd0619e1302cfbaea374ea05b27aaab19b7b7b0 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Wed, 6 May 2026 18:52:26 +0200 +Subject: [PATCH] netfilter: ctnetlink: ensure safe access to master conntrack + +JIRA: https://issues.redhat.com/browse/RHEL-173885 + +CVE: CVE-2026-43116 + +Conflict: We lack upstream del_timer/timer_delete rename. + +commit bffcaad9afdfe45d7fc777397d3b83c1e3ebffe5 +Author: Pablo Neira Ayuso +Date: Wed Mar 25 14:11:04 2026 +0100 + + netfilter: ctnetlink: ensure safe access to master conntrack + + Holding reference on the expectation is not sufficient, the master + conntrack object can just go away, making exp->master invalid. + + To access exp->master safely: + + - Grab the nf_conntrack_expect_lock, this gets serialized with + clean_from_lists() which also holds this lock when the master + conntrack goes away. + + - Hold reference on master conntrack via nf_conntrack_find_get(). + Not so easy since the master tuple to look up for the master conntrack + is not available in the existing problematic paths. + + This patch goes for extending the nf_conntrack_expect_lock section + to address this issue for simplicity, in the cases that are described + below this is just slightly extending the lock section. + + The add expectation command already holds a reference to the master + conntrack from ctnetlink_create_expect(). + + However, the delete expectation command needs to grab the spinlock + before looking up for the expectation. Expand the existing spinlock + section to address this to cover the expectation lookup. Note that, + the nf_ct_expect_iterate_net() calls already grabs the spinlock while + iterating over the expectation table, which is correct. + + The get expectation command needs to grab the spinlock to ensure master + conntrack does not go away. This also expands the existing spinlock + section to cover the expectation lookup too. I needed to move the + netlink skb allocation out of the spinlock to keep it GFP_KERNEL. + + For the expectation events, the IPEXP_DESTROY event is already delivered + under the spinlock, just move the delivery of IPEXP_NEW under the + spinlock too because the master conntrack event cache is reached through + exp->master. + + While at it, add lockdep notations to help identify what codepaths need + to grab the spinlock. + + Signed-off-by: Florian Westphal + Signed-off-by: Pablo Neira Ayuso + +Assisted-by: Patchpal +Signed-off-by: Florian Westphal + +diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h +index ff315e3ae75f..6ff83618e968 100644 +--- a/include/net/netfilter/nf_conntrack_core.h ++++ b/include/net/netfilter/nf_conntrack_core.h +@@ -84,6 +84,11 @@ void nf_conntrack_lock(spinlock_t *lock); + + extern spinlock_t nf_conntrack_expect_lock; + ++static inline void lockdep_nfct_expect_lock_held(void) ++{ ++ lockdep_assert_held(&nf_conntrack_expect_lock); ++} ++ + /* ctnetlink code shared by both ctnetlink and nf_conntrack_bpf */ + + #if (IS_BUILTIN(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) || \ +diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c +index 69948e1d6974..6526bdcca580 100644 +--- a/net/netfilter/nf_conntrack_ecache.c ++++ b/net/netfilter/nf_conntrack_ecache.c +@@ -237,6 +237,8 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, + struct nf_ct_event_notifier *notify; + struct nf_conntrack_ecache *e; + ++ lockdep_nfct_expect_lock_held(); ++ + rcu_read_lock(); + notify = rcu_dereference(net->ct.nf_conntrack_event_cb); + if (!notify) +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index ce1ac3187f1c..29bd82d1715d 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -51,6 +51,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, + struct net *net = nf_ct_exp_net(exp); + struct nf_conntrack_net *cnet; + ++ lockdep_nfct_expect_lock_held(); + WARN_ON(!master_help); + WARN_ON(timer_pending(&exp->timeout)); + +@@ -118,6 +119,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple, + + bool nf_ct_remove_expect(struct nf_conntrack_expect *exp) + { ++ lockdep_nfct_expect_lock_held(); ++ + if (del_timer(&exp->timeout)) { + nf_ct_unlink_expect(exp); + nf_ct_expect_put(exp); +@@ -177,6 +180,8 @@ nf_ct_find_expectation(struct net *net, + struct nf_conntrack_expect *i, *exp = NULL; + unsigned int h; + ++ lockdep_nfct_expect_lock_held(); ++ + if (!cnet->expect_count) + return NULL; + +@@ -442,6 +447,8 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, + unsigned int h; + int ret = 0; + ++ lockdep_nfct_expect_lock_held(); ++ + if (!master_help) { + ret = -ESHUTDOWN; + goto out; +@@ -498,8 +505,9 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, + + nf_ct_expect_insert(expect); + +- spin_unlock_bh(&nf_conntrack_expect_lock); + nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report); ++ spin_unlock_bh(&nf_conntrack_expect_lock); ++ + return 0; + out: + spin_unlock_bh(&nf_conntrack_expect_lock); +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index 91151e5df688..e19697d16d4c 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -3329,31 +3329,37 @@ static int ctnetlink_get_expect(struct sk_buff *skb, + if (err < 0) + return err; + ++ skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!skb2) ++ return -ENOMEM; ++ ++ spin_lock_bh(&nf_conntrack_expect_lock); + exp = nf_ct_expect_find_get(info->net, &zone, &tuple); +- if (!exp) ++ if (!exp) { ++ spin_unlock_bh(&nf_conntrack_expect_lock); ++ kfree_skb(skb2); + return -ENOENT; ++ } + + if (cda[CTA_EXPECT_ID]) { + __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]); + + if (id != nf_expect_get_id(exp)) { + nf_ct_expect_put(exp); ++ spin_unlock_bh(&nf_conntrack_expect_lock); ++ kfree_skb(skb2); + return -ENOENT; + } + } + +- skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +- if (!skb2) { +- nf_ct_expect_put(exp); +- return -ENOMEM; +- } +- + rcu_read_lock(); + err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid, + info->nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, + exp); + rcu_read_unlock(); + nf_ct_expect_put(exp); ++ spin_unlock_bh(&nf_conntrack_expect_lock); ++ + if (err <= 0) { + kfree_skb(skb2); + return -ENOMEM; +@@ -3403,22 +3409,26 @@ static int ctnetlink_del_expect(struct sk_buff *skb, + if (err < 0) + return err; + ++ spin_lock_bh(&nf_conntrack_expect_lock); ++ + /* bump usage count to 2 */ + exp = nf_ct_expect_find_get(info->net, &zone, &tuple); +- if (!exp) ++ if (!exp) { ++ spin_unlock_bh(&nf_conntrack_expect_lock); + return -ENOENT; ++ } + + if (cda[CTA_EXPECT_ID]) { + __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]); + + if (id != nf_expect_get_id(exp)) { + nf_ct_expect_put(exp); ++ spin_unlock_bh(&nf_conntrack_expect_lock); + return -ENOENT; + } + } + + /* after list removal, usage count == 1 */ +- spin_lock_bh(&nf_conntrack_expect_lock); + if (del_timer(&exp->timeout)) { + nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, + nlmsg_report(info->nlh)); +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1278-rdma-rxe-fix-double-free-in-rxe-srq-from-init.patch b/SOURCES/1278-rdma-rxe-fix-double-free-in-rxe-srq-from-init.patch new file mode 100644 index 000000000..d2c38e1e5 --- /dev/null +++ b/SOURCES/1278-rdma-rxe-fix-double-free-in-rxe-srq-from-init.patch @@ -0,0 +1,59 @@ +From 0beefd0e15d962f497aad750b2d5e9c3570b66d1 Mon Sep 17 00:00:00 2001 +From: Jiasheng Jiang +Date: Mon, 12 Jan 2026 01:54:12 +0000 +Subject: [PATCH] RDMA/rxe: Fix double free in rxe_srq_from_init + +In rxe_srq_from_init(), the queue pointer 'q' is assigned to +'srq->rq.queue' before copying the SRQ number to user space. +If copy_to_user() fails, the function calls rxe_queue_cleanup() +to free the queue, but leaves the now-invalid pointer in +'srq->rq.queue'. + +The caller of rxe_srq_from_init() (rxe_create_srq) eventually +calls rxe_srq_cleanup() upon receiving the error, which triggers +a second rxe_queue_cleanup() on the same memory, leading to a +double free. + +The call trace looks like this: + kmem_cache_free+0x.../0x... + rxe_queue_cleanup+0x1a/0x30 [rdma_rxe] + rxe_srq_cleanup+0x42/0x60 [rdma_rxe] + rxe_elem_release+0x31/0x70 [rdma_rxe] + rxe_create_srq+0x12b/0x1a0 [rdma_rxe] + ib_create_srq_user+0x9a/0x150 [ib_core] + +Fix this by moving 'srq->rq.queue = q' after copy_to_user. + +Fixes: aae0484e15f0 ("IB/rxe: avoid srq memory leak") +Signed-off-by: Jiasheng Jiang +Link: https://patch.msgid.link/20260112015412.29458-1-jiashengjiangcool@gmail.com +Reviewed-by: Zhu Yanjun +Signed-off-by: Leon Romanovsky + +diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c +index 2a234f26ac10..c9a7cd38953d 100644 +--- a/drivers/infiniband/sw/rxe/rxe_srq.c ++++ b/drivers/infiniband/sw/rxe/rxe_srq.c +@@ -77,9 +77,6 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + goto err_free; + } + +- srq->rq.queue = q; +- init->attr.max_wr = srq->rq.max_wr; +- + if (uresp) { + if (copy_to_user(&uresp->srq_num, &srq->srq_num, + sizeof(uresp->srq_num))) { +@@ -88,6 +85,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, + } + } + ++ srq->rq.queue = q; ++ init->attr.max_wr = srq->rq.max_wr; ++ + return 0; + + err_free: +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1279-net-openvswitch-avoid-releasing-netdev-before-teardown-compl.patch b/SOURCES/1279-net-openvswitch-avoid-releasing-netdev-before-teardown-compl.patch new file mode 100644 index 000000000..8845a85f7 --- /dev/null +++ b/SOURCES/1279-net-openvswitch-avoid-releasing-netdev-before-teardown-compl.patch @@ -0,0 +1,121 @@ +From 7c770dadfda5cbbde6aa3c4363ed513f1d212bf8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= +Date: Wed, 18 Mar 2026 16:55:51 +0100 +Subject: [PATCH] net: openvswitch: Avoid releasing netdev before teardown + completes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The patch cited in the Fixes tag below changed the teardown code for +OVS ports to no longer unconditionally take the RTNL. After this change, +the netdev_destroy() callback can proceed immediately to the call_rcu() +invocation if the IFF_OVS_DATAPATH flag is already cleared on the +netdev. + +The ovs_netdev_detach_dev() function clears the flag before completing +the unregistration, and if it gets preempted after clearing the flag (as +can happen on an -rt kernel), netdev_destroy() can complete and the +device can be freed before the unregistration completes. This leads to a +splat like: + +[ 998.393867] Oops: general protection fault, probably for non-canonical address 0xff00000001000239: 0000 [#1] SMP PTI +[ 998.393877] CPU: 42 UID: 0 PID: 55177 Comm: ip Kdump: loaded Not tainted 6.12.0-211.1.1.el10_2.x86_64+rt #1 PREEMPT_RT +[ 998.393886] Hardware name: Dell Inc. PowerEdge R740/0JMK61, BIOS 2.24.0 03/27/2025 +[ 998.393889] RIP: 0010:dev_set_promiscuity+0x8d/0xa0 +[ 998.393901] Code: 00 00 75 d8 48 8b 53 08 48 83 ba b0 02 00 00 00 75 ca 48 83 c4 08 5b c3 cc cc cc cc 48 83 bf 48 09 00 00 00 75 91 48 8b 47 08 <48> 83 b8 b0 02 00 00 00 74 97 eb 81 0f 1f 80 00 00 00 00 90 90 90 +[ 998.393906] RSP: 0018:ffffce5864a5f6a0 EFLAGS: 00010246 +[ 998.393912] RAX: ff00000000ffff89 RBX: ffff894d0adf5a05 RCX: 0000000000000000 +[ 998.393917] RDX: 0000000000000000 RSI: 00000000ffffffff RDI: ffff894d0adf5a05 +[ 998.393921] RBP: ffff894d19252000 R08: ffff894d19252000 R09: 0000000000000000 +[ 998.393924] R10: ffff894d19252000 R11: ffff894d192521b8 R12: 0000000000000006 +[ 998.393927] R13: ffffce5864a5f738 R14: 00000000ffffffe2 R15: 0000000000000000 +[ 998.393931] FS: 00007fad61971800(0000) GS:ffff894cc0140000(0000) knlGS:0000000000000000 +[ 998.393936] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 998.393940] CR2: 000055df0a2a6e40 CR3: 000000011c7fe003 CR4: 00000000007726f0 +[ 998.393944] PKRU: 55555554 +[ 998.393946] Call Trace: +[ 998.393949] +[ 998.393952] ? show_trace_log_lvl+0x1b0/0x2f0 +[ 998.393961] ? show_trace_log_lvl+0x1b0/0x2f0 +[ 998.393975] ? dp_device_event+0x41/0x80 [openvswitch] +[ 998.394009] ? __die_body.cold+0x8/0x12 +[ 998.394016] ? die_addr+0x3c/0x60 +[ 998.394027] ? exc_general_protection+0x16d/0x390 +[ 998.394042] ? asm_exc_general_protection+0x26/0x30 +[ 998.394058] ? dev_set_promiscuity+0x8d/0xa0 +[ 998.394066] ? ovs_netdev_detach_dev+0x3a/0x80 [openvswitch] +[ 998.394092] dp_device_event+0x41/0x80 [openvswitch] +[ 998.394102] notifier_call_chain+0x5a/0xd0 +[ 998.394106] unregister_netdevice_many_notify+0x51b/0xa60 +[ 998.394110] rtnl_dellink+0x169/0x3e0 +[ 998.394121] ? rt_mutex_slowlock.constprop.0+0x95/0xd0 +[ 998.394125] rtnetlink_rcv_msg+0x142/0x3f0 +[ 998.394128] ? avc_has_perm_noaudit+0x69/0xf0 +[ 998.394130] ? __pfx_rtnetlink_rcv_msg+0x10/0x10 +[ 998.394132] netlink_rcv_skb+0x50/0x100 +[ 998.394138] netlink_unicast+0x292/0x3f0 +[ 998.394141] netlink_sendmsg+0x21b/0x470 +[ 998.394145] ____sys_sendmsg+0x39d/0x3d0 +[ 998.394149] ___sys_sendmsg+0x9a/0xe0 +[ 998.394156] __sys_sendmsg+0x7a/0xd0 +[ 998.394160] do_syscall_64+0x7f/0x170 +[ 998.394162] entry_SYSCALL_64_after_hwframe+0x76/0x7e +[ 998.394165] RIP: 0033:0x7fad61bf4724 +[ 998.394188] Code: 89 02 b8 ff ff ff ff eb bb 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 f3 0f 1e fa 80 3d c5 e9 0c 00 00 74 13 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 c3 0f 1f 00 48 83 ec 28 89 54 24 1c 48 89 +[ 998.394189] RSP: 002b:00007ffd7e2f7cb8 EFLAGS: 00000202 ORIG_RAX: 000000000000002e +[ 998.394191] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007fad61bf4724 +[ 998.394193] RDX: 0000000000000000 RSI: 00007ffd7e2f7d20 RDI: 0000000000000003 +[ 998.394194] RBP: 00007ffd7e2f7d90 R08: 0000000000000010 R09: 000000000000003f +[ 998.394195] R10: 000055df11558010 R11: 0000000000000202 R12: 00007ffd7e2f8380 +[ 998.394196] R13: 0000000069b233d7 R14: 000055df0a256040 R15: 0000000000000000 +[ 998.394200] + +To fix this, reorder the operations in ovs_netdev_detach_dev() to only +clear the flag after completing the other operations, and introduce an +smp_wmb() to make the ordering requirement explicit. The smp_wmb() is +paired with a full smp_mb() in netdev_destroy() to make sure the +call_rcu() invocation does not happen before the unregister operations +are visible. + +Reported-by: Minxi Hou +Tested-by: Minxi Hou +Fixes: 549822767630 ("net: openvswitch: Avoid needlessly taking the RTNL on vport destroy") +Signed-off-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260318155554.1133405-1-toke@redhat.com +Signed-off-by: Jakub Kicinski + +diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c +index 6574f9bcdc02..c688dee96503 100644 +--- a/net/openvswitch/vport-netdev.c ++++ b/net/openvswitch/vport-netdev.c +@@ -151,11 +151,15 @@ static void vport_netdev_free(struct rcu_head *rcu) + void ovs_netdev_detach_dev(struct vport *vport) + { + ASSERT_RTNL(); +- vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; + netdev_rx_handler_unregister(vport->dev); + netdev_upper_dev_unlink(vport->dev, + netdev_master_upper_dev_get(vport->dev)); + dev_set_promiscuity(vport->dev, -1); ++ ++ /* paired with smp_mb() in netdev_destroy() */ ++ smp_wmb(); ++ ++ vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; + } + + static void netdev_destroy(struct vport *vport) +@@ -174,6 +178,9 @@ static void netdev_destroy(struct vport *vport) + rtnl_unlock(); + } + ++ /* paired with smp_wmb() in ovs_netdev_detach_dev() */ ++ smp_mb(); ++ + call_rcu(&vport->rcu, vport_netdev_free); + } + +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1280-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch b/SOURCES/1280-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch new file mode 100644 index 000000000..bdfd7e220 --- /dev/null +++ b/SOURCES/1280-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch @@ -0,0 +1,51 @@ +From 2edfa31769a4add828a7e604b21cb82aaaa05925 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 26 Mar 2026 15:51:38 +0000 +Subject: [PATCH] ip6_tunnel: clear skb2->cb[] in ip4ip6_err() + +Oskar Kjos reported the following problem. + +ip4ip6_err() calls icmp_send() on a cloned skb whose cb[] was written +by the IPv6 receive path as struct inet6_skb_parm. icmp_send() passes +IPCB(skb2) to __ip_options_echo(), which interprets that cb[] region +as struct inet_skb_parm (IPv4). The layouts differ: inet6_skb_parm.nhoff +at offset 14 overlaps inet_skb_parm.opt.rr, producing a non-zero rr +value. __ip_options_echo() then reads optlen from attacker-controlled +packet data at sptr[rr+1] and copies that many bytes into dopt->__data, +a fixed 40-byte stack buffer (IP_OPTIONS_DATA_FIXED_SIZE). + +To fix this we clear skb2->cb[], as suggested by Oskar Kjos. + +Also add minimal IPv4 header validation (version == 4, ihl >= 5). + +Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.") +Reported-by: Oskar Kjos +Signed-off-by: Eric Dumazet +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260326155138.2429480-1-edumazet@google.com +Signed-off-by: Jakub Kicinski + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 4c29aa94e86e..0b53488a9229 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -601,11 +601,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + if (!skb2) + return 0; + ++ /* Remove debris left by IPv6 stack. */ ++ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2))); ++ + skb_dst_drop(skb2); + + skb_pull(skb2, offset); + skb_reset_network_header(skb2); + eiph = ip_hdr(skb2); ++ if (eiph->version != 4 || eiph->ihl < 5) ++ goto out; + + /* Try to guess incoming interface */ + rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr, +-- +2.50.1 (Apple Git-155) + diff --git a/SOURCES/1281-ipv6-rpl-headroom.patch b/SOURCES/1281-ipv6-rpl-headroom.patch new file mode 100644 index 000000000..af6f758d0 --- /dev/null +++ b/SOURCES/1281-ipv6-rpl-headroom.patch @@ -0,0 +1,37 @@ +Subject: [PATCH] ipv6: rpl: reserve mac_len headroom when recompressed SRH grows (CVE-2026-43501) +# AlmaLinux: reconstructed (687.13.1->687.15.1); includes RHEL kABI / RHEL-only files + +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 400ca6a..4475aa3 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -479,6 +479,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + struct net *net = dev_net(skb->dev); + struct inet6_dev *idev; + struct ipv6hdr *oldhdr; ++ unsigned int chdr_len; + struct in6_addr addr; + unsigned char *buf; + int accept_rpl_seg; +@@ -601,8 +602,10 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + skb_pull(skb, ((hdr->hdrlen + 1) << 3)); + skb_postpull_rcsum(skb, oldhdr, + sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); +- if (unlikely(!hdr->segments_left)) { +- if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0, ++ chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3); ++ if (unlikely(!hdr->segments_left || ++ skb_headroom(skb) < chdr_len + skb->mac_len)) { ++ if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0, + GFP_ATOMIC)) { + __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); + kfree_skb(skb); +@@ -612,7 +615,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) + + oldhdr = ipv6_hdr(skb); + } +- skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr)); ++ skb_push(skb, chdr_len); + skb_reset_network_header(skb); + skb_mac_header_rebuild(skb); + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); diff --git a/SOURCES/1282-rdma-mlx4-srq.patch b/SOURCES/1282-rdma-mlx4-srq.patch new file mode 100644 index 000000000..ff1beea28 --- /dev/null +++ b/SOURCES/1282-rdma-mlx4-srq.patch @@ -0,0 +1,37 @@ +Subject: [PATCH] RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event() (CVE-2026-46181) +# AlmaLinux: reconstructed base->final + +diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c +index dd890f5..b21eae5 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/srq.c ++++ b/drivers/net/ethernet/mellanox/mlx4/srq.c +@@ -44,13 +44,14 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) + { + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + struct mlx4_srq *srq; ++ unsigned long flags; + +- rcu_read_lock(); ++ spin_lock_irqsave(&srq_table->lock, flags); + srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1)); +- rcu_read_unlock(); +- if (srq) +- refcount_inc(&srq->refcount); +- else { ++ if (!srq || !refcount_inc_not_zero(&srq->refcount)) ++ srq = NULL; ++ spin_unlock_irqrestore(&srq_table->lock, flags); ++ if (!srq) { + mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn); + return; + } +@@ -203,8 +204,8 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, + if (err) + goto err_radix; + +- refcount_set(&srq->refcount, 1); + init_completion(&srq->free); ++ atomic_set_release(&srq->refcount.refs, 1); + + return 0; + diff --git a/SOURCES/1283-dpll-series-RHEL.patch b/SOURCES/1283-dpll-series-RHEL.patch new file mode 100644 index 000000000..28872bf78 --- /dev/null +++ b/SOURCES/1283-dpll-series-RHEL.patch @@ -0,0 +1,3225 @@ +Subject: [PATCH] dpll/zl3073x series (RHEL-167273/167833/172938; RH_KABI + RHEL chan.c/.h) +# AlmaLinux: reconstructed (687.13.1->687.15.1); includes RHEL kABI / RHEL-only files + +diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst +index 83118c7..93c191b 100644 +--- a/Documentation/driver-api/dpll.rst ++++ b/Documentation/driver-api/dpll.rst +@@ -250,6 +250,24 @@ in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute. + ``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature + =============================== ======================== + ++Frequency monitor ++================= ++ ++Some DPLL devices may offer the capability to measure the actual ++frequency of all available input pins. The attribute and current feature state ++shall be included in the response message of the ``DPLL_CMD_DEVICE_GET`` ++command for supported DPLL devices. In such cases, users can also control ++the feature using the ``DPLL_CMD_DEVICE_SET`` command by setting the ++``enum dpll_feature_state`` values for the attribute. ++Once enabled the measured input frequency for each input pin shall be ++returned in the ``DPLL_A_PIN_MEASURED_FREQUENCY`` attribute. The value ++is in millihertz (mHz), using ``DPLL_PIN_MEASURED_FREQUENCY_DIVIDER`` ++as the divider. ++ ++ =============================== ======================== ++ ``DPLL_A_FREQUENCY_MONITOR`` attr state of a feature ++ =============================== ======================== ++ + Embedded SYNC + ============= + +@@ -411,6 +429,8 @@ according to attribute purpose. + ``DPLL_A_PIN_STATE`` attr state of pin on the parent + pin + ``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities ++ ``DPLL_A_PIN_MEASURED_FREQUENCY`` attr measured frequency of ++ an input pin in mHz + ==================================== ================================== + + ==================================== ================================= +diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml +index ed58662..cb5da35 100644 +--- a/Documentation/netlink/specs/dpll.yaml ++++ b/Documentation/netlink/specs/dpll.yaml +@@ -240,6 +240,20 @@ definitions: + integer part of a measured phase offset value. + Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a + fractional part of a measured phase offset value. ++ - ++ type: const ++ name: pin-measured-frequency-divider ++ value: 1000 ++ doc: | ++ pin measured frequency divider allows userspace to calculate ++ a value of measured input frequency as a fractional value with ++ three digit decimal precision (millihertz). ++ Value of (DPLL_A_PIN_MEASURED_FREQUENCY / ++ DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is an integer part of ++ a measured frequency value. ++ Value of (DPLL_A_PIN_MEASURED_FREQUENCY % ++ DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part of ++ a measured frequency value. + - + type: enum + name: feature-state +@@ -319,6 +333,13 @@ attribute-sets: + name: phase-offset-avg-factor + type: u32 + doc: Averaging factor applied to calculation of reported phase offset. ++ - ++ name: frequency-monitor ++ type: u32 ++ enum: feature-state ++ doc: Current or desired state of the frequency monitor feature. ++ If enabled, dpll device shall measure all currently available ++ inputs for their actual input frequency. + - + name: pin + enum-name: dpll_a_pin +@@ -456,6 +477,17 @@ attribute-sets: + Value is in PPT (parts per trillion, 10^-12). + Note: This attribute provides higher resolution than the standard + fractional-frequency-offset (which is in PPM). ++ - ++ name: measured-frequency ++ type: u64 ++ doc: | ++ The measured frequency of the input pin in millihertz (mHz). ++ Value of (DPLL_A_PIN_MEASURED_FREQUENCY / ++ DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is an integer part (Hz) ++ of a measured frequency value. ++ Value of (DPLL_A_PIN_MEASURED_FREQUENCY % ++ DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part ++ of a measured frequency value. + + - + name: pin-parent-device +@@ -544,6 +576,7 @@ operations: + - type + - phase-offset-monitor + - phase-offset-avg-factor ++ - frequency-monitor + + dump: + reply: *dev-attrs +@@ -563,6 +596,7 @@ operations: + - mode + - phase-offset-monitor + - phase-offset-avg-factor ++ - frequency-monitor + - + name: device-create-ntf + doc: Notification about device appearing +@@ -643,6 +677,7 @@ operations: + - esync-frequency-supported + - esync-pulse + - reference-sync ++ - measured-frequency + + dump: + request: +diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c +index 842f733..84e1b63 100644 +--- a/drivers/dpll/dpll_core.c ++++ b/drivers/dpll/dpll_core.c +@@ -880,7 +880,10 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, + + if (WARN_ON(!ops) || + WARN_ON(!ops->state_on_dpll_get) || +- WARN_ON(!ops->direction_get)) ++ WARN_ON(!ops->direction_get) || ++ WARN_ON(ops->measured_freq_get && ++ (!dpll_device_ops(dpll)->freq_monitor_get || ++ !dpll_device_ops(dpll)->freq_monitor_set))) + return -EINVAL; + + mutex_lock(&dpll_lock); +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index 95ae786..0ff1658 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -175,6 +175,26 @@ dpll_msg_add_phase_offset_monitor(struct sk_buff *msg, struct dpll_device *dpll, + return 0; + } + ++static int ++dpll_msg_add_freq_monitor(struct sk_buff *msg, struct dpll_device *dpll, ++ struct netlink_ext_ack *extack) ++{ ++ const struct dpll_device_ops *ops = dpll_device_ops(dpll); ++ enum dpll_feature_state state; ++ int ret; ++ ++ if (ops->freq_monitor_set && ops->freq_monitor_get) { ++ ret = ops->freq_monitor_get(dpll, dpll_priv(dpll), ++ &state, extack); ++ if (ret) ++ return ret; ++ if (nla_put_u32(msg, DPLL_A_FREQUENCY_MONITOR, state)) ++ return -EMSGSIZE; ++ } ++ ++ return 0; ++} ++ + static int + dpll_msg_add_phase_offset_avg_factor(struct sk_buff *msg, + struct dpll_device *dpll, +@@ -400,6 +420,38 @@ static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin, + ffo); + } + ++static int dpll_msg_add_measured_freq(struct sk_buff *msg, struct dpll_pin *pin, ++ struct dpll_pin_ref *ref, ++ struct netlink_ext_ack *extack) ++{ ++ const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll); ++ const struct dpll_pin_ops *ops = dpll_pin_ops(ref); ++ struct dpll_device *dpll = ref->dpll; ++ enum dpll_feature_state state; ++ u64 measured_freq; ++ int ret; ++ ++ if (!ops->measured_freq_get) ++ return 0; ++ ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll), ++ &state, extack); ++ if (ret) ++ return ret; ++ if (state == DPLL_FEATURE_STATE_DISABLE) ++ return 0; ++ ret = ops->measured_freq_get(pin, dpll_pin_on_dpll_priv(dpll, pin), ++ dpll, dpll_priv(dpll), &measured_freq, ++ extack); ++ if (ret) ++ return ret; ++ if (nla_put_64bit(msg, DPLL_A_PIN_MEASURED_FREQUENCY, ++ sizeof(measured_freq), &measured_freq, ++ DPLL_A_PIN_PAD)) ++ return -EMSGSIZE; ++ ++ return 0; ++} ++ + static int + dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, + struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) +@@ -670,6 +722,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, + if (ret) + return ret; + ret = dpll_msg_add_ffo(msg, pin, ref, extack); ++ if (ret) ++ return ret; ++ ret = dpll_msg_add_measured_freq(msg, pin, ref, extack); + if (ret) + return ret; + ret = dpll_msg_add_pin_esync(msg, pin, ref, extack); +@@ -722,6 +777,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, + if (ret) + return ret; + ret = dpll_msg_add_phase_offset_avg_factor(msg, dpll, extack); ++ if (ret) ++ return ret; ++ ret = dpll_msg_add_freq_monitor(msg, dpll, extack); + if (ret) + return ret; + +@@ -958,6 +1016,32 @@ dpll_phase_offset_avg_factor_set(struct dpll_device *dpll, struct nlattr *a, + extack); + } + ++static int ++dpll_freq_monitor_set(struct dpll_device *dpll, struct nlattr *a, ++ struct netlink_ext_ack *extack) ++{ ++ const struct dpll_device_ops *ops = dpll_device_ops(dpll); ++ enum dpll_feature_state state = nla_get_u32(a), old_state; ++ int ret; ++ ++ if (!(ops->freq_monitor_set && ops->freq_monitor_get)) { ++ NL_SET_ERR_MSG_ATTR(extack, a, ++ "dpll device not capable of frequency monitor"); ++ return -EOPNOTSUPP; ++ } ++ ret = ops->freq_monitor_get(dpll, dpll_priv(dpll), &old_state, ++ extack); ++ if (ret) { ++ NL_SET_ERR_MSG(extack, ++ "unable to get current state of frequency monitor"); ++ return ret; ++ } ++ if (state == old_state) ++ return 0; ++ ++ return ops->freq_monitor_set(dpll, dpll_priv(dpll), state, extack); ++} ++ + static int + dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a, + struct netlink_ext_ack *extack) +@@ -1888,6 +1972,12 @@ dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info) + if (ret) + return ret; + break; ++ case DPLL_A_FREQUENCY_MONITOR: ++ ret = dpll_freq_monitor_set(dpll, a, ++ info->extack); ++ if (ret) ++ return ret; ++ break; + } + } + +diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c +index 3fb64aa..da92aa8 100644 +--- a/drivers/dpll/dpll_nl.c ++++ b/drivers/dpll/dpll_nl.c +@@ -42,11 +42,12 @@ static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = { + }; + + /* DPLL_CMD_DEVICE_SET - do */ +-static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_PHASE_OFFSET_AVG_FACTOR + 1] = { ++static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_FREQUENCY_MONITOR + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_MODE] = NLA_POLICY_RANGE(NLA_U32, 1, 2), + [DPLL_A_PHASE_OFFSET_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1), + [DPLL_A_PHASE_OFFSET_AVG_FACTOR] = { .type = NLA_U32, }, ++ [DPLL_A_FREQUENCY_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1), + }; + + /* DPLL_CMD_PIN_ID_GET - do */ +@@ -114,7 +115,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { + .doit = dpll_nl_device_set_doit, + .post_doit = dpll_post_doit, + .policy = dpll_device_set_nl_policy, +- .maxattr = DPLL_A_PHASE_OFFSET_AVG_FACTOR, ++ .maxattr = DPLL_A_FREQUENCY_MONITOR, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { +diff --git a/drivers/dpll/zl3073x/Makefile b/drivers/dpll/zl3073x/Makefile +index bd324c7..906ec3f 100644 +--- a/drivers/dpll/zl3073x/Makefile ++++ b/drivers/dpll/zl3073x/Makefile +@@ -1,8 +1,8 @@ + # SPDX-License-Identifier: GPL-2.0 + + obj-$(CONFIG_ZL3073X) += zl3073x.o +-zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o \ +- out.o prop.o ref.o synth.o ++zl3073x-objs := chan.o core.o devlink.o dpll.o \ ++ flash.o fw.o out.o prop.o ref.o synth.o + + obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o + zl3073x_i2c-objs := i2c.o +diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c +new file mode 100644 +index 0000000..2f48ca2 +--- /dev/null ++++ b/drivers/dpll/zl3073x/chan.c +@@ -0,0 +1,165 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++ ++#include "chan.h" ++#include "core.h" ++ ++/** ++ * zl3073x_chan_state_update - update DPLL channel status from HW ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: DPLL channel index ++ * ++ * Return: 0 on success, <0 on error ++ */ ++int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index) ++{ ++ struct zl3073x_chan *chan = &zldev->chan[index]; ++ int rc; ++ ++ rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index), ++ &chan->mon_status); ++ if (rc) ++ return rc; ++ ++ return zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index), ++ &chan->refsel_status); ++} ++ ++/** ++ * zl3073x_chan_state_fetch - fetch DPLL channel state from hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: DPLL channel index to fetch state for ++ * ++ * Reads the mode_refsel register and reference priority registers for ++ * the given DPLL channel and stores the raw values for later use. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index) ++{ ++ struct zl3073x_chan *chan = &zldev->chan[index]; ++ int rc, i; ++ ++ rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), ++ &chan->mode_refsel); ++ if (rc) ++ return rc; ++ ++ dev_dbg(zldev->dev, "DPLL%u mode: %u, ref: %u\n", index, ++ zl3073x_chan_mode_get(chan), zl3073x_chan_ref_get(chan)); ++ ++ rc = zl3073x_chan_state_update(zldev, index); ++ if (rc) ++ return rc; ++ ++ dev_dbg(zldev->dev, ++ "DPLL%u lock_state: %u, ho: %u, sel_state: %u, sel_ref: %u\n", ++ index, zl3073x_chan_lock_state_get(chan), ++ zl3073x_chan_is_ho_ready(chan) ? 1 : 0, ++ zl3073x_chan_refsel_state_get(chan), ++ zl3073x_chan_refsel_ref_get(chan)); ++ ++ guard(mutex)(&zldev->multiop_lock); ++ ++ /* Read DPLL configuration from mailbox */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, ++ ZL_REG_DPLL_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* Read reference priority registers */ ++ for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) { ++ rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(i), ++ &chan->ref_prio[i]); ++ if (rc) ++ return rc; ++ } ++ ++ return 0; ++} ++ ++/** ++ * zl3073x_chan_state_get - get current DPLL channel state ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: DPLL channel index to get state for ++ * ++ * Return: pointer to given DPLL channel state ++ */ ++const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev, ++ u8 index) ++{ ++ return &zldev->chan[index]; ++} ++ ++/** ++ * zl3073x_chan_state_set - commit DPLL channel state changes to hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: DPLL channel index to set state for ++ * @chan: desired channel state ++ * ++ * Skips the HW write if the configuration is unchanged, and otherwise ++ * writes only the changed registers to hardware. The mode_refsel register ++ * is written directly, while the reference priority registers are written ++ * via the DPLL mailbox interface. ++ * ++ * Return: 0 on success, <0 on HW error ++ */ ++int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, ++ const struct zl3073x_chan *chan) ++{ ++ struct zl3073x_chan *dchan = &zldev->chan[index]; ++ int rc, i; ++ ++ /* Skip HW write if configuration hasn't changed */ ++ if (!memcmp(&dchan->cfg, &chan->cfg, sizeof(chan->cfg))) ++ return 0; ++ ++ /* Direct register write for mode_refsel */ ++ if (dchan->mode_refsel != chan->mode_refsel) { ++ rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), ++ chan->mode_refsel); ++ if (rc) ++ return rc; ++ dchan->mode_refsel = chan->mode_refsel; ++ } ++ ++ /* Mailbox write for ref_prio if changed */ ++ if (!memcmp(dchan->ref_prio, chan->ref_prio, sizeof(chan->ref_prio))) { ++ dchan->cfg = chan->cfg; ++ return 0; ++ } ++ ++ guard(mutex)(&zldev->multiop_lock); ++ ++ /* Read DPLL configuration into mailbox */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, ++ ZL_REG_DPLL_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* Update changed ref_prio registers */ ++ for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) { ++ if (dchan->ref_prio[i] != chan->ref_prio[i]) { ++ rc = zl3073x_write_u8(zldev, ++ ZL_REG_DPLL_REF_PRIO(i), ++ chan->ref_prio[i]); ++ if (rc) ++ return rc; ++ } ++ } ++ ++ /* Commit DPLL configuration */ ++ rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR, ++ ZL_REG_DPLL_MB_MASK, BIT(index)); ++ if (rc) ++ return rc; ++ ++ /* After successful write store new state */ ++ dchan->cfg = chan->cfg; ++ ++ return 0; ++} +diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h +new file mode 100644 +index 0000000..481da21 +--- /dev/null ++++ b/drivers/dpll/zl3073x/chan.h +@@ -0,0 +1,174 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef _ZL3073X_CHAN_H ++#define _ZL3073X_CHAN_H ++ ++#include ++#include ++#include ++ ++#include "regs.h" ++ ++struct zl3073x_dev; ++ ++/** ++ * struct zl3073x_chan - DPLL channel state ++ * @mode_refsel: mode and reference selection register value ++ * @ref_prio: reference priority registers (4 bits per ref, P/N packed) ++ * @mon_status: monitor status register value ++ * @refsel_status: reference selection status register value ++ */ ++struct zl3073x_chan { ++ struct_group(cfg, ++ u8 mode_refsel; ++ u8 ref_prio[ZL3073X_NUM_REFS / 2]; ++ ); ++ struct_group(stat, ++ u8 mon_status; ++ u8 refsel_status; ++ ); ++}; ++ ++int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index); ++const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev, ++ u8 index); ++int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, ++ const struct zl3073x_chan *chan); ++ ++int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index); ++ ++/** ++ * zl3073x_chan_mode_get - get DPLL channel operating mode ++ * @chan: pointer to channel state ++ * ++ * Return: reference selection mode of the given DPLL channel ++ */ ++static inline u8 zl3073x_chan_mode_get(const struct zl3073x_chan *chan) ++{ ++ return FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, chan->mode_refsel); ++} ++ ++/** ++ * zl3073x_chan_ref_get - get manually selected reference ++ * @chan: pointer to channel state ++ * ++ * Return: reference selected in forced reference lock mode ++ */ ++static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan) ++{ ++ return FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, chan->mode_refsel); ++} ++ ++/** ++ * zl3073x_chan_mode_set - set DPLL channel operating mode ++ * @chan: pointer to channel state ++ * @mode: mode to set ++ */ ++static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode) ++{ ++ FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &chan->mode_refsel, mode); ++} ++ ++/** ++ * zl3073x_chan_ref_set - set manually selected reference ++ * @chan: pointer to channel state ++ * @ref: reference to set ++ */ ++static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref) ++{ ++ FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_REF, &chan->mode_refsel, ref); ++} ++ ++/** ++ * zl3073x_chan_ref_prio_get - get reference priority ++ * @chan: pointer to channel state ++ * @ref: input reference index ++ * ++ * Return: priority of the given reference <0, 15> ++ */ ++static inline u8 ++zl3073x_chan_ref_prio_get(const struct zl3073x_chan *chan, u8 ref) ++{ ++ u8 val = chan->ref_prio[ref / 2]; ++ ++ if (!(ref & 1)) ++ return FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, val); ++ else ++ return FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, val); ++} ++ ++/** ++ * zl3073x_chan_ref_prio_set - set reference priority ++ * @chan: pointer to channel state ++ * @ref: input reference index ++ * @prio: priority to set ++ */ ++static inline void ++zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio) ++{ ++ u8 *val = &chan->ref_prio[ref / 2]; ++ ++ if (!(ref & 1)) ++ FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_P, val, prio); ++ else ++ FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_N, val, prio); ++} ++ ++/** ++ * zl3073x_chan_ref_is_selectable - check if reference is selectable ++ * @chan: pointer to channel state ++ * @ref: input reference index ++ * ++ * Return: true if the reference priority is not NONE, false otherwise ++ */ ++static inline bool ++zl3073x_chan_ref_is_selectable(const struct zl3073x_chan *chan, u8 ref) ++{ ++ return zl3073x_chan_ref_prio_get(chan, ref) != ZL_DPLL_REF_PRIO_NONE; ++} ++ ++/** ++ * zl3073x_chan_lock_state_get - get DPLL channel lock state ++ * @chan: pointer to channel state ++ * ++ * Return: lock state of the given DPLL channel ++ */ ++static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan) ++{ ++ return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status); ++} ++ ++/** ++ * zl3073x_chan_is_ho_ready - check if holdover is ready ++ * @chan: pointer to channel state ++ * ++ * Return: true if holdover is ready, false otherwise ++ */ ++static inline bool zl3073x_chan_is_ho_ready(const struct zl3073x_chan *chan) ++{ ++ return !!FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, chan->mon_status); ++} ++ ++/** ++ * zl3073x_chan_refsel_state_get - get reference selection state ++ * @chan: pointer to channel state ++ * ++ * Return: reference selection state of the given DPLL channel ++ */ ++static inline u8 zl3073x_chan_refsel_state_get(const struct zl3073x_chan *chan) ++{ ++ return FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, chan->refsel_status); ++} ++ ++/** ++ * zl3073x_chan_refsel_ref_get - get currently selected reference in auto mode ++ * @chan: pointer to channel state ++ * ++ * Return: reference selected by the DPLL in automatic mode ++ */ ++static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan) ++{ ++ return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status); ++} ++ ++#endif /* _ZL3073X_CHAN_H */ +diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c +index 179fff5..024f0a2 100644 +--- a/drivers/dpll/zl3073x/core.c ++++ b/drivers/dpll/zl3073x/core.c +@@ -20,79 +20,30 @@ + #include "dpll.h" + #include "regs.h" + +-/* Chip IDs for zl30731 */ +-static const u16 zl30731_ids[] = { +- 0x0E93, +- 0x1E93, +- 0x2E93, ++#define ZL_CHIP_INFO(_id, _nchannels, _flags) \ ++ { .id = (_id), .num_channels = (_nchannels), .flags = (_flags) } ++ ++static const struct zl3073x_chip_info zl3073x_chip_ids[] = { ++ ZL_CHIP_INFO(0x0E30, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E93, 1, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E94, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E96, 4, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x0E97, 5, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x1E93, 1, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E94, 2, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E95, 3, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E96, 4, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1E97, 5, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x1F60, 2, ZL3073X_FLAG_REF_PHASE_COMP_32), ++ ZL_CHIP_INFO(0x2E93, 1, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E94, 2, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E95, 3, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E96, 4, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x2E97, 5, ZL3073X_FLAG_DIE_TEMP), ++ ZL_CHIP_INFO(0x3FC4, 2, ZL3073X_FLAG_DIE_TEMP), + }; + +-const struct zl3073x_chip_info zl30731_chip_info = { +- .ids = zl30731_ids, +- .num_ids = ARRAY_SIZE(zl30731_ids), +- .num_channels = 1, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30731_chip_info, ZL3073X); +- +-/* Chip IDs for zl30732 */ +-static const u16 zl30732_ids[] = { +- 0x0E30, +- 0x0E94, +- 0x1E94, +- 0x1F60, +- 0x2E94, +- 0x3FC4, +-}; +- +-const struct zl3073x_chip_info zl30732_chip_info = { +- .ids = zl30732_ids, +- .num_ids = ARRAY_SIZE(zl30732_ids), +- .num_channels = 2, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30732_chip_info, ZL3073X); +- +-/* Chip IDs for zl30733 */ +-static const u16 zl30733_ids[] = { +- 0x0E95, +- 0x1E95, +- 0x2E95, +-}; +- +-const struct zl3073x_chip_info zl30733_chip_info = { +- .ids = zl30733_ids, +- .num_ids = ARRAY_SIZE(zl30733_ids), +- .num_channels = 3, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30733_chip_info, ZL3073X); +- +-/* Chip IDs for zl30734 */ +-static const u16 zl30734_ids[] = { +- 0x0E96, +- 0x1E96, +- 0x2E96, +-}; +- +-const struct zl3073x_chip_info zl30734_chip_info = { +- .ids = zl30734_ids, +- .num_ids = ARRAY_SIZE(zl30734_ids), +- .num_channels = 4, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30734_chip_info, ZL3073X); +- +-/* Chip IDs for zl30735 */ +-static const u16 zl30735_ids[] = { +- 0x0E97, +- 0x1E97, +- 0x2E97, +-}; +- +-const struct zl3073x_chip_info zl30735_chip_info = { +- .ids = zl30735_ids, +- .num_ids = ARRAY_SIZE(zl30735_ids), +- .num_channels = 5, +-}; +-EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, ZL3073X); +- + #define ZL_RANGE_OFFSET 0x80 + #define ZL_PAGE_SIZE 0x80 + #define ZL_NUM_PAGES 256 +@@ -588,17 +539,26 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev) + } + } + ++ for (i = 0; i < zldev->info->num_channels; i++) { ++ rc = zl3073x_chan_state_fetch(zldev, i); ++ if (rc) { ++ dev_err(zldev->dev, ++ "Failed to fetch channel state: %pe\n", ++ ERR_PTR(rc)); ++ return rc; ++ } ++ } ++ + return rc; + } + + static void +-zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev) ++zl3073x_dev_ref_states_update(struct zl3073x_dev *zldev) + { + int i, rc; + + for (i = 0; i < ZL3073X_NUM_REFS; i++) { +- rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(i), +- &zldev->ref[i].mon_status); ++ rc = zl3073x_ref_state_update(zldev, i); + if (rc) + dev_warn(zldev->dev, + "Failed to get REF%u status: %pe\n", i, +@@ -606,6 +566,20 @@ zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev) + } + } + ++static void ++zl3073x_dev_chan_states_update(struct zl3073x_dev *zldev) ++{ ++ int i, rc; ++ ++ for (i = 0; i < zldev->info->num_channels; i++) { ++ rc = zl3073x_chan_state_update(zldev, i); ++ if (rc) ++ dev_warn(zldev->dev, ++ "Failed to get DPLL%u state: %pe\n", i, ++ ERR_PTR(rc)); ++ } ++} ++ + /** + * zl3073x_ref_phase_offsets_update - update reference phase offsets + * @zldev: pointer to zl3073x_dev structure +@@ -658,22 +632,21 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel) + } + + /** +- * zl3073x_ref_ffo_update - update reference fractional frequency offsets ++ * zl3073x_ref_freq_meas_latch - latch reference frequency measurements + * @zldev: pointer to zl3073x_dev structure ++ * @type: measurement type (ZL_REF_FREQ_MEAS_CTRL_*) + * +- * The function asks device to update fractional frequency offsets latch +- * registers the latest measured values, reads and stores them into ++ * The function waits for the previous measurement to finish, selects all ++ * references and requests a new measurement of the given type. + * + * Return: 0 on success, <0 on error + */ + static int +-zl3073x_ref_ffo_update(struct zl3073x_dev *zldev) ++zl3073x_ref_freq_meas_latch(struct zl3073x_dev *zldev, u8 type) + { +- int i, rc; ++ int rc; + +- /* Per datasheet we have to wait for 'ref_freq_meas_ctrl' to be zero +- * to ensure that the measured data are coherent. +- */ ++ /* Wait for previous measurement to finish */ + rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, + ZL_REF_FREQ_MEAS_CTRL); + if (rc) +@@ -689,15 +662,64 @@ zl3073x_ref_ffo_update(struct zl3073x_dev *zldev) + if (rc) + return rc; + +- /* Request frequency offset measurement */ +- rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, +- ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF); ++ /* Request measurement */ ++ rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, type); + if (rc) + return rc; + + /* Wait for finish */ +- rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, +- ZL_REF_FREQ_MEAS_CTRL); ++ return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, ++ ZL_REF_FREQ_MEAS_CTRL); ++} ++ ++/** ++ * zl3073x_ref_freq_meas_update - update measured input reference frequencies ++ * @zldev: pointer to zl3073x_dev structure ++ * ++ * The function asks device to latch measured input reference frequencies ++ * and stores the results in the ref state. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++static int ++zl3073x_ref_freq_meas_update(struct zl3073x_dev *zldev) ++{ ++ int i, rc; ++ ++ rc = zl3073x_ref_freq_meas_latch(zldev, ZL_REF_FREQ_MEAS_CTRL_REF_FREQ); ++ if (rc) ++ return rc; ++ ++ /* Read measured frequencies in Hz (unsigned 32-bit, LSB = 1 Hz) */ ++ for (i = 0; i < ZL3073X_NUM_REFS; i++) { ++ u32 value; ++ ++ rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value); ++ if (rc) ++ return rc; ++ ++ zldev->ref[i].meas_freq = value; ++ } ++ ++ return 0; ++} ++ ++/** ++ * zl3073x_ref_ffo_update - update reference fractional frequency offsets ++ * @zldev: pointer to zl3073x_dev structure ++ * ++ * The function asks device to latch the latest measured fractional ++ * frequency offset values, reads and stores them into the ref state. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++static int ++zl3073x_ref_ffo_update(struct zl3073x_dev *zldev) ++{ ++ int i, rc; ++ ++ rc = zl3073x_ref_freq_meas_latch(zldev, ++ ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF); + if (rc) + return rc; + +@@ -728,8 +750,11 @@ zl3073x_dev_periodic_work(struct kthread_work *work) + struct zl3073x_dpll *zldpll; + int rc; + +- /* Update input references status */ +- zl3073x_dev_ref_status_update(zldev); ++ /* Update input references' states */ ++ zl3073x_dev_ref_states_update(zldev); ++ ++ /* Update DPLL channels' states */ ++ zl3073x_dev_chan_states_update(zldev); + + /* Update DPLL-to-connected-ref phase offsets registers */ + rc = zl3073x_ref_phase_offsets_update(zldev, -1); +@@ -737,6 +762,20 @@ zl3073x_dev_periodic_work(struct kthread_work *work) + dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n", + ERR_PTR(rc)); + ++ /* Update measured input reference frequencies if any DPLL has ++ * frequency monitoring enabled. ++ */ ++ list_for_each_entry(zldpll, &zldev->dplls, list) { ++ if (zldpll->freq_monitor) { ++ rc = zl3073x_ref_freq_meas_update(zldev); ++ if (rc) ++ dev_warn(zldev->dev, ++ "Failed to update measured frequencies: %pe\n", ++ ERR_PTR(rc)); ++ break; ++ } ++ } ++ + /* Update references' fractional frequency offsets */ + rc = zl3073x_ref_ffo_update(zldev); + if (rc) +@@ -766,8 +805,7 @@ int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor) + value = (factor + 1) & 0x0f; + + /* Update phase measurement control register */ +- dpll_meas_ctrl &= ~ZL_DPLL_MEAS_CTRL_AVG_FACTOR; +- dpll_meas_ctrl |= FIELD_PREP(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, value); ++ FIELD_MODIFY(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, &dpll_meas_ctrl, value); + rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, dpll_meas_ctrl); + if (rc) + return rc; +@@ -942,7 +980,7 @@ static void zl3073x_dev_dpll_fini(void *ptr) + } + + static int +-zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) ++zl3073x_devm_dpll_init(struct zl3073x_dev *zldev) + { + struct kthread_worker *kworker; + struct zl3073x_dpll *zldpll; +@@ -952,7 +990,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) + INIT_LIST_HEAD(&zldev->dplls); + + /* Allocate all DPLLs */ +- for (i = 0; i < num_dplls; i++) { ++ for (i = 0; i < zldev->info->num_channels; i++) { + zldpll = zl3073x_dpll_alloc(zldev, i); + if (IS_ERR(zldpll)) { + dev_err_probe(zldev->dev, PTR_ERR(zldpll), +@@ -994,14 +1032,12 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) + /** + * zl3073x_dev_probe - initialize zl3073x device + * @zldev: pointer to zl3073x device +- * @chip_info: chip info based on compatible + * + * Common initialization of zl3073x device structure. + * + * Returns: 0 on success, <0 on error + */ +-int zl3073x_dev_probe(struct zl3073x_dev *zldev, +- const struct zl3073x_chip_info *chip_info) ++int zl3073x_dev_probe(struct zl3073x_dev *zldev) + { + u16 id, revision, fw_ver; + unsigned int i; +@@ -1013,18 +1049,17 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, + if (rc) + return rc; + +- /* Check it matches */ +- for (i = 0; i < chip_info->num_ids; i++) { +- if (id == chip_info->ids[i]) ++ /* Detect chip variant */ ++ for (i = 0; i < ARRAY_SIZE(zl3073x_chip_ids); i++) { ++ if (zl3073x_chip_ids[i].id == id) + break; + } + +- if (i == chip_info->num_ids) { ++ if (i == ARRAY_SIZE(zl3073x_chip_ids)) + return dev_err_probe(zldev->dev, -ENODEV, +- "Unknown or non-match chip ID: 0x%0x\n", +- id); +- } +- zldev->chip_id = id; ++ "Unknown chip ID: 0x%04x\n", id); ++ ++ zldev->info = &zl3073x_chip_ids[i]; + + /* Read revision, firmware version and custom config version */ + rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); +@@ -1063,7 +1098,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, + "Failed to initialize mutex\n"); + + /* Register DPLL channels */ +- rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels); ++ rc = zl3073x_devm_dpll_init(zldev); + if (rc) + return rc; + +diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h +index fd2af3c..9944062 100644 +--- a/drivers/dpll/zl3073x/core.h ++++ b/drivers/dpll/zl3073x/core.h +@@ -9,6 +9,7 @@ + #include + #include + ++#include "chan.h" + #include "out.h" + #include "ref.h" + #include "regs.h" +@@ -18,27 +19,39 @@ struct device; + struct regmap; + struct zl3073x_dpll; + +-/* +- * Hardware limits for ZL3073x chip family ++ ++enum zl3073x_flags { ++ ZL3073X_FLAG_REF_PHASE_COMP_32_BIT, ++ ZL3073X_FLAG_DIE_TEMP_BIT, ++ ZL3073X_FLAGS_NBITS /* must be last */ ++}; ++ ++#define __ZL3073X_FLAG(name) BIT(ZL3073X_FLAG_ ## name ## _BIT) ++#define ZL3073X_FLAG_REF_PHASE_COMP_32 __ZL3073X_FLAG(REF_PHASE_COMP_32) ++#define ZL3073X_FLAG_DIE_TEMP __ZL3073X_FLAG(DIE_TEMP) ++ ++/** ++ * struct zl3073x_chip_info - chip variant identification ++ * @id: chip ID ++ * @num_channels: number of DPLL channels supported by this variant ++ * @flags: chip variant flags + */ +-#define ZL3073X_MAX_CHANNELS 5 +-#define ZL3073X_NUM_REFS 10 +-#define ZL3073X_NUM_OUTS 10 +-#define ZL3073X_NUM_SYNTHS 5 +-#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS +-#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2) +-#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ +- ZL3073X_NUM_OUTPUT_PINS) ++struct zl3073x_chip_info { ++ u16 id; ++ u8 num_channels; ++ unsigned long flags; ++}; + + /** + * struct zl3073x_dev - zl3073x device + * @dev: pointer to device + * @regmap: regmap to access device registers ++ * @info: detected chip info + * @multiop_lock: to serialize multiple register operations +- * @chip_id: chip ID read from hardware + * @ref: array of input references' invariants + * @out: array of outs' invariants + * @synth: array of synths' invariants ++ * @chan: array of DPLL channels' state + * @dplls: list of DPLLs + * @kworker: thread for periodic work + * @work: periodic work +@@ -46,15 +59,16 @@ struct zl3073x_dpll; + * @phase_avg_factor: phase offset measurement averaging factor + */ + struct zl3073x_dev { +- struct device *dev; +- struct regmap *regmap; +- struct mutex multiop_lock; +- u16 chip_id; ++ struct device *dev; ++ struct regmap *regmap; ++ const struct zl3073x_chip_info *info; ++ struct mutex multiop_lock; + + /* Invariants */ + struct zl3073x_ref ref[ZL3073X_NUM_REFS]; + struct zl3073x_out out[ZL3073X_NUM_OUTS]; + struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS]; ++ struct zl3073x_chan chan[ZL3073X_MAX_CHANNELS]; + + /* DPLL channels */ + struct list_head dplls; +@@ -68,22 +82,10 @@ struct zl3073x_dev { + u8 phase_avg_factor; + }; + +-struct zl3073x_chip_info { +- const u16 *ids; +- size_t num_ids; +- int num_channels; +-}; +- +-extern const struct zl3073x_chip_info zl30731_chip_info; +-extern const struct zl3073x_chip_info zl30732_chip_info; +-extern const struct zl3073x_chip_info zl30733_chip_info; +-extern const struct zl3073x_chip_info zl30734_chip_info; +-extern const struct zl3073x_chip_info zl30735_chip_info; + extern const struct regmap_config zl3073x_regmap_config; + + struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev); +-int zl3073x_dev_probe(struct zl3073x_dev *zldev, +- const struct zl3073x_chip_info *chip_info); ++int zl3073x_dev_probe(struct zl3073x_dev *zldev); + + int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full); + void zl3073x_dev_stop(struct zl3073x_dev *zldev); +@@ -158,18 +160,7 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel); + static inline bool + zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev) + { +- switch (zldev->chip_id) { +- case 0x0E30: +- case 0x0E93: +- case 0x0E94: +- case 0x0E95: +- case 0x0E96: +- case 0x0E97: +- case 0x1F60: +- return true; +- default: +- return false; +- } ++ return zldev->info->flags & ZL3073X_FLAG_REF_PHASE_COMP_32; + } + + static inline bool +diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c +index 8ffbede..55195dc 100644 +--- a/drivers/dpll/zl3073x/dpll.c ++++ b/drivers/dpll/zl3073x/dpll.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -30,32 +31,34 @@ + * @dpll: DPLL the pin is registered to + * @dpll_pin: pointer to registered dpll_pin + * @tracker: tracking object for the acquired reference ++ * @fwnode: firmware node handle + * @label: package label + * @dir: pin direction + * @id: pin id + * @prio: pin priority <0, 14> +- * @selectable: pin is selectable in automatic mode + * @esync_control: embedded sync is controllable + * @phase_gran: phase adjustment granularity + * @pin_state: last saved pin state + * @phase_offset: last saved pin phase offset + * @freq_offset: last saved fractional frequency offset ++ * @measured_freq: last saved measured frequency + */ + struct zl3073x_dpll_pin { + struct list_head list; + struct zl3073x_dpll *dpll; + struct dpll_pin *dpll_pin; + dpll_tracker tracker; ++ struct fwnode_handle *fwnode; + char label[8]; + enum dpll_pin_direction dir; + u8 id; + u8 prio; +- bool selectable; + bool esync_control; + s32 phase_gran; + enum dpll_pin_state pin_state; + s64 phase_offset; + s64 freq_offset; ++ u32 measured_freq; + }; + + /* +@@ -133,7 +136,13 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin, + ref_id = zl3073x_input_pin_ref_get(pin->id); + ref = zl3073x_ref_state_get(zldev, ref_id); + +- switch (FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl)) { ++ if (!pin->esync_control || zl3073x_ref_freq_get(ref) <= 1) ++ return -EOPNOTSUPP; ++ ++ esync->range = esync_freq_ranges; ++ esync->range_num = ARRAY_SIZE(esync_freq_ranges); ++ ++ switch (zl3073x_ref_sync_mode_get(ref)) { + case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75: + esync->freq = ref->esync_n_div == ZL_REF_ESYNC_DIV_1HZ ? 1 : 0; + esync->pulse = 25; +@@ -144,17 +153,6 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin, + break; + } + +- /* If the pin supports esync control expose its range but only +- * if the current reference frequency is > 1 Hz. +- */ +- if (pin->esync_control && zl3073x_ref_freq_get(ref) > 1) { +- esync->range = esync_freq_ranges; +- esync->range_num = ARRAY_SIZE(esync_freq_ranges); +- } else { +- esync->range = NULL; +- esync->range_num = 0; +- } +- + return 0; + } + +@@ -180,8 +178,7 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin, + else + sync_mode = ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75; + +- ref.sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE; +- ref.sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode); ++ zl3073x_ref_sync_mode_set(&ref, sync_mode); + + if (freq) { + /* 1 Hz is only supported frequency now */ +@@ -192,6 +189,109 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin, + return zl3073x_ref_state_set(zldev, ref_id, &ref); + } + ++static int ++zl3073x_dpll_input_pin_ref_sync_get(const struct dpll_pin *dpll_pin, ++ void *pin_priv, ++ const struct dpll_pin *ref_sync_pin, ++ void *ref_sync_pin_priv, ++ enum dpll_pin_state *state, ++ struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv; ++ struct zl3073x_dpll_pin *pin = pin_priv; ++ struct zl3073x_dpll *zldpll = pin->dpll; ++ struct zl3073x_dev *zldev = zldpll->dev; ++ const struct zl3073x_ref *ref; ++ u8 ref_id, mode, pair; ++ ++ ref_id = zl3073x_input_pin_ref_get(pin->id); ++ ref = zl3073x_ref_state_get(zldev, ref_id); ++ mode = zl3073x_ref_sync_mode_get(ref); ++ pair = zl3073x_ref_sync_pair_get(ref); ++ ++ if (mode == ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR && ++ pair == zl3073x_input_pin_ref_get(sync_pin->id)) ++ *state = DPLL_PIN_STATE_CONNECTED; ++ else ++ *state = DPLL_PIN_STATE_DISCONNECTED; ++ ++ return 0; ++} ++ ++static int ++zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin, ++ void *pin_priv, ++ const struct dpll_pin *ref_sync_pin, ++ void *ref_sync_pin_priv, ++ const enum dpll_pin_state state, ++ struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv; ++ struct zl3073x_dpll_pin *pin = pin_priv; ++ struct zl3073x_dpll *zldpll = pin->dpll; ++ struct zl3073x_dev *zldev = zldpll->dev; ++ u8 mode, ref_id, sync_ref_id; ++ struct zl3073x_chan chan; ++ struct zl3073x_ref ref; ++ int rc; ++ ++ ref_id = zl3073x_input_pin_ref_get(pin->id); ++ sync_ref_id = zl3073x_input_pin_ref_get(sync_pin->id); ++ ref = *zl3073x_ref_state_get(zldev, ref_id); ++ ++ if (state == DPLL_PIN_STATE_CONNECTED) { ++ const struct zl3073x_ref *sync_ref; ++ u32 ref_freq, sync_freq; ++ ++ sync_ref = zl3073x_ref_state_get(zldev, sync_ref_id); ++ ref_freq = zl3073x_ref_freq_get(&ref); ++ sync_freq = zl3073x_ref_freq_get(sync_ref); ++ ++ /* Sync signal must be 8 kHz or less and clock reference ++ * must be 1 kHz or more and higher than the sync signal. ++ */ ++ if (sync_freq > 8000) { ++ NL_SET_ERR_MSG(extack, ++ "sync frequency must be 8 kHz or less"); ++ return -EINVAL; ++ } ++ if (ref_freq < 1000) { ++ NL_SET_ERR_MSG(extack, ++ "clock frequency must be 1 kHz or more"); ++ return -EINVAL; ++ } ++ if (ref_freq <= sync_freq) { ++ NL_SET_ERR_MSG(extack, ++ "clock frequency must be higher than sync frequency"); ++ return -EINVAL; ++ } ++ ++ zl3073x_ref_sync_pair_set(&ref, sync_ref_id); ++ mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR; ++ } else { ++ mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF; ++ } ++ ++ zl3073x_ref_sync_mode_set(&ref, mode); ++ ++ rc = zl3073x_ref_state_set(zldev, ref_id, &ref); ++ if (rc) ++ return rc; ++ ++ /* Exclude sync source from automatic reference selection by setting ++ * its priority to NONE. On disconnect the priority is left as NONE ++ * and the user must explicitly make the pin selectable again. ++ */ ++ if (state == DPLL_PIN_STATE_CONNECTED) { ++ chan = *zl3073x_chan_state_get(zldev, zldpll->id); ++ zl3073x_chan_ref_prio_set(&chan, sync_ref_id, ++ ZL_DPLL_REF_PRIO_NONE); ++ return zl3073x_chan_state_set(zldev, zldpll->id, &chan); ++ } ++ ++ return 0; ++} ++ + static int + zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, +@@ -204,6 +304,21 @@ zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv, + return 0; + } + ++static int ++zl3073x_dpll_input_pin_measured_freq_get(const struct dpll_pin *dpll_pin, ++ void *pin_priv, ++ const struct dpll_device *dpll, ++ void *dpll_priv, u64 *measured_freq, ++ struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll_pin *pin = pin_priv; ++ ++ *measured_freq = pin->measured_freq; ++ *measured_freq *= DPLL_PIN_MEASURED_FREQUENCY_DIVIDER; ++ ++ return 0; ++} ++ + static int + zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin, + void *pin_priv, +@@ -245,156 +360,27 @@ zl3073x_dpll_input_pin_frequency_set(const struct dpll_pin *dpll_pin, + return zl3073x_ref_state_set(zldev, ref_id, &ref); + } + +-/** +- * zl3073x_dpll_selected_ref_get - get currently selected reference +- * @zldpll: pointer to zl3073x_dpll +- * @ref: place to store selected reference +- * +- * Check for currently selected reference the DPLL should be locked to +- * and stores its index to given @ref. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_dpll_selected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) +-{ +- struct zl3073x_dev *zldev = zldpll->dev; +- u8 state, value; +- int rc; +- +- switch (zldpll->refsel_mode) { +- case ZL_DPLL_MODE_REFSEL_MODE_AUTO: +- /* For automatic mode read refsel_status register */ +- rc = zl3073x_read_u8(zldev, +- ZL_REG_DPLL_REFSEL_STATUS(zldpll->id), +- &value); +- if (rc) +- return rc; +- +- /* Extract reference state */ +- state = FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, value); +- +- /* Return the reference only if the DPLL is locked to it */ +- if (state == ZL_DPLL_REFSEL_STATUS_STATE_LOCK) +- *ref = FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, value); +- else +- *ref = ZL3073X_DPLL_REF_NONE; +- break; +- case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: +- /* For manual mode return stored value */ +- *ref = zldpll->forced_ref; +- break; +- default: +- /* For other modes like NCO, freerun... there is no input ref */ +- *ref = ZL3073X_DPLL_REF_NONE; +- break; +- } +- +- return 0; +-} +- +-/** +- * zl3073x_dpll_selected_ref_set - select reference in manual mode +- * @zldpll: pointer to zl3073x_dpll +- * @ref: input reference to be selected +- * +- * Selects the given reference for the DPLL channel it should be +- * locked to. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_dpll_selected_ref_set(struct zl3073x_dpll *zldpll, u8 ref) +-{ +- struct zl3073x_dev *zldev = zldpll->dev; +- u8 mode, mode_refsel; +- int rc; +- +- mode = zldpll->refsel_mode; +- +- switch (mode) { +- case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: +- /* Manual mode with ref selected */ +- if (ref == ZL3073X_DPLL_REF_NONE) { +- switch (zldpll->lock_status) { +- case DPLL_LOCK_STATUS_LOCKED_HO_ACQ: +- case DPLL_LOCK_STATUS_HOLDOVER: +- /* Switch to forced holdover */ +- mode = ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER; +- break; +- default: +- /* Switch to freerun */ +- mode = ZL_DPLL_MODE_REFSEL_MODE_FREERUN; +- break; +- } +- /* Keep selected reference */ +- ref = zldpll->forced_ref; +- } else if (ref == zldpll->forced_ref) { +- /* No register update - same mode and same ref */ +- return 0; +- } +- break; +- case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: +- case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: +- /* Manual mode without no ref */ +- if (ref == ZL3073X_DPLL_REF_NONE) +- /* No register update - keep current mode */ +- return 0; +- +- /* Switch to reflock mode and update ref selection */ +- mode = ZL_DPLL_MODE_REFSEL_MODE_REFLOCK; +- break; +- default: +- /* For other modes like automatic or NCO ref cannot be selected +- * manually +- */ +- return -EOPNOTSUPP; +- } +- +- /* Build mode_refsel value */ +- mode_refsel = FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, mode) | +- FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref); +- +- /* Update dpll_mode_refsel register */ +- rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id), +- mode_refsel); +- if (rc) +- return rc; +- +- /* Store new mode and forced reference */ +- zldpll->refsel_mode = mode; +- zldpll->forced_ref = ref; +- +- return rc; +-} +- + /** + * zl3073x_dpll_connected_ref_get - get currently connected reference + * @zldpll: pointer to zl3073x_dpll +- * @ref: place to store selected reference + * +- * Looks for currently connected the DPLL is locked to and stores its index +- * to given @ref. ++ * Looks for currently connected reference the DPLL is locked to. + * +- * Return: 0 on success, <0 on error ++ * Return: reference index if locked, ZL3073X_DPLL_REF_NONE otherwise + */ +-static int +-zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) ++static u8 ++zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll) + { +- struct zl3073x_dev *zldev = zldpll->dev; +- int rc; +- +- /* Get currently selected input reference */ +- rc = zl3073x_dpll_selected_ref_get(zldpll, ref); +- if (rc) +- return rc; ++ const struct zl3073x_chan *chan = zl3073x_chan_state_get(zldpll->dev, ++ zldpll->id); ++ u8 state; + +- /* If the monitor indicates an error nothing is connected */ +- if (ZL3073X_DPLL_REF_IS_VALID(*ref) && +- !zl3073x_dev_ref_is_status_ok(zldev, *ref)) +- *ref = ZL3073X_DPLL_REF_NONE; ++ /* A reference is connected only when the DPLL is locked to it */ ++ state = zl3073x_chan_refsel_state_get(chan); ++ if (state == ZL_DPLL_REFSEL_STATUS_STATE_LOCK) ++ return zl3073x_chan_refsel_ref_get(chan); + +- return 0; ++ return ZL3073X_DPLL_REF_NONE; + } + + static int +@@ -410,12 +396,9 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin, + const struct zl3073x_ref *ref; + u8 conn_id, ref_id; + s64 ref_phase; +- int rc; + + /* Get currently connected reference */ +- rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_id); +- if (rc) +- return rc; ++ conn_id = zl3073x_dpll_connected_ref_get(zldpll); + + /* Report phase offset only for currently connected pin if the phase + * monitor feature is disabled and only if the input pin signal is +@@ -453,7 +436,7 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin, + + *phase_offset = ref_phase * DPLL_PHASE_OFFSET_DIVIDER; + +- return rc; ++ return 0; + } + + static int +@@ -516,98 +499,6 @@ zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, + return zl3073x_ref_state_set(zldev, ref_id, &ref); + } + +-/** +- * zl3073x_dpll_ref_prio_get - get priority for given input pin +- * @pin: pointer to pin +- * @prio: place to store priority +- * +- * Reads current priority for the given input pin and stores the value +- * to @prio. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) +-{ +- struct zl3073x_dpll *zldpll = pin->dpll; +- struct zl3073x_dev *zldev = zldpll->dev; +- u8 ref, ref_prio; +- int rc; +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read DPLL configuration */ +- rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, +- ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); +- if (rc) +- return rc; +- +- /* Read reference priority - one value for P&N pins (4 bits/pin) */ +- ref = zl3073x_input_pin_ref_get(pin->id); +- rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), +- &ref_prio); +- if (rc) +- return rc; +- +- /* Select nibble according pin type */ +- if (zl3073x_dpll_is_p_pin(pin)) +- *prio = FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, ref_prio); +- else +- *prio = FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, ref_prio); +- +- return rc; +-} +- +-/** +- * zl3073x_dpll_ref_prio_set - set priority for given input pin +- * @pin: pointer to pin +- * @prio: place to store priority +- * +- * Sets priority for the given input pin. +- * +- * Return: 0 on success, <0 on error +- */ +-static int +-zl3073x_dpll_ref_prio_set(struct zl3073x_dpll_pin *pin, u8 prio) +-{ +- struct zl3073x_dpll *zldpll = pin->dpll; +- struct zl3073x_dev *zldev = zldpll->dev; +- u8 ref, ref_prio; +- int rc; +- +- guard(mutex)(&zldev->multiop_lock); +- +- /* Read DPLL configuration into mailbox */ +- rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, +- ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); +- if (rc) +- return rc; +- +- /* Read reference priority - one value shared between P&N pins */ +- ref = zl3073x_input_pin_ref_get(pin->id); +- rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), &ref_prio); +- if (rc) +- return rc; +- +- /* Update nibble according pin type */ +- if (zl3073x_dpll_is_p_pin(pin)) { +- ref_prio &= ~ZL_DPLL_REF_PRIO_REF_P; +- ref_prio |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_P, prio); +- } else { +- ref_prio &= ~ZL_DPLL_REF_PRIO_REF_N; +- ref_prio |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_N, prio); +- } +- +- /* Update reference priority */ +- rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), ref_prio); +- if (rc) +- return rc; +- +- /* Commit configuration */ +- return zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR, +- ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); +-} +- + /** + * zl3073x_dpll_ref_state_get - get status for given input pin + * @pin: pointer to pin +@@ -624,17 +515,14 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin, + { + struct zl3073x_dpll *zldpll = pin->dpll; + struct zl3073x_dev *zldev = zldpll->dev; +- u8 ref, ref_conn; +- int rc; ++ const struct zl3073x_chan *chan; ++ u8 ref; + ++ chan = zl3073x_chan_state_get(zldev, zldpll->id); + ref = zl3073x_input_pin_ref_get(pin->id); + +- /* Get currently connected reference */ +- rc = zl3073x_dpll_connected_ref_get(zldpll, &ref_conn); +- if (rc) +- return rc; +- +- if (ref == ref_conn) { ++ /* Check if the pin reference is connected */ ++ if (ref == zl3073x_dpll_connected_ref_get(zldpll)) { + *state = DPLL_PIN_STATE_CONNECTED; + return 0; + } +@@ -643,8 +531,9 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin, + * selectable and its monitor does not report any error then report + * pin as selectable. + */ +- if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_AUTO && +- zl3073x_dev_ref_is_status_ok(zldev, ref) && pin->selectable) { ++ if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO && ++ zl3073x_dev_ref_is_status_ok(zldev, ref) && ++ zl3073x_chan_ref_is_selectable(chan, ref)) { + *state = DPLL_PIN_STATE_SELECTABLE; + return 0; + } +@@ -678,68 +567,81 @@ zl3073x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *dpll_pin, + { + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dpll_pin *pin = pin_priv; +- u8 new_ref; ++ struct zl3073x_chan chan; ++ u8 mode, ref; + int rc; + +- switch (zldpll->refsel_mode) { ++ chan = *zl3073x_chan_state_get(zldpll->dev, zldpll->id); ++ ref = zl3073x_input_pin_ref_get(pin->id); ++ mode = zl3073x_chan_mode_get(&chan); ++ ++ switch (mode) { + case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: +- case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: +- case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: + if (state == DPLL_PIN_STATE_CONNECTED) { + /* Choose the pin as new selected reference */ +- new_ref = zl3073x_input_pin_ref_get(pin->id); ++ zl3073x_chan_ref_set(&chan, ref); + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { +- /* No reference */ +- new_ref = ZL3073X_DPLL_REF_NONE; ++ /* Choose new mode based on lock status */ ++ switch (zldpll->lock_status) { ++ case DPLL_LOCK_STATUS_LOCKED_HO_ACQ: ++ case DPLL_LOCK_STATUS_HOLDOVER: ++ mode = ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER; ++ break; ++ default: ++ mode = ZL_DPLL_MODE_REFSEL_MODE_FREERUN; ++ break; ++ } ++ zl3073x_chan_mode_set(&chan, mode); + } else { +- NL_SET_ERR_MSG_MOD(extack, +- "Invalid pin state for manual mode"); +- return -EINVAL; ++ goto invalid_state; ++ } ++ break; ++ case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: ++ case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: ++ if (state == DPLL_PIN_STATE_CONNECTED) { ++ /* Choose the pin as new selected reference */ ++ zl3073x_chan_ref_set(&chan, ref); ++ /* Switch to reflock mode */ ++ zl3073x_chan_mode_set(&chan, ++ ZL_DPLL_MODE_REFSEL_MODE_REFLOCK); ++ } else if (state != DPLL_PIN_STATE_DISCONNECTED) { ++ goto invalid_state; + } +- +- rc = zl3073x_dpll_selected_ref_set(zldpll, new_ref); + break; +- + case ZL_DPLL_MODE_REFSEL_MODE_AUTO: + if (state == DPLL_PIN_STATE_SELECTABLE) { +- if (pin->selectable) ++ if (zl3073x_chan_ref_is_selectable(&chan, ref)) + return 0; /* Pin is already selectable */ + + /* Restore pin priority in HW */ +- rc = zl3073x_dpll_ref_prio_set(pin, pin->prio); +- if (rc) +- return rc; +- +- /* Mark pin as selectable */ +- pin->selectable = true; ++ zl3073x_chan_ref_prio_set(&chan, ref, pin->prio); + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { +- if (!pin->selectable) ++ if (!zl3073x_chan_ref_is_selectable(&chan, ref)) + return 0; /* Pin is already disconnected */ + + /* Set pin priority to none in HW */ +- rc = zl3073x_dpll_ref_prio_set(pin, +- ZL_DPLL_REF_PRIO_NONE); +- if (rc) +- return rc; +- +- /* Mark pin as non-selectable */ +- pin->selectable = false; ++ zl3073x_chan_ref_prio_set(&chan, ref, ++ ZL_DPLL_REF_PRIO_NONE); + } else { +- NL_SET_ERR_MSG(extack, +- "Invalid pin state for automatic mode"); +- return -EINVAL; ++ goto invalid_state; + } + break; +- + default: + /* In other modes we cannot change input reference */ + NL_SET_ERR_MSG(extack, + "Pin state cannot be changed in current mode"); +- rc = -EOPNOTSUPP; +- break; ++ return -EOPNOTSUPP; + } + +- return rc; ++ /* Commit DPLL channel changes */ ++ rc = zl3073x_chan_state_set(zldpll->dev, zldpll->id, &chan); ++ if (rc) ++ return rc; ++ ++ return 0; ++invalid_state: ++ NL_SET_ERR_MSG_MOD(extack, "Invalid pin state for this device mode"); ++ return -EINVAL; + } + + static int +@@ -759,15 +661,21 @@ zl3073x_dpll_input_pin_prio_set(const struct dpll_pin *dpll_pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 prio, struct netlink_ext_ack *extack) + { ++ struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dpll_pin *pin = pin_priv; ++ struct zl3073x_chan chan; ++ u8 ref; + int rc; + + if (prio > ZL_DPLL_REF_PRIO_MAX) + return -EINVAL; + + /* If the pin is selectable then update HW registers */ +- if (pin->selectable) { +- rc = zl3073x_dpll_ref_prio_set(pin, prio); ++ chan = *zl3073x_chan_state_get(zldpll->dev, zldpll->id); ++ ref = zl3073x_input_pin_ref_get(pin->id); ++ if (zl3073x_chan_ref_is_selectable(&chan, ref)) { ++ zl3073x_chan_ref_prio_set(&chan, ref, prio); ++ rc = zl3073x_chan_state_set(zldpll->dev, zldpll->id, &chan); + if (rc) + return rc; + } +@@ -791,8 +699,8 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll_pin *pin = pin_priv; + const struct zl3073x_synth *synth; + const struct zl3073x_out *out; +- u8 clock_type, out_id; +- u32 synth_freq; ++ u32 synth_freq, out_freq; ++ u8 out_id; + + out_id = zl3073x_output_pin_out_get(pin->id); + out = zl3073x_out_state_get(zldev, out_id); +@@ -801,29 +709,30 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + * for N-division is also used for the esync divider so both cannot + * be used. + */ +- switch (zl3073x_out_signal_format_get(out)) { +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: ++ if (zl3073x_out_is_ndiv(out)) + return -EOPNOTSUPP; +- default: +- break; +- } + + /* Get attached synth frequency */ + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); + synth_freq = zl3073x_synth_freq_get(synth); ++ out_freq = synth_freq / out->div; ++ ++ if (!pin->esync_control || out_freq <= 1) ++ return -EOPNOTSUPP; ++ ++ esync->range = esync_freq_ranges; ++ esync->range_num = ARRAY_SIZE(esync_freq_ranges); + +- clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode); +- if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) { ++ if (zl3073x_out_clock_type_get(out) != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) { + /* No need to read esync data if it is not enabled */ + esync->freq = 0; + esync->pulse = 0; + +- goto finish; ++ return 0; + } + + /* Compute esync frequency */ +- esync->freq = synth_freq / out->div / out->esync_n_period; ++ esync->freq = out_freq / out->esync_n_period; + + /* By comparing the esync_pulse_width to the half of the pulse width + * the esync pulse percentage can be determined. +@@ -832,18 +741,6 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin, + */ + esync->pulse = (50 * out->esync_n_width) / out->div; + +-finish: +- /* Set supported esync ranges if the pin supports esync control and +- * if the output frequency is > 1 Hz. +- */ +- if (pin->esync_control && (synth_freq / out->div) > 1) { +- esync->range = esync_freq_ranges; +- esync->range_num = ARRAY_SIZE(esync_freq_ranges); +- } else { +- esync->range = NULL; +- esync->range_num = 0; +- } +- + return 0; + } + +@@ -859,8 +756,8 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + struct zl3073x_dpll_pin *pin = pin_priv; + const struct zl3073x_synth *synth; + struct zl3073x_out out; +- u8 clock_type, out_id; + u32 synth_freq; ++ u8 out_id; + + out_id = zl3073x_output_pin_out_get(pin->id); + out = *zl3073x_out_state_get(zldev, out_id); +@@ -869,23 +766,16 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin, + * for N-division is also used for the esync divider so both cannot + * be used. + */ +- switch (zl3073x_out_signal_format_get(&out)) { +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: +- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: ++ if (zl3073x_out_is_ndiv(&out)) + return -EOPNOTSUPP; +- default: +- break; +- } + +- /* Select clock type */ ++ /* Update clock type in output mode */ + if (freq) +- clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC; ++ zl3073x_out_clock_type_set(&out, ++ ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC); + else +- clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL; +- +- /* Update clock type in output mode */ +- out.mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE; +- out.mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); ++ zl3073x_out_clock_type_set(&out, ++ ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL); + + /* If esync is being disabled just write mailbox and finish */ + if (!freq) +@@ -937,9 +827,9 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, + struct zl3073x_dev *zldev = zldpll->dev; + struct zl3073x_dpll_pin *pin = pin_priv; + const struct zl3073x_synth *synth; +- u8 out_id, signal_format; + u32 new_div, synth_freq; + struct zl3073x_out out; ++ u8 out_id; + + out_id = zl3073x_output_pin_out_get(pin->id); + out = *zl3073x_out_state_get(zldev, out_id); +@@ -949,12 +839,8 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin, + synth_freq = zl3073x_synth_freq_get(synth); + new_div = synth_freq / (u32)frequency; + +- /* Get used signal format for the given output */ +- signal_format = zl3073x_out_signal_format_get(&out); +- + /* Check signal format */ +- if (signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV && +- signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV) { ++ if (!zl3073x_out_is_ndiv(&out)) { + /* For non N-divided signal formats the frequency is computed + * as division of synth frequency and output divisor. + */ +@@ -1065,6 +951,25 @@ zl3073x_dpll_output_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, + return 0; + } + ++static int ++zl3073x_dpll_temp_get(const struct dpll_device *dpll, void *dpll_priv, ++ s32 *temp, struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll *zldpll = dpll_priv; ++ struct zl3073x_dev *zldev = zldpll->dev; ++ u16 val; ++ int rc; ++ ++ rc = zl3073x_read_u16(zldev, ZL_REG_DIE_TEMP_STATUS, &val); ++ if (rc) ++ return rc; ++ ++ /* Register value is in units of 0.1 C, convert to millidegrees */ ++ *temp = (s16)val * 100; ++ ++ return 0; ++} ++ + static int + zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_lock_status *status, +@@ -1072,11 +977,11 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, + struct netlink_ext_ack *extack) + { + struct zl3073x_dpll *zldpll = dpll_priv; +- struct zl3073x_dev *zldev = zldpll->dev; +- u8 mon_status, state; +- int rc; ++ const struct zl3073x_chan *chan; ++ ++ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); + +- switch (zldpll->refsel_mode) { ++ switch (zl3073x_chan_mode_get(chan)) { + case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: + case ZL_DPLL_MODE_REFSEL_MODE_NCO: + /* In FREERUN and NCO modes the DPLL is always unlocked */ +@@ -1087,16 +992,9 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, + break; + } + +- /* Read DPLL monitor status */ +- rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(zldpll->id), +- &mon_status); +- if (rc) +- return rc; +- state = FIELD_GET(ZL_DPLL_MON_STATUS_STATE, mon_status); +- +- switch (state) { ++ switch (zl3073x_chan_lock_state_get(chan)) { + case ZL_DPLL_MON_STATUS_STATE_LOCK: +- if (FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, mon_status)) ++ if (zl3073x_chan_is_ho_ready(chan)) + *status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ; + else + *status = DPLL_LOCK_STATUS_LOCKED; +@@ -1106,8 +1004,9 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, + *status = DPLL_LOCK_STATUS_HOLDOVER; + break; + default: +- dev_warn(zldev->dev, "Unknown DPLL monitor status: 0x%02x\n", +- mon_status); ++ dev_warn(zldpll->dev->dev, ++ "Unknown DPLL monitor status: 0x%02x\n", ++ chan->mon_status); + *status = DPLL_LOCK_STATUS_UNLOCKED; + break; + } +@@ -1121,13 +1020,16 @@ zl3073x_dpll_supported_modes_get(const struct dpll_device *dpll, + struct netlink_ext_ack *extack) + { + struct zl3073x_dpll *zldpll = dpll_priv; ++ const struct zl3073x_chan *chan; ++ ++ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); + + /* We support switching between automatic and manual mode, except in + * a case where the DPLL channel is configured to run in NCO mode. + * In this case, report only the manual mode to which the NCO is mapped + * as the only supported one. + */ +- if (zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_NCO) ++ if (zl3073x_chan_mode_get(chan) != ZL_DPLL_MODE_REFSEL_MODE_NCO) + __set_bit(DPLL_MODE_AUTOMATIC, modes); + + __set_bit(DPLL_MODE_MANUAL, modes); +@@ -1140,8 +1042,11 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_mode *mode, struct netlink_ext_ack *extack) + { + struct zl3073x_dpll *zldpll = dpll_priv; ++ const struct zl3073x_chan *chan; + +- switch (zldpll->refsel_mode) { ++ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); ++ ++ switch (zl3073x_chan_mode_get(chan)) { + case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: + case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: + case ZL_DPLL_MODE_REFSEL_MODE_NCO: +@@ -1220,14 +1125,12 @@ zl3073x_dpll_mode_set(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_mode mode, struct netlink_ext_ack *extack) + { + struct zl3073x_dpll *zldpll = dpll_priv; +- u8 hw_mode, mode_refsel, ref; ++ struct zl3073x_chan chan; ++ u8 hw_mode, ref; + int rc; + +- rc = zl3073x_dpll_selected_ref_get(zldpll, &ref); +- if (rc) { +- NL_SET_ERR_MSG_MOD(extack, "failed to get selected reference"); +- return rc; +- } ++ chan = *zl3073x_chan_state_get(zldpll->dev, zldpll->id); ++ ref = zl3073x_chan_refsel_ref_get(&chan); + + if (mode == DPLL_MODE_MANUAL) { + /* We are switching from automatic to manual mode: +@@ -1250,44 +1153,32 @@ zl3073x_dpll_mode_set(const struct dpll_device *dpll, void *dpll_priv, + * it is selectable after switch to automatic mode + * - switch to automatic mode + */ +- struct zl3073x_dpll_pin *pin; +- +- pin = zl3073x_dpll_pin_get_by_ref(zldpll, ref); +- if (pin && !pin->selectable) { +- /* Restore pin priority in HW */ +- rc = zl3073x_dpll_ref_prio_set(pin, pin->prio); +- if (rc) { +- NL_SET_ERR_MSG_MOD(extack, +- "failed to restore pin priority"); +- return rc; ++ if (ZL3073X_DPLL_REF_IS_VALID(ref) && ++ !zl3073x_chan_ref_is_selectable(&chan, ref)) { ++ struct zl3073x_dpll_pin *pin; ++ ++ pin = zl3073x_dpll_pin_get_by_ref(zldpll, ref); ++ if (pin) { ++ /* Restore pin priority in HW */ ++ zl3073x_chan_ref_prio_set(&chan, ref, ++ pin->prio); + } +- +- pin->selectable = true; + } + + hw_mode = ZL_DPLL_MODE_REFSEL_MODE_AUTO; + } + +- /* Build mode_refsel value */ +- mode_refsel = FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, hw_mode); +- ++ zl3073x_chan_mode_set(&chan, hw_mode); + if (ZL3073X_DPLL_REF_IS_VALID(ref)) +- mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref); ++ zl3073x_chan_ref_set(&chan, ref); + +- /* Update dpll_mode_refsel register */ +- rc = zl3073x_write_u8(zldpll->dev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id), +- mode_refsel); ++ rc = zl3073x_chan_state_set(zldpll->dev, zldpll->id, &chan); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, + "failed to set reference selection mode"); + return rc; + } + +- zldpll->refsel_mode = hw_mode; +- +- if (ZL3073X_DPLL_REF_IS_VALID(ref)) +- zldpll->forced_ref = ref; +- + return 0; + } + +@@ -1320,6 +1211,35 @@ zl3073x_dpll_phase_offset_monitor_set(const struct dpll_device *dpll, + return 0; + } + ++static int ++zl3073x_dpll_freq_monitor_get(const struct dpll_device *dpll, ++ void *dpll_priv, ++ enum dpll_feature_state *state, ++ struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll *zldpll = dpll_priv; ++ ++ if (zldpll->freq_monitor) ++ *state = DPLL_FEATURE_STATE_ENABLE; ++ else ++ *state = DPLL_FEATURE_STATE_DISABLE; ++ ++ return 0; ++} ++ ++static int ++zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll, ++ void *dpll_priv, ++ enum dpll_feature_state state, ++ struct netlink_ext_ack *extack) ++{ ++ struct zl3073x_dpll *zldpll = dpll_priv; ++ ++ zldpll->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE); ++ ++ return 0; ++} ++ + static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { + .direction_get = zl3073x_dpll_pin_direction_get, + .esync_get = zl3073x_dpll_input_pin_esync_get, +@@ -1327,11 +1247,14 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { + .ffo_get = zl3073x_dpll_input_pin_ffo_get, + .frequency_get = zl3073x_dpll_input_pin_frequency_get, + .frequency_set = zl3073x_dpll_input_pin_frequency_set, ++ .measured_freq_get = zl3073x_dpll_input_pin_measured_freq_get, + .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, + .phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get, + .phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set, + .prio_get = zl3073x_dpll_input_pin_prio_get, + .prio_set = zl3073x_dpll_input_pin_prio_set, ++ .ref_sync_get = zl3073x_dpll_input_pin_ref_sync_get, ++ .ref_sync_set = zl3073x_dpll_input_pin_ref_sync_set, + .state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get, + .state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set, + }; +@@ -1355,6 +1278,8 @@ static const struct dpll_device_ops zl3073x_dpll_device_ops = { + .phase_offset_avg_factor_set = zl3073x_dpll_phase_offset_avg_factor_set, + .phase_offset_monitor_get = zl3073x_dpll_phase_offset_monitor_get, + .phase_offset_monitor_set = zl3073x_dpll_phase_offset_monitor_set, ++ .freq_monitor_get = zl3073x_dpll_freq_monitor_get, ++ .freq_monitor_set = zl3073x_dpll_freq_monitor_set, + .supported_modes_get = zl3073x_dpll_supported_modes_get, + }; + +@@ -1422,24 +1347,25 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index) + if (IS_ERR(props)) + return PTR_ERR(props); + +- /* Save package label, esync capability and phase adjust granularity */ ++ /* Save package label, fwnode, esync capability and phase adjust ++ * granularity. ++ */ + strscpy(pin->label, props->package_label); ++ pin->fwnode = fwnode_handle_get(props->fwnode); + pin->esync_control = props->esync_control; + pin->phase_gran = props->dpll_props.phase_gran; + + if (zl3073x_dpll_is_input_pin(pin)) { +- rc = zl3073x_dpll_ref_prio_get(pin, &pin->prio); +- if (rc) +- goto err_prio_get; ++ const struct zl3073x_chan *chan; ++ u8 ref; + +- if (pin->prio == ZL_DPLL_REF_PRIO_NONE) { +- /* Clamp prio to max value & mark pin non-selectable */ ++ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); ++ ref = zl3073x_input_pin_ref_get(pin->id); ++ pin->prio = zl3073x_chan_ref_prio_get(chan, ref); ++ ++ if (pin->prio == ZL_DPLL_REF_PRIO_NONE) ++ /* Clamp prio to max value */ + pin->prio = ZL_DPLL_REF_PRIO_MAX; +- pin->selectable = false; +- } else { +- /* Mark pin as selectable */ +- pin->selectable = true; +- } + } + + /* Create or get existing DPLL pin */ +@@ -1468,9 +1394,10 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index) + + err_register: + dpll_pin_put(pin->dpll_pin, &pin->tracker); +-err_prio_get: + pin->dpll_pin = NULL; + err_pin_get: ++ fwnode_handle_put(pin->fwnode); ++ pin->fwnode = NULL; + zl3073x_pin_props_put(props); + + return rc; +@@ -1500,6 +1427,9 @@ zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin) + + dpll_pin_put(pin->dpll_pin, &pin->tracker); + pin->dpll_pin = NULL; ++ ++ fwnode_handle_put(pin->fwnode); ++ pin->fwnode = NULL; + } + + /** +@@ -1540,15 +1470,18 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll, + enum dpll_pin_direction dir, u8 index) + { + struct zl3073x_dev *zldev = zldpll->dev; ++ const struct zl3073x_chan *chan; + bool is_diff, is_enabled; + const char *name; + ++ chan = zl3073x_chan_state_get(zldev, zldpll->id); ++ + if (dir == DPLL_PIN_DIRECTION_INPUT) { + u8 ref_id = zl3073x_input_pin_ref_get(index); + const struct zl3073x_ref *ref; + + /* Skip the pin if the DPLL is running in NCO mode */ +- if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO) ++ if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_NCO) + return false; + + name = "REF"; +@@ -1656,20 +1589,11 @@ static int + zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll) + { + struct zl3073x_dev *zldev = zldpll->dev; +- u8 dpll_mode_refsel; + int rc; + +- /* Read DPLL mode and forcibly selected reference */ +- rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id), +- &dpll_mode_refsel); +- if (rc) +- return rc; +- +- /* Extract mode and selected input reference */ +- zldpll->refsel_mode = FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, +- dpll_mode_refsel); +- zldpll->forced_ref = FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, +- dpll_mode_refsel); ++ zldpll->ops = zl3073x_dpll_device_ops; ++ if (zldev->info->flags & ZL3073X_FLAG_DIE_TEMP) ++ zldpll->ops.temp_get = zl3073x_dpll_temp_get; + + zldpll->dpll_dev = dpll_device_get(zldev->clock_id, zldpll->id, + THIS_MODULE, &zldpll->tracker); +@@ -1682,7 +1606,7 @@ zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll) + + rc = dpll_device_register(zldpll->dpll_dev, + zl3073x_prop_dpll_type_get(zldev, zldpll->id), +- &zl3073x_dpll_device_ops, zldpll); ++ &zldpll->ops, zldpll); + if (rc) { + dpll_device_put(zldpll->dpll_dev, &zldpll->tracker); + zldpll->dpll_dev = NULL; +@@ -1705,8 +1629,7 @@ zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll) + + cancel_work_sync(&zldpll->change_work); + +- dpll_device_unregister(zldpll->dpll_dev, &zl3073x_dpll_device_ops, +- zldpll); ++ dpll_device_unregister(zldpll->dpll_dev, &zldpll->ops, zldpll); + dpll_device_put(zldpll->dpll_dev, &zldpll->tracker); + zldpll->dpll_dev = NULL; + } +@@ -1786,6 +1709,7 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin) + struct zl3073x_dev *zldev = zldpll->dev; + const struct zl3073x_ref *ref; + u8 ref_id; ++ s64 ffo; + + /* Get reference monitor status */ + ref_id = zl3073x_input_pin_ref_get(pin->id); +@@ -1796,10 +1720,47 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin) + return false; + + /* Compare with previous value */ +- if (pin->freq_offset != ref->ffo) { ++ ffo = zl3073x_ref_ffo_get(ref); ++ if (pin->freq_offset != ffo) { + dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n", +- pin->label, pin->freq_offset, ref->ffo); +- pin->freq_offset = ref->ffo; ++ pin->label, pin->freq_offset, ffo); ++ pin->freq_offset = ffo; ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++/** ++ * zl3073x_dpll_pin_measured_freq_check - check for pin measured frequency ++ * change ++ * @pin: pin to check ++ * ++ * Check for the given pin's measured frequency change. ++ * ++ * Return: true on measured frequency change, false otherwise ++ */ ++static bool ++zl3073x_dpll_pin_measured_freq_check(struct zl3073x_dpll_pin *pin) ++{ ++ struct zl3073x_dpll *zldpll = pin->dpll; ++ struct zl3073x_dev *zldev = zldpll->dev; ++ const struct zl3073x_ref *ref; ++ u8 ref_id; ++ u32 freq; ++ ++ if (!zldpll->freq_monitor) ++ return false; ++ ++ ref_id = zl3073x_input_pin_ref_get(pin->id); ++ ref = zl3073x_ref_state_get(zldev, ref_id); ++ ++ freq = zl3073x_ref_meas_freq_get(ref); ++ if (pin->measured_freq != freq) { ++ dev_dbg(zldev->dev, "%s measured freq changed: %u -> %u\n", ++ pin->label, pin->measured_freq, freq); ++ pin->measured_freq = freq; + + return true; + } +@@ -1822,8 +1783,10 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll) + struct zl3073x_dev *zldev = zldpll->dev; + enum dpll_lock_status lock_status; + struct device *dev = zldev->dev; ++ const struct zl3073x_chan *chan; + struct zl3073x_dpll_pin *pin; + int rc; ++ u8 mode; + + zldpll->check_count++; + +@@ -1845,8 +1808,10 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll) + /* Input pin monitoring does make sense only in automatic + * or forced reference modes. + */ +- if (zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO && +- zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK) ++ chan = zl3073x_chan_state_get(zldev, zldpll->id); ++ mode = zl3073x_chan_mode_get(chan); ++ if (mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO && ++ mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK) + return; + + /* Update phase offset latch registers for this DPLL if the phase +@@ -1887,13 +1852,18 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll) + pin_changed = true; + } + +- /* Check for phase offset and ffo change once per second */ ++ /* Check for phase offset, ffo, and measured freq change ++ * once per second. ++ */ + if (zldpll->check_count % 2 == 0) { + if (zl3073x_dpll_pin_phase_offset_check(pin)) + pin_changed = true; + + if (zl3073x_dpll_pin_ffo_check(pin)) + pin_changed = true; ++ ++ if (zl3073x_dpll_pin_measured_freq_check(pin)) ++ pin_changed = true; + } + + if (pin_changed) +@@ -1973,6 +1943,88 @@ zl3073x_dpll_free(struct zl3073x_dpll *zldpll) + kfree(zldpll); + } + ++/** ++ * zl3073x_dpll_ref_sync_pair_register - register ref_sync pairs for a pin ++ * @pin: pointer to zl3073x_dpll_pin structure ++ * ++ * Iterates 'ref-sync-sources' phandles in the pin's firmware node and ++ * registers each declared pairing. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++static int ++zl3073x_dpll_ref_sync_pair_register(struct zl3073x_dpll_pin *pin) ++{ ++ struct zl3073x_dev *zldev = pin->dpll->dev; ++ struct fwnode_handle *fwnode; ++ struct dpll_pin *sync_pin; ++ dpll_tracker tracker; ++ int n, rc; ++ ++ for (n = 0; ; n++) { ++ /* Get n'th ref-sync source */ ++ fwnode = fwnode_find_reference(pin->fwnode, "ref-sync-sources", ++ n); ++ if (IS_ERR(fwnode)) { ++ rc = PTR_ERR(fwnode); ++ break; ++ } ++ ++ /* Find associated dpll pin */ ++ sync_pin = fwnode_dpll_pin_find(fwnode, &tracker); ++ fwnode_handle_put(fwnode); ++ if (!sync_pin) { ++ dev_warn(zldev->dev, "%s: ref-sync source %d not found", ++ pin->label, n); ++ continue; ++ } ++ ++ /* Register new ref-sync pair */ ++ rc = dpll_pin_ref_sync_pair_add(pin->dpll_pin, sync_pin); ++ dpll_pin_put(sync_pin, &tracker); ++ ++ /* -EBUSY means pairing already exists from another DPLL's ++ * registration. ++ */ ++ if (rc && rc != -EBUSY) { ++ dev_err(zldev->dev, ++ "%s: failed to add ref-sync source %d: %pe", ++ pin->label, n, ERR_PTR(rc)); ++ break; ++ } ++ } ++ ++ return rc != -ENOENT ? rc : 0; ++} ++ ++/** ++ * zl3073x_dpll_ref_sync_pairs_register - register ref_sync pairs for a DPLL ++ * @zldpll: pointer to zl3073x_dpll structure ++ * ++ * Iterates all registered input pins of the given DPLL and establishes ++ * ref_sync pairings declared by 'ref-sync-sources' phandles in the ++ * device tree. ++ * ++ * Return: 0 on success, <0 on error ++ */ ++static int ++zl3073x_dpll_ref_sync_pairs_register(struct zl3073x_dpll *zldpll) ++{ ++ struct zl3073x_dpll_pin *pin; ++ int rc; ++ ++ list_for_each_entry(pin, &zldpll->pins, list) { ++ if (!zl3073x_dpll_is_input_pin(pin) || !pin->fwnode) ++ continue; ++ ++ rc = zl3073x_dpll_ref_sync_pair_register(pin); ++ if (rc) ++ return rc; ++ } ++ ++ return 0; ++} ++ + /** + * zl3073x_dpll_register - register DPLL device and all its pins + * @zldpll: pointer to zl3073x_dpll structure +@@ -1996,6 +2048,13 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll) + return rc; + } + ++ rc = zl3073x_dpll_ref_sync_pairs_register(zldpll); ++ if (rc) { ++ zl3073x_dpll_pins_unregister(zldpll); ++ zl3073x_dpll_device_unregister(zldpll); ++ return rc; ++ } ++ + return 0; + } + +diff --git a/drivers/dpll/zl3073x/dpll.h b/drivers/dpll/zl3073x/dpll.h +index c65c798..434c32a 100644 +--- a/drivers/dpll/zl3073x/dpll.h ++++ b/drivers/dpll/zl3073x/dpll.h +@@ -13,10 +13,10 @@ + * @list: this DPLL list entry + * @dev: pointer to multi-function parent device + * @id: DPLL index +- * @refsel_mode: reference selection mode +- * @forced_ref: selected reference in forced reference lock mode + * @check_count: periodic check counter + * @phase_monitor: is phase offset monitor enabled ++ * @freq_monitor: is frequency monitor enabled ++ * @ops: DPLL device operations for this instance + * @dpll_dev: pointer to registered DPLL device + * @tracker: tracking object for the acquired reference + * @lock_status: last saved DPLL lock status +@@ -27,10 +27,10 @@ struct zl3073x_dpll { + struct list_head list; + struct zl3073x_dev *dev; + u8 id; +- u8 refsel_mode; +- u8 forced_ref; + u8 check_count; + bool phase_monitor; ++ bool freq_monitor; ++ struct dpll_device_ops ops; + struct dpll_device *dpll_dev; + dpll_tracker tracker; + enum dpll_lock_status lock_status; +diff --git a/drivers/dpll/zl3073x/flash.c b/drivers/dpll/zl3073x/flash.c +index e2771dd..fa7ee9e 100644 +--- a/drivers/dpll/zl3073x/flash.c ++++ b/drivers/dpll/zl3073x/flash.c +@@ -194,8 +194,7 @@ zl3073x_flash_cmd_wait(struct zl3073x_dev *zldev, u32 operation, + if (rc) + return rc; + +- value &= ~ZL_WRITE_FLASH_OP; +- value |= FIELD_PREP(ZL_WRITE_FLASH_OP, operation); ++ FIELD_MODIFY(ZL_WRITE_FLASH_OP, &value, operation); + + rc = zl3073x_write_u8(zldev, ZL_REG_WRITE_FLASH, value); + if (rc) +diff --git a/drivers/dpll/zl3073x/i2c.c b/drivers/dpll/zl3073x/i2c.c +index a7ac128..2f36f2e 100644 +--- a/drivers/dpll/zl3073x/i2c.c ++++ b/drivers/dpll/zl3073x/i2c.c +@@ -22,40 +22,25 @@ static int zl3073x_i2c_probe(struct i2c_client *client) + return dev_err_probe(dev, PTR_ERR(zldev->regmap), + "Failed to initialize regmap\n"); + +- return zl3073x_dev_probe(zldev, i2c_get_match_data(client)); ++ return zl3073x_dev_probe(zldev); + } + + static const struct i2c_device_id zl3073x_i2c_id[] = { +- { +- .name = "zl30731", +- .driver_data = (kernel_ulong_t)&zl30731_chip_info, +- }, +- { +- .name = "zl30732", +- .driver_data = (kernel_ulong_t)&zl30732_chip_info, +- }, +- { +- .name = "zl30733", +- .driver_data = (kernel_ulong_t)&zl30733_chip_info, +- }, +- { +- .name = "zl30734", +- .driver_data = (kernel_ulong_t)&zl30734_chip_info, +- }, +- { +- .name = "zl30735", +- .driver_data = (kernel_ulong_t)&zl30735_chip_info, +- }, ++ { "zl30731" }, ++ { "zl30732" }, ++ { "zl30733" }, ++ { "zl30734" }, ++ { "zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id); + + static const struct of_device_id zl3073x_i2c_of_match[] = { +- { .compatible = "microchip,zl30731", .data = &zl30731_chip_info }, +- { .compatible = "microchip,zl30732", .data = &zl30732_chip_info }, +- { .compatible = "microchip,zl30733", .data = &zl30733_chip_info }, +- { .compatible = "microchip,zl30734", .data = &zl30734_chip_info }, +- { .compatible = "microchip,zl30735", .data = &zl30735_chip_info }, ++ { .compatible = "microchip,zl30731" }, ++ { .compatible = "microchip,zl30732" }, ++ { .compatible = "microchip,zl30733" }, ++ { .compatible = "microchip,zl30734" }, ++ { .compatible = "microchip,zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match); +diff --git a/drivers/dpll/zl3073x/out.c b/drivers/dpll/zl3073x/out.c +index 86829a0..eb5628a 100644 +--- a/drivers/dpll/zl3073x/out.c ++++ b/drivers/dpll/zl3073x/out.c +@@ -106,12 +106,32 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, + return &zldev->out[index]; + } + ++/** ++ * zl3073x_out_state_set - commit output state changes to hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: output index to set state for ++ * @out: desired output state ++ * ++ * Validates that invariant fields have not been modified, skips the HW ++ * write if the mutable configuration is unchanged, and otherwise writes ++ * only the changed cfg fields to hardware via the mailbox interface. ++ * ++ * Return: 0 on success, -EINVAL if invariants changed, <0 on HW error ++ */ + int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_out *out) + { + struct zl3073x_out *dout = &zldev->out[index]; + int rc; + ++ /* Reject attempts to change invariant fields (set at fetch only) */ ++ if (WARN_ON(memcmp(&dout->inv, &out->inv, sizeof(out->inv)))) ++ return -EINVAL; ++ ++ /* Skip HW write if configuration hasn't changed */ ++ if (!memcmp(&dout->cfg, &out->cfg, sizeof(out->cfg))) ++ return 0; ++ + guard(mutex)(&zldev->multiop_lock); + + /* Read output configuration into mailbox */ +@@ -146,12 +166,7 @@ int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, + return rc; + + /* After successful commit store new state */ +- dout->div = out->div; +- dout->width = out->width; +- dout->esync_n_period = out->esync_n_period; +- dout->esync_n_width = out->esync_n_width; +- dout->mode = out->mode; +- dout->phase_comp = out->phase_comp; ++ dout->cfg = out->cfg; + + return 0; + } +diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h +index 318f9bb..660889c 100644 +--- a/drivers/dpll/zl3073x/out.h ++++ b/drivers/dpll/zl3073x/out.h +@@ -4,6 +4,7 @@ + #define _ZL3073X_OUT_H + + #include ++#include + #include + + #include "regs.h" +@@ -17,17 +18,21 @@ struct zl3073x_dev; + * @esync_n_period: embedded sync or n-pin period (for n-div formats) + * @esync_n_width: embedded sync or n-pin pulse width + * @phase_comp: phase compensation +- * @ctrl: output control + * @mode: output mode ++ * @ctrl: output control + */ + struct zl3073x_out { +- u32 div; +- u32 width; +- u32 esync_n_period; +- u32 esync_n_width; +- s32 phase_comp; +- u8 ctrl; +- u8 mode; ++ struct_group(cfg, /* Config */ ++ u32 div; ++ u32 width; ++ u32 esync_n_period; ++ u32 esync_n_width; ++ s32 phase_comp; ++ u8 mode; ++ ); ++ struct_group(inv, /* Invariants */ ++ u8 ctrl; ++ ); + }; + + int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index); +@@ -37,6 +42,28 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, + int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_out *out); + ++/** ++ * zl3073x_out_clock_type_get - get output clock type ++ * @out: pointer to out state ++ * ++ * Return: clock type of given output (ZL_OUTPUT_MODE_CLOCK_TYPE_*) ++ */ ++static inline u8 zl3073x_out_clock_type_get(const struct zl3073x_out *out) ++{ ++ return FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode); ++} ++ ++/** ++ * zl3073x_out_clock_type_set - set output clock type ++ * @out: pointer to out state ++ * @type: clock type (ZL_OUTPUT_MODE_CLOCK_TYPE_*) ++ */ ++static inline void ++zl3073x_out_clock_type_set(struct zl3073x_out *out, u8 type) ++{ ++ FIELD_MODIFY(ZL_OUTPUT_MODE_CLOCK_TYPE, &out->mode, type); ++} ++ + /** + * zl3073x_out_signal_format_get - get output signal format + * @out: pointer to out state +diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c +index 6b65e61..825ac30 100644 +--- a/drivers/dpll/zl3073x/ref.c ++++ b/drivers/dpll/zl3073x/ref.c +@@ -51,6 +51,21 @@ zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult) + return -EINVAL; + } + ++/** ++ * zl3073x_ref_state_update - update input reference status from HW ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: input reference index ++ * ++ * Return: 0 on success, <0 on error ++ */ ++int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index) ++{ ++ struct zl3073x_ref *ref = &zldev->ref[index]; ++ ++ return zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(index), ++ &ref->mon_status); ++} ++ + /** + * zl3073x_ref_state_fetch - fetch input reference state from hardware + * @zldev: pointer to zl3073x_dev structure +@@ -73,18 +88,17 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) + struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/ + + /* Copy the shared items from the P-pin */ +- ref->config = p_ref->config; +- ref->esync_n_div = p_ref->esync_n_div; +- ref->freq_base = p_ref->freq_base; +- ref->freq_mult = p_ref->freq_mult; +- ref->freq_ratio_m = p_ref->freq_ratio_m; +- ref->freq_ratio_n = p_ref->freq_ratio_n; +- ref->phase_comp = p_ref->phase_comp; +- ref->sync_ctrl = p_ref->sync_ctrl; ++ ref->cfg = p_ref->cfg; ++ ref->inv = p_ref->inv; + + return 0; /* Finish - no non-shared items for now */ + } + ++ /* Read reference status */ ++ rc = zl3073x_ref_state_update(zldev, index); ++ if (rc) ++ return rc; ++ + guard(mutex)(&zldev->multiop_lock); + + /* Read reference configuration */ +@@ -154,12 +168,32 @@ zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index) + return &zldev->ref[index]; + } + ++/** ++ * zl3073x_ref_state_set - commit input reference state changes to hardware ++ * @zldev: pointer to zl3073x_dev structure ++ * @index: input reference index to set state for ++ * @ref: desired reference state ++ * ++ * Validates that invariant fields have not been modified, skips the HW ++ * write if the mutable configuration is unchanged, and otherwise writes ++ * only the changed cfg fields to hardware via the mailbox interface. ++ * ++ * Return: 0 on success, -EINVAL if invariants changed, <0 on HW error ++ */ + int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_ref *ref) + { + struct zl3073x_ref *dref = &zldev->ref[index]; + int rc; + ++ /* Reject attempts to change invariant fields (set at init only) */ ++ if (WARN_ON(memcmp(&dref->inv, &ref->inv, sizeof(ref->inv)))) ++ return -EINVAL; ++ ++ /* Skip HW write if configuration hasn't changed */ ++ if (!memcmp(&dref->cfg, &ref->cfg, sizeof(ref->cfg))) ++ return 0; ++ + guard(mutex)(&zldev->multiop_lock); + + /* Read reference configuration into mailbox */ +@@ -207,13 +241,7 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, + return rc; + + /* After successful commit store new state */ +- dref->freq_base = ref->freq_base; +- dref->freq_mult = ref->freq_mult; +- dref->freq_ratio_m = ref->freq_ratio_m; +- dref->freq_ratio_n = ref->freq_ratio_n; +- dref->esync_n_div = ref->esync_n_div; +- dref->sync_ctrl = ref->sync_ctrl; +- dref->phase_comp = ref->phase_comp; ++ dref->cfg = ref->cfg; + + return 0; + } +diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h +index 0d8618f..55e80e4 100644 +--- a/drivers/dpll/zl3073x/ref.h ++++ b/drivers/dpll/zl3073x/ref.h +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + + #include "regs.h" +@@ -13,28 +14,36 @@ struct zl3073x_dev; + + /** + * struct zl3073x_ref - input reference state +- * @ffo: current fractional frequency offset + * @phase_comp: phase compensation + * @esync_n_div: divisor for embedded sync or n-divided signal formats + * @freq_base: frequency base + * @freq_mult: frequnecy multiplier + * @freq_ratio_m: FEC mode multiplier + * @freq_ratio_n: FEC mode divisor +- * @config: reference config + * @sync_ctrl: reference sync control ++ * @config: reference config ++ * @ffo: current fractional frequency offset ++ * @meas_freq: measured input frequency in Hz + * @mon_status: reference monitor status + */ + struct zl3073x_ref { +- s64 ffo; +- u64 phase_comp; +- u32 esync_n_div; +- u16 freq_base; +- u16 freq_mult; +- u16 freq_ratio_m; +- u16 freq_ratio_n; +- u8 config; +- u8 sync_ctrl; +- u8 mon_status; ++ struct_group(cfg, /* Configuration */ ++ u64 phase_comp; ++ u32 esync_n_div; ++ u16 freq_base; ++ u16 freq_mult; ++ u16 freq_ratio_m; ++ u16 freq_ratio_n; ++ u8 sync_ctrl; ++ ); ++ struct_group(inv, /* Invariants */ ++ u8 config; ++ ); ++ struct_group(stat, /* Status */ ++ s64 ffo; ++ u32 meas_freq; ++ u8 mon_status; ++ ); + }; + + int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index); +@@ -45,6 +54,8 @@ const struct zl3073x_ref *zl3073x_ref_state_get(struct zl3073x_dev *zldev, + int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, + const struct zl3073x_ref *ref); + ++int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index); ++ + int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult); + + /** +@@ -59,6 +70,18 @@ zl3073x_ref_ffo_get(const struct zl3073x_ref *ref) + return ref->ffo; + } + ++/** ++ * zl3073x_ref_meas_freq_get - get measured input frequency ++ * @ref: pointer to ref state ++ * ++ * Return: measured input frequency in Hz ++ */ ++static inline u32 ++zl3073x_ref_meas_freq_get(const struct zl3073x_ref *ref) ++{ ++ return ref->meas_freq; ++} ++ + /** + * zl3073x_ref_freq_get - get given input reference frequency + * @ref: pointer to ref state +@@ -97,6 +120,52 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq) + return 0; + } + ++/** ++ * zl3073x_ref_sync_mode_get - get sync control mode ++ * @ref: pointer to ref state ++ * ++ * Return: sync control mode (ZL_REF_SYNC_CTRL_MODE_*) ++ */ ++static inline u8 ++zl3073x_ref_sync_mode_get(const struct zl3073x_ref *ref) ++{ ++ return FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl); ++} ++ ++/** ++ * zl3073x_ref_sync_mode_set - set sync control mode ++ * @ref: pointer to ref state ++ * @mode: sync control mode (ZL_REF_SYNC_CTRL_MODE_*) ++ */ ++static inline void ++zl3073x_ref_sync_mode_set(struct zl3073x_ref *ref, u8 mode) ++{ ++ FIELD_MODIFY(ZL_REF_SYNC_CTRL_MODE, &ref->sync_ctrl, mode); ++} ++ ++/** ++ * zl3073x_ref_sync_pair_get - get sync pair reference index ++ * @ref: pointer to ref state ++ * ++ * Return: paired reference index ++ */ ++static inline u8 ++zl3073x_ref_sync_pair_get(const struct zl3073x_ref *ref) ++{ ++ return FIELD_GET(ZL_REF_SYNC_CTRL_PAIR, ref->sync_ctrl); ++} ++ ++/** ++ * zl3073x_ref_sync_pair_set - set sync pair reference index ++ * @ref: pointer to ref state ++ * @pair: paired reference index ++ */ ++static inline void ++zl3073x_ref_sync_pair_set(struct zl3073x_ref *ref, u8 pair) ++{ ++ FIELD_MODIFY(ZL_REF_SYNC_CTRL_PAIR, &ref->sync_ctrl, pair); ++} ++ + /** + * zl3073x_ref_is_diff - check if the given input reference is differential + * @ref: pointer to ref state +diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h +index 5573d71..d425dc6 100644 +--- a/drivers/dpll/zl3073x/regs.h ++++ b/drivers/dpll/zl3073x/regs.h +@@ -6,6 +6,18 @@ + #include + #include + ++/* ++ * Hardware limits for ZL3073x chip family ++ */ ++#define ZL3073X_MAX_CHANNELS 5 ++#define ZL3073X_NUM_REFS 10 ++#define ZL3073X_NUM_OUTS 10 ++#define ZL3073X_NUM_SYNTHS 5 ++#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS ++#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2) ++#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ ++ ZL3073X_NUM_OUTPUT_PINS) ++ + /* + * Register address structure: + * =========================== +@@ -78,6 +90,8 @@ + #define ZL_REG_RESET_STATUS ZL_REG(0, 0x18, 1) + #define ZL_REG_RESET_STATUS_RESET BIT(0) + ++#define ZL_REG_DIE_TEMP_STATUS ZL_REG(0, 0x44, 2) ++ + /************************* + * Register Page 2, Status + *************************/ +@@ -199,7 +213,9 @@ + #define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1) + #define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0) + #define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0 ++#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR 1 + #define ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75 2 ++#define ZL_REF_SYNC_CTRL_PAIR GENMASK(7, 4) + + #define ZL_REG_REF_ESYNC_DIV ZL_REG(10, 0x30, 4) + #define ZL_REF_ESYNC_DIV_1HZ 0 +diff --git a/drivers/dpll/zl3073x/spi.c b/drivers/dpll/zl3073x/spi.c +index 00c5e38..ad43bf9 100644 +--- a/drivers/dpll/zl3073x/spi.c ++++ b/drivers/dpll/zl3073x/spi.c +@@ -22,40 +22,25 @@ static int zl3073x_spi_probe(struct spi_device *spi) + return dev_err_probe(dev, PTR_ERR(zldev->regmap), + "Failed to initialize regmap\n"); + +- return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi)); ++ return zl3073x_dev_probe(zldev); + } + + static const struct spi_device_id zl3073x_spi_id[] = { +- { +- .name = "zl30731", +- .driver_data = (kernel_ulong_t)&zl30731_chip_info +- }, +- { +- .name = "zl30732", +- .driver_data = (kernel_ulong_t)&zl30732_chip_info, +- }, +- { +- .name = "zl30733", +- .driver_data = (kernel_ulong_t)&zl30733_chip_info, +- }, +- { +- .name = "zl30734", +- .driver_data = (kernel_ulong_t)&zl30734_chip_info, +- }, +- { +- .name = "zl30735", +- .driver_data = (kernel_ulong_t)&zl30735_chip_info, +- }, ++ { "zl30731" }, ++ { "zl30732" }, ++ { "zl30733" }, ++ { "zl30734" }, ++ { "zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(spi, zl3073x_spi_id); + + static const struct of_device_id zl3073x_spi_of_match[] = { +- { .compatible = "microchip,zl30731", .data = &zl30731_chip_info }, +- { .compatible = "microchip,zl30732", .data = &zl30732_chip_info }, +- { .compatible = "microchip,zl30733", .data = &zl30733_chip_info }, +- { .compatible = "microchip,zl30734", .data = &zl30734_chip_info }, +- { .compatible = "microchip,zl30735", .data = &zl30735_chip_info }, ++ { .compatible = "microchip,zl30731" }, ++ { .compatible = "microchip,zl30732" }, ++ { .compatible = "microchip,zl30733" }, ++ { .compatible = "microchip,zl30734" }, ++ { .compatible = "microchip,zl30735" }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match); +diff --git a/drivers/dpll/zl3073x/synth.h b/drivers/dpll/zl3073x/synth.h +index 6c55eb8..89e13ea 100644 +--- a/drivers/dpll/zl3073x/synth.h ++++ b/drivers/dpll/zl3073x/synth.h +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + + #include "regs.h" +@@ -20,11 +21,13 @@ struct zl3073x_dev; + * @ctrl: synth control + */ + struct zl3073x_synth { +- u32 freq_mult; +- u16 freq_base; +- u16 freq_m; +- u16 freq_n; +- u8 ctrl; ++ struct_group(inv, /* Invariants */ ++ u32 freq_mult; ++ u16 freq_base; ++ u16 freq_m; ++ u16 freq_n; ++ u8 ctrl; ++ ); + }; + + int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id); +@@ -32,9 +35,6 @@ int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id); + const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev, + u8 synth_id); + +-int zl3073x_synth_state_set(struct zl3073x_dev *zldev, u8 synth_id, +- const struct zl3073x_synth *synth); +- + /** + * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by + * @synth: pointer to synth state +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index 6961f6e..7f8fa58 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -55,8 +55,12 @@ struct dpll_device_ops { + void *dpll_priv, u32 *factor, + struct netlink_ext_ack *extack); + +- RH_KABI_RESERVE(1) +- RH_KABI_RESERVE(2) ++ RH_KABI_USE(1, int (*freq_monitor_set)(const struct dpll_device *dpll, void *dpll_priv, ++ enum dpll_feature_state state, ++ struct netlink_ext_ack *extack)) ++ RH_KABI_USE(2, int (*freq_monitor_get)(const struct dpll_device *dpll, void *dpll_priv, ++ enum dpll_feature_state *state, ++ struct netlink_ext_ack *extack)) + RH_KABI_RESERVE(3) + RH_KABI_RESERVE(4) + RH_KABI_RESERVE(5) +@@ -141,7 +145,10 @@ struct dpll_pin_ops { + enum dpll_pin_state *state, + struct netlink_ext_ack *extack); + +- RH_KABI_RESERVE(1) ++ RH_KABI_USE(1, int (*measured_freq_get)(const struct dpll_pin *pin, void *pin_priv, ++ const struct dpll_device *dpll, ++ void *dpll_priv, u64 *measured_freq, ++ struct netlink_ext_ack *extack)) + RH_KABI_RESERVE(2) + RH_KABI_RESERVE(3) + RH_KABI_RESERVE(4) +diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h +index 603a88c..93614cc 100644 +--- a/include/uapi/linux/dpll.h ++++ b/include/uapi/linux/dpll.h +@@ -190,7 +190,8 @@ enum dpll_pin_capabilities { + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE = 4, + }; + +-#define DPLL_PHASE_OFFSET_DIVIDER 1000 ++#define DPLL_PHASE_OFFSET_DIVIDER 1000 ++#define DPLL_PIN_MEASURED_FREQUENCY_DIVIDER 1000 + + /** + * enum dpll_feature_state - Allow control (enable/disable) and status checking +@@ -217,6 +218,7 @@ enum dpll_a { + DPLL_A_CLOCK_QUALITY_LEVEL, + DPLL_A_PHASE_OFFSET_MONITOR, + DPLL_A_PHASE_OFFSET_AVG_FACTOR, ++ DPLL_A_FREQUENCY_MONITOR, + + __DPLL_A_MAX, + DPLL_A_MAX = (__DPLL_A_MAX - 1) +@@ -253,6 +255,7 @@ enum dpll_a_pin { + DPLL_A_PIN_REFERENCE_SYNC, + DPLL_A_PIN_PHASE_ADJUST_GRAN, + DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, ++ DPLL_A_PIN_MEASURED_FREQUENCY, + + __DPLL_A_PIN_MAX, + DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) diff --git a/SOURCES/1284-ice-rss-queues-RHEL.patch b/SOURCES/1284-ice-rss-queues-RHEL.patch new file mode 100644 index 000000000..f1ecbdb04 --- /dev/null +++ b/SOURCES/1284-ice-rss-queues-RHEL.patch @@ -0,0 +1,256 @@ +Subject: [PATCH] ice: default RSS queues series incl RHEL ice_rh (RHEL-174336/177526) +# AlmaLinux: reconstructed; includes RHEL-only ice_rh.c/.h + +diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile +index 0b8cf4e..3da38fc 100644 +--- a/drivers/net/ethernet/intel/ice/Makefile ++++ b/drivers/net/ethernet/intel/ice/Makefile +@@ -43,7 +43,8 @@ ice-y := ice_main.o \ + ice_repr.o \ + ice_tc_lib.o \ + ice_debugfs.o \ +- ice_adapter.o ++ ice_adapter.o \ ++ ice_rh.o + ice-$(CONFIG_PCI_IOV) += \ + ice_sriov.o \ + virt/allowlist.o \ +diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h +index a23ccd4..480db81 100644 +--- a/drivers/net/ethernet/intel/ice/ice.h ++++ b/drivers/net/ethernet/intel/ice/ice.h +@@ -837,6 +837,28 @@ static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid) + WRITE_ONCE(ring->xsk_pool, ice_get_xp_from_qid(vsi, qid)); + } + ++/** ++ * ice_get_max_txq - return the maximum number of Tx queues for in a PF ++ * @pf: PF structure ++ * ++ * Return: maximum number of Tx queues ++ */ ++static inline int ice_get_max_txq(struct ice_pf *pf) ++{ ++ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq); ++} ++ ++/** ++ * ice_get_max_rxq - return the maximum number of Rx queues for in a PF ++ * @pf: PF structure ++ * ++ * Return: maximum number of Rx queues ++ */ ++static inline int ice_get_max_rxq(struct ice_pf *pf) ++{ ++ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq); ++} ++ + /** + * ice_get_main_vsi - Get the PF VSI + * @pf: PF instance +diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c +index 912d800..db6adaa 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c ++++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c +@@ -3744,24 +3744,6 @@ ice_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info) + return 0; + } + +-/** +- * ice_get_max_txq - return the maximum number of Tx queues for in a PF +- * @pf: PF structure +- */ +-static int ice_get_max_txq(struct ice_pf *pf) +-{ +- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq); +-} +- +-/** +- * ice_get_max_rxq - return the maximum number of Rx queues for in a PF +- * @pf: PF structure +- */ +-static int ice_get_max_rxq(struct ice_pf *pf) +-{ +- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq); +-} +- + /** + * ice_get_combined_cnt - return the current number of combined channels + * @vsi: PF VSI pointer +diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c +index 30801fd..4766951 100644 +--- a/drivers/net/ethernet/intel/ice/ice_irq.c ++++ b/drivers/net/ethernet/intel/ice/ice_irq.c +@@ -4,6 +4,7 @@ + #include "ice.h" + #include "ice_lib.h" + #include "ice_irq.h" ++#include "ice_rh.h" + + /** + * ice_init_irq_tracker - initialize interrupt tracker +@@ -106,9 +107,10 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, + #define ICE_RDMA_AEQ_MSIX 1 + static int ice_get_default_msix_amount(struct ice_pf *pf) + { +- return ICE_MIN_LAN_OICR_MSIX + num_online_cpus() + ++ return ICE_MIN_LAN_OICR_MSIX + ice_rh_get_num_default_rss_queues() + + (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? ICE_FDIR_MSIX : 0) + +- (ice_is_rdma_ena(pf) ? num_online_cpus() + ICE_RDMA_AEQ_MSIX : 0); ++ (ice_is_rdma_ena(pf) ? ice_rh_get_num_default_rss_queues() + ++ ICE_RDMA_AEQ_MSIX : 0); + } + + /** +diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c +index d668806..72c91bd 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_lib.c +@@ -9,6 +9,7 @@ + #include "ice_dcb_lib.h" + #include "ice_type.h" + #include "ice_vsi_vlan_ops.h" ++#include "ice_rh.h" + + /** + * ice_vsi_type_str - maps VSI type enum to string equivalents +@@ -159,12 +160,14 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi) + + static u16 ice_get_rxq_count(struct ice_pf *pf) + { +- return min(ice_get_avail_rxq_count(pf), num_online_cpus()); ++ return min(ice_get_avail_rxq_count(pf), ++ ice_rh_get_num_default_rss_queues()); + } + + static u16 ice_get_txq_count(struct ice_pf *pf) + { +- return min(ice_get_avail_txq_count(pf), num_online_cpus()); ++ return min(ice_get_avail_txq_count(pf), ++ ice_rh_get_num_default_rss_queues()); + } + + /** +@@ -911,13 +914,15 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi) + if (vsi->type == ICE_VSI_CHNL) + vsi->rss_size = min_t(u16, vsi->num_rxq, max_rss_size); + else +- vsi->rss_size = min_t(u16, num_online_cpus(), ++ vsi->rss_size = min_t(u16, ++ ice_rh_get_num_default_rss_queues(), + max_rss_size); + vsi->rss_lut_type = ICE_LUT_PF; + break; + case ICE_VSI_SF: + vsi->rss_table_size = ICE_LUT_VSI_SIZE; +- vsi->rss_size = min_t(u16, num_online_cpus(), max_rss_size); ++ vsi->rss_size = min_t(u16, ice_rh_get_num_default_rss_queues(), ++ max_rss_size); + vsi->rss_lut_type = ICE_LUT_VSI; + break; + case ICE_VSI_VF: +@@ -3007,7 +3012,7 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, + * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones + * @vsi: VSI pointer + */ +-static int ++int + ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi) + { + u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq; +diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h +index 2cb1eb9..fce6f63 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lib.h ++++ b/drivers/net/ethernet/intel/ice/ice_lib.h +@@ -66,6 +66,7 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked); + void ice_vsi_decfg(struct ice_vsi *vsi); + void ice_dis_vsi(struct ice_vsi *vsi, bool locked); + ++int ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi); + int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags); + int ice_vsi_cfg(struct ice_vsi *vsi); + struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf); +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index 6b1e6ee..38356f6 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -4730,8 +4730,8 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) + struct net_device *netdev; + u8 mac_addr[ETH_ALEN]; + +- netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq, +- vsi->alloc_rxq); ++ netdev = alloc_etherdev_mqs(sizeof(*np), ice_get_max_txq(vsi->back), ++ ice_get_max_rxq(vsi->back)); + if (!netdev) + return -ENOMEM; + +diff --git a/drivers/net/ethernet/intel/ice/ice_rh.c b/drivers/net/ethernet/intel/ice/ice_rh.c +new file mode 100644 +index 0000000..7660eee +--- /dev/null ++++ b/drivers/net/ethernet/intel/ice/ice_rh.c +@@ -0,0 +1,33 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#include "ice_rh.h" ++ ++/** ++ * ice_rh_get_num_default_rss_queues - default number of RSS queues ++ * ++ * Default value is the number of physical cores if there are only 1 or 2, or ++ * divided by 2 if there are more. ++ * ++ * This is a renamed copy of netif_get_num_default_rss_queues() from upstream. ++ */ ++int ice_rh_get_num_default_rss_queues(void) ++{ ++ cpumask_var_t cpus; ++ int cpu, count = 0; ++ ++ if (unlikely(is_kdump_kernel() || !zalloc_cpumask_var(&cpus, GFP_KERNEL))) ++ return 1; ++ ++ cpumask_copy(cpus, cpu_online_mask); ++ for_each_cpu(cpu, cpus) { ++ ++count; ++ cpumask_andnot(cpus, cpus, topology_sibling_cpumask(cpu)); ++ } ++ free_cpumask_var(cpus); ++ ++ return count > 2 ? DIV_ROUND_UP(count, 2) : count; ++} +diff --git a/drivers/net/ethernet/intel/ice/ice_rh.h b/drivers/net/ethernet/intel/ice/ice_rh.h +new file mode 100644 +index 0000000..d88e00a +--- /dev/null ++++ b/drivers/net/ethernet/intel/ice/ice_rh.h +@@ -0,0 +1,6 @@ ++#ifndef __ICE_RH_H ++#define __ICE_RH_H ++ ++int ice_rh_get_num_default_rss_queues(void); ++ ++#endif +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index e53a1e4..08e3e26 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -268,6 +268,13 @@ static int ice_vf_reconfig_vsi(struct ice_vf *vf) + + vsi->flags = ICE_VSI_FLAG_NO_INIT; + ++ vsi->req_txq = vf->num_req_qs; ++ vsi->req_rxq = vf->num_req_qs; ++ ++ err = ice_vsi_realloc_stat_arrays(vsi); ++ if (err) ++ return err; ++ + ice_vsi_decfg(vsi); + ice_fltr_remove_all(vsi); + diff --git a/SOURCES/Module.kabi_aarch64 b/SOURCES/Module.kabi_aarch64 index 88c74a802..ed4c57807 100644 --- a/SOURCES/Module.kabi_aarch64 +++ b/SOURCES/Module.kabi_aarch64 @@ -1708,163 +1708,6 @@ 0x290bad79 mlx4_write_mtt drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL 0x5b36c4a2 mlx4_xrcd_alloc drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL 0x918cd6e6 mlx4_xrcd_free drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL -0xa16fd523 mlx5_add_flow_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x81e2699b mlx5_alloc_bfreg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x7672da8f mlx5_blocking_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x0fd736a7 mlx5_blocking_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x23255f46 mlx5_cmd_add_privileged_uid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6dda02b6 mlx5_cmd_check drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1ef778b2 mlx5_cmd_cleanup_async_ctx drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x522b4431 mlx5_cmd_create_vport_lag drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1cd98a74 mlx5_cmd_destroy_vport_lag drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbd37c692 mlx5_cmd_do drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x282800df mlx5_cmd_exec drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x562bab7a mlx5_cmd_exec_cb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc3dc5280 mlx5_cmd_init_async_ctx drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x961af1f0 mlx5_cmd_out_err drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1fa9852f mlx5_cmd_remove_privileged_uid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x0a4002db mlx5_comp_eqn_get drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xca05ca8b mlx5_comp_vectors_max drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd07e7d0c mlx5_core_access_reg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xdc853cec mlx5_core_alloc_pd drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb388ccea mlx5_core_create_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3441e413 mlx5_core_create_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xeb09b7b8 mlx5_core_create_psv drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x62560925 mlx5_core_create_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x7ef86a93 mlx5_core_create_rqt drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe22b8924 mlx5_core_create_tis drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x748773e7 mlx5_core_dealloc_pd drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5a52c89e mlx5_core_destroy_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb77ec2da mlx5_core_destroy_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xebbd3531 mlx5_core_destroy_psv drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x20d8360e mlx5_core_modify_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x19e1c3d4 mlx5_core_modify_cq_moderation drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2c376041 mlx5_core_modify_hca_vport_context drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x99ec65f6 mlx5_core_modify_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x94ddba25 mlx5_core_modify_sq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfd027378 mlx5_core_modify_tis drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe6cedc25 mlx5_core_mp_event_replay drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x69bf2cdc mlx5_core_query_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x04c04d8f mlx5_core_query_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x347873bb mlx5_core_query_sq_state drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x2dc2915e mlx5_core_query_vendor_id drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4ed22479 mlx5_core_query_vport_counter drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x51776b7b mlx5_core_reserved_gids_count drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x343a7e55 mlx5_core_roce_gid_set drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x7cb23851 mlx5_core_uplink_netdev_event_replay drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x721a42d6 mlx5_create_auto_grouped_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5c42c4b9 mlx5_create_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb1a2c116 mlx5_create_flow_group drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc7387224 mlx5_create_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfe5e6db5 mlx5_create_lag_demux_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb38d5ce9 mlx5_db_alloc_node drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xaa3d1e23 mlx5_db_free drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x161b06a2 mlx5_debug_qp_add drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x45dc02ba mlx5_debug_qp_remove drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x60307d96 mlx5_debugfs_get_dev_root drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa95deb76 mlx5_debugfs_root drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd51a05ab mlx5_del_flow_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x57b612e8 mlx5_destroy_flow_group drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdb9ff463 mlx5_destroy_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x677f1a83 mlx5_dm_sw_icm_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x02fd07db mlx5_dm_sw_icm_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x562e7236 mlx5_eq_create_generic drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x19a0584e mlx5_eq_destroy_generic drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf1e946e8 mlx5_eq_disable drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb1f030e9 mlx5_eq_enable drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x770e8eb5 mlx5_eq_get_eqe drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9e083b7a mlx5_eq_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc4b08053 mlx5_eq_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc9ff4841 mlx5_eq_update_ci drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x20cde6c5 mlx5_eswitch_add_send_to_vport_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xefc12273 mlx5_eswitch_get_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf876e61c mlx5_eswitch_get_encap_mode drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x32e24179 mlx5_eswitch_get_proto_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd329b533 mlx5_eswitch_get_total_vports drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xb329ecaf mlx5_eswitch_get_vport_metadata_for_match drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x08e13db4 mlx5_eswitch_mode drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x0c178bd7 mlx5_eswitch_register_vport_reps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3185bbb6 mlx5_eswitch_unregister_vport_reps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x71427a70 mlx5_eswitch_uplink_get_proto_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x039f514a mlx5_eswitch_vport_match_metadata_enabled drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd91596a2 mlx5_fc_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5592bf6b mlx5_fc_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8a7cd712 mlx5_fc_local_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6030960f mlx5_fc_local_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xeabf9268 mlx5_fc_query drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x072460c4 mlx5_fill_page_frag_array drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x81aadc6a mlx5_fill_page_frag_array_perm drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x04e078a5 mlx5_flow_table_id drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x95240825 mlx5_frag_buf_alloc_node drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3597af48 mlx5_frag_buf_free drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x956cd1f1 mlx5_free_bfreg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x33ec7df6 mlx5_get_flow_namespace drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbafe8cc6 mlx5_get_flow_vport_namespace drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb8010aed mlx5_get_uars_page drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x66c0b1aa mlx5_is_roce_on drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2e3c17ee mlx5_lag_get_next_peer_mdev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x127b22ae mlx5_lag_get_num_ports drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd8081509 mlx5_lag_get_slave_port drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x871fdc80 mlx5_lag_is_active drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf8e4fc25 mlx5_lag_is_master drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x00d9044e mlx5_lag_is_mpesw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xcfc38fde mlx5_lag_is_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x41454b8c mlx5_lag_is_shared_fdb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x62c41f46 mlx5_lag_is_sriov drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa44daa31 mlx5_lag_mode_is_hash drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1dd0ebe1 mlx5_lag_query_cong_counters drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x64fade05 mlx5_macsec_add_roce_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x37897e7f mlx5_macsec_add_roce_sa_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x42b43a38 mlx5_macsec_del_roce_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x390b982c mlx5_macsec_del_roce_sa_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x89b23e60 mlx5_modify_header_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf8acce42 mlx5_modify_header_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8d32a4f6 mlx5_mpfs_add_mac drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6456eb57 mlx5_mpfs_del_mac drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x00296a87 mlx5_nic_vport_affiliate_multiport drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xf036e184 mlx5_nic_vport_disable_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x52903f7b mlx5_nic_vport_enable_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x1e85de77 mlx5_nic_vport_unaffiliate_multiport drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x4eb45831 mlx5_nic_vport_update_local_lb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xc708cf71 mlx5_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe835af05 mlx5_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x37135fc1 mlx5_packet_reformat_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd72dc8fb mlx5_packet_reformat_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x497175d8 mlx5_put_uars_page drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2ea79214 mlx5_qp_debugfs_cleanup drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x00777ce8 mlx5_qp_debugfs_init drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x59ae5f5b mlx5_query_hca_vport_context drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x731460b7 mlx5_query_hca_vport_gid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x5f4501ac mlx5_query_hca_vport_node_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xb74d42ea mlx5_query_hca_vport_pkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xddb13d55 mlx5_query_hca_vport_system_image_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xce3b7022 mlx5_query_ib_port_oper drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xcfe5e991 mlx5_query_min_inline drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xc28c9ad1 mlx5_query_nic_vport_mac_address drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x7edf73f2 mlx5_query_nic_vport_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x4d29408b mlx5_query_nic_vport_node_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xbfe23e60 mlx5_query_nic_vport_qkey_viol_cntr drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xa9682314 mlx5_query_nic_vport_system_image_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x47bd7760 mlx5_query_port_max_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x5488f88c mlx5_query_port_oper_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xf0229f91 mlx5_query_port_ptys drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x94a74269 mlx5_query_port_vl_hw_cap drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x0ff31a30 mlx5_rdma_rn_get_params drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6b31a6da mlx5_rl_add_rate drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb4fc819f mlx5_rl_add_rate_raw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x61492bb7 mlx5_rl_are_equal drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9e397476 mlx5_rl_remove_rate drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x7c645af3 mlx5_rl_remove_rate_raw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbaee7dfe mlx5_rsc_dump_cmd_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xad6815cd mlx5_rsc_dump_cmd_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc71b4998 mlx5_rsc_dump_next drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3d5c617e mlx5_set_port_caps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xd7f74c10 mlx5_sriov_blocking_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x7bf0e2ae mlx5_sriov_blocking_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x94e7e1f2 mlx5_vf_get_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x009914cd mlx5_vf_put_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4fb51e71 mlx5_vport_get_other_func_cap drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x26fd44d0 mlx5_wc_support_get drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL 0x1d434f3f mlxfw_firmware_flash drivers/net/ethernet/mellanox/mlxfw/mlxfw EXPORT_SYMBOL 0xe16986dd mlxsw_afa_block_activity_get drivers/net/ethernet/mellanox/mlxsw/mlxsw_core EXPORT_SYMBOL 0xd28256cf mlxsw_afa_block_append_allocated_counter drivers/net/ethernet/mellanox/mlxsw/mlxsw_core EXPORT_SYMBOL diff --git a/SOURCES/Module.kabi_s390x b/SOURCES/Module.kabi_s390x index 1e01af2bc..92283f2a2 100644 --- a/SOURCES/Module.kabi_s390x +++ b/SOURCES/Module.kabi_s390x @@ -1563,163 +1563,6 @@ 0xb07058d1 mlx4_write_mtt drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL 0x130aa373 mlx4_xrcd_alloc drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL 0xe394b349 mlx4_xrcd_free drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL -0x23e2c280 mlx5_add_flow_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfe8c30c3 mlx5_alloc_bfreg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdf25b983 mlx5_blocking_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xec65ebb6 mlx5_blocking_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x026e7498 mlx5_cmd_add_privileged_uid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x0780275a mlx5_cmd_check drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf371e9b9 mlx5_cmd_cleanup_async_ctx drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9d9b55f1 mlx5_cmd_create_vport_lag drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6615d6cf mlx5_cmd_destroy_vport_lag drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf5dfee90 mlx5_cmd_do drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x468b5dc0 mlx5_cmd_exec drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x146dff49 mlx5_cmd_exec_cb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4d9dacd8 mlx5_cmd_init_async_ctx drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4c479bb3 mlx5_cmd_out_err drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf4ed926e mlx5_cmd_remove_privileged_uid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1fc60ea3 mlx5_comp_eqn_get drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6879484b mlx5_comp_vectors_max drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa4426337 mlx5_core_access_reg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x361421c7 mlx5_core_alloc_pd drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9f00095a mlx5_core_create_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xec69e160 mlx5_core_create_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb6708ff9 mlx5_core_create_psv drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xed057685 mlx5_core_create_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1b77962d mlx5_core_create_rqt drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf9fed668 mlx5_core_create_tis drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x024760ba mlx5_core_dealloc_pd drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x69dfce3f mlx5_core_destroy_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbd514239 mlx5_core_destroy_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x22123027 mlx5_core_destroy_psv drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2c1cc256 mlx5_core_modify_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2c07d0b2 mlx5_core_modify_cq_moderation drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x40edd8fd mlx5_core_modify_hca_vport_context drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x9bd42ac0 mlx5_core_modify_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5b3cd613 mlx5_core_modify_sq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x584c6e39 mlx5_core_modify_tis drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9ee2374d mlx5_core_mp_event_replay drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2ec76882 mlx5_core_query_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x85a7d8cb mlx5_core_query_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x256250dc mlx5_core_query_sq_state drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x09498dd0 mlx5_core_query_vendor_id drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3cc5aa29 mlx5_core_query_vport_counter drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xee179e34 mlx5_core_reserved_gids_count drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x6b63d322 mlx5_core_roce_gid_set drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x52891d91 mlx5_core_uplink_netdev_event_replay drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa9744a5e mlx5_create_auto_grouped_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbbdaea54 mlx5_create_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x101384cb mlx5_create_flow_group drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x593965e2 mlx5_create_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x75c7c44b mlx5_create_lag_demux_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x86ba557a mlx5_db_alloc_node drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xe08a7efa mlx5_db_free drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x1e945f73 mlx5_debug_qp_add drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x41107a0a mlx5_debug_qp_remove drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x962521b9 mlx5_debugfs_get_dev_root drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb00fb943 mlx5_debugfs_root drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd95055a7 mlx5_del_flow_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9010c06e mlx5_destroy_flow_group drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x911df19f mlx5_destroy_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x08404b3f mlx5_dm_sw_icm_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xfadf2ef8 mlx5_dm_sw_icm_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x60c1de7e mlx5_eq_create_generic drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x347a1e7c mlx5_eq_destroy_generic drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xaf1e8434 mlx5_eq_disable drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf9d72f18 mlx5_eq_enable drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x12b82305 mlx5_eq_get_eqe drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xedd8e8d7 mlx5_eq_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6f9b60a5 mlx5_eq_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xed93cf6e mlx5_eq_update_ci drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x147adb9b mlx5_eswitch_add_send_to_vport_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1155bb3f mlx5_eswitch_get_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x74b09a8e mlx5_eswitch_get_encap_mode drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x03a4bf81 mlx5_eswitch_get_proto_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc005f69b mlx5_eswitch_get_total_vports drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x4ecfbcda mlx5_eswitch_get_vport_metadata_for_match drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf2b34efe mlx5_eswitch_mode drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xf23065e3 mlx5_eswitch_register_vport_reps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9bbc0e5f mlx5_eswitch_unregister_vport_reps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9d72f7dc mlx5_eswitch_uplink_get_proto_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xaecde58a mlx5_eswitch_vport_match_metadata_enabled drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4a6dd09f mlx5_fc_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3f752250 mlx5_fc_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf1400f9a mlx5_fc_local_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd0c7964e mlx5_fc_local_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x31fe1c83 mlx5_fc_query drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x072460c4 mlx5_fill_page_frag_array drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x81aadc6a mlx5_fill_page_frag_array_perm drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x116d3d38 mlx5_flow_table_id drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe3c44ed8 mlx5_frag_buf_alloc_node drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xd1e337a3 mlx5_frag_buf_free drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x75d691db mlx5_free_bfreg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x69fb1001 mlx5_get_flow_namespace drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5dbd05dd mlx5_get_flow_vport_namespace drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9f904da5 mlx5_get_uars_page drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x927fd895 mlx5_is_roce_on drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa8ec5316 mlx5_lag_get_next_peer_mdev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xde018299 mlx5_lag_get_num_ports drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x16ab61de mlx5_lag_get_slave_port drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xccee9a22 mlx5_lag_is_active drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x29360443 mlx5_lag_is_master drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3e4d04d3 mlx5_lag_is_mpesw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x31fb9198 mlx5_lag_is_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x27947b64 mlx5_lag_is_shared_fdb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb007398e mlx5_lag_is_sriov drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x109b593d mlx5_lag_mode_is_hash drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbab77e9d mlx5_lag_query_cong_counters drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x64fade05 mlx5_macsec_add_roce_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x37897e7f mlx5_macsec_add_roce_sa_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x42b43a38 mlx5_macsec_del_roce_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x390b982c mlx5_macsec_del_roce_sa_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x053bcb81 mlx5_modify_header_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x94278bae mlx5_modify_header_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe484db6f mlx5_mpfs_add_mac drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf31038ce mlx5_mpfs_del_mac drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x17229e4e mlx5_nic_vport_affiliate_multiport drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3b8c3a15 mlx5_nic_vport_disable_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe98fc8b4 mlx5_nic_vport_enable_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x0a388ba2 mlx5_nic_vport_unaffiliate_multiport drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x6d351fea mlx5_nic_vport_update_local_lb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xc3735f72 mlx5_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa8ab6051 mlx5_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x83b3642b mlx5_packet_reformat_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x954b266a mlx5_packet_reformat_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x26cb0780 mlx5_put_uars_page drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdb0cef4d mlx5_qp_debugfs_cleanup drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb4de480d mlx5_qp_debugfs_init drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb4047218 mlx5_query_hca_vport_context drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xb2d0436c mlx5_query_hca_vport_gid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x39d04754 mlx5_query_hca_vport_node_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xa5763da7 mlx5_query_hca_vport_pkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x4e207674 mlx5_query_hca_vport_system_image_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xda028548 mlx5_query_ib_port_oper drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x73cb80bc mlx5_query_min_inline drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xc7492f79 mlx5_query_nic_vport_mac_address drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x0a073317 mlx5_query_nic_vport_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3b712b75 mlx5_query_nic_vport_node_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x5b6d083c mlx5_query_nic_vport_qkey_viol_cntr drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x9f6aa306 mlx5_query_nic_vport_system_image_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x8c4eece4 mlx5_query_port_max_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x0f449762 mlx5_query_port_oper_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x4aa00d9a mlx5_query_port_ptys drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xc3836b5e mlx5_query_port_vl_hw_cap drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x49d13634 mlx5_rdma_rn_get_params drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x05fa348a mlx5_rl_add_rate drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe56c41cb mlx5_rl_add_rate_raw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x61492bb7 mlx5_rl_are_equal drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdc76a730 mlx5_rl_remove_rate drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x52e94d40 mlx5_rl_remove_rate_raw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x76f90753 mlx5_rsc_dump_cmd_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xad6815cd mlx5_rsc_dump_cmd_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4be53b1f mlx5_rsc_dump_next drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x89a1683c mlx5_set_port_caps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xfb385f7c mlx5_sriov_blocking_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc589267e mlx5_sriov_blocking_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe280c64f mlx5_vf_get_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x7689dd6a mlx5_vf_put_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc0b8a38c mlx5_vport_get_other_func_cap drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xab6d5f71 mlx5_wc_support_get drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL 0x18143ee4 mlxfw_firmware_flash drivers/net/ethernet/mellanox/mlxfw/mlxfw EXPORT_SYMBOL 0xe16986dd mlxsw_afa_block_activity_get drivers/net/ethernet/mellanox/mlxsw/mlxsw_core EXPORT_SYMBOL 0xd28256cf mlxsw_afa_block_append_allocated_counter drivers/net/ethernet/mellanox/mlxsw/mlxsw_core EXPORT_SYMBOL diff --git a/SOURCES/Module.kabi_x86_64 b/SOURCES/Module.kabi_x86_64 index 06417aa6c..90b9478bf 100644 --- a/SOURCES/Module.kabi_x86_64 +++ b/SOURCES/Module.kabi_x86_64 @@ -1794,163 +1794,6 @@ 0x08ca0e05 mlx4_write_mtt drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL 0x6f264329 mlx4_xrcd_alloc drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL 0x4194430d mlx4_xrcd_free drivers/net/ethernet/mellanox/mlx4/mlx4_core EXPORT_SYMBOL_GPL -0x2566c076 mlx5_add_flow_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x42f0731a mlx5_alloc_bfreg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6f6f8492 mlx5_blocking_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6b419739 mlx5_blocking_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9132b1bc mlx5_cmd_add_privileged_uid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6621eaf8 mlx5_cmd_check drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9827e074 mlx5_cmd_cleanup_async_ctx drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe20daa8f mlx5_cmd_create_vport_lag drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1eb91ec9 mlx5_cmd_destroy_vport_lag drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1099c766 mlx5_cmd_do drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xeab65831 mlx5_cmd_exec drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x326e5ccb mlx5_cmd_exec_cb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3a7bce9a mlx5_cmd_init_async_ctx drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdf8eb63f mlx5_cmd_out_err drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x0d46c448 mlx5_cmd_remove_privileged_uid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x59e45e50 mlx5_comp_eqn_get drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x22ddec9b mlx5_comp_vectors_max drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x986aa1c6 mlx5_core_access_reg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x60f6ed60 mlx5_core_alloc_pd drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa0305b82 mlx5_core_create_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x9d73839d mlx5_core_create_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8ed891ac mlx5_core_create_psv drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x47dbc39e mlx5_core_create_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf10e815a mlx5_core_create_rqt drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xaefdfdf0 mlx5_core_create_tis drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x203756eb mlx5_core_dealloc_pd drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8c654697 mlx5_core_destroy_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfae29f13 mlx5_core_destroy_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x15fdbfd8 mlx5_core_destroy_psv drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe8dc6482 mlx5_core_modify_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa3f02ff1 mlx5_core_modify_cq_moderation drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x74d94947 mlx5_core_modify_hca_vport_context drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xf17f6df9 mlx5_core_modify_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbdf13bb6 mlx5_core_modify_sq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfd972858 mlx5_core_modify_tis drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2bf1b47e mlx5_core_mp_event_replay drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x723ed7e0 mlx5_core_query_mkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x60ee8151 mlx5_core_query_rq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xbab22823 mlx5_core_query_sq_state drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x24476ce0 mlx5_core_query_vendor_id drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x88a79244 mlx5_core_query_vport_counter drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3433b778 mlx5_core_reserved_gids_count drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x1d380c3c mlx5_core_roce_gid_set drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x774a7a45 mlx5_core_uplink_netdev_event_replay drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x721a42d6 mlx5_create_auto_grouped_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa2f61bad mlx5_create_cq drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb1a2c116 mlx5_create_flow_group drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc7387224 mlx5_create_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfe5e6db5 mlx5_create_lag_demux_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x41274e53 mlx5_db_alloc_node drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x98e03852 mlx5_db_free drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x37fc06fe mlx5_debug_qp_add drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1a9e7024 mlx5_debug_qp_remove drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x22bfb371 mlx5_debugfs_get_dev_root drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x76ab8b7f mlx5_debugfs_root drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x51a8a3a4 mlx5_del_flow_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x57b612e8 mlx5_destroy_flow_group drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdb9ff463 mlx5_destroy_flow_table drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x564e4980 mlx5_dm_sw_icm_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xedb136fa mlx5_dm_sw_icm_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xe5976f2a mlx5_eq_create_generic drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x417e1126 mlx5_eq_destroy_generic drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6bf52858 mlx5_eq_disable drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x426a616a mlx5_eq_enable drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb266177f mlx5_eq_get_eqe drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x842aa534 mlx5_eq_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdee6bcfa mlx5_eq_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x33c0b7d8 mlx5_eq_update_ci drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x74e18a55 mlx5_eswitch_add_send_to_vport_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x78c2a413 mlx5_eswitch_get_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5f55d2f2 mlx5_eswitch_get_encap_mode drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1181b93a mlx5_eswitch_get_proto_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc4f94b71 mlx5_eswitch_get_total_vports drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x045e4e46 mlx5_eswitch_get_vport_metadata_for_match drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8487d19a mlx5_eswitch_mode drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x1e38c8f0 mlx5_eswitch_register_vport_reps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5b6709b1 mlx5_eswitch_unregister_vport_reps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xdaa29c0c mlx5_eswitch_uplink_get_proto_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xba8643e4 mlx5_eswitch_vport_match_metadata_enabled drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1a4dd7a7 mlx5_fc_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x72ec0780 mlx5_fc_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8a7cd712 mlx5_fc_local_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x6030960f mlx5_fc_local_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x173d9f6d mlx5_fc_query drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x072460c4 mlx5_fill_page_frag_array drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x81aadc6a mlx5_fill_page_frag_array_perm drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x04e078a5 mlx5_flow_table_id drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x67a0fb24 mlx5_frag_buf_alloc_node drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xd8474598 mlx5_frag_buf_free drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x4176849a mlx5_free_bfreg drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc24034d8 mlx5_get_flow_namespace drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xf5d3b07b mlx5_get_flow_vport_namespace drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xeaa9f956 mlx5_get_uars_page drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5e52188e mlx5_is_roce_on drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x3ab38e7f mlx5_lag_get_next_peer_mdev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfbc40435 mlx5_lag_get_num_ports drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8d91db20 mlx5_lag_get_slave_port drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x625e66f2 mlx5_lag_is_active drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x62b35677 mlx5_lag_is_master drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xa81e9d2f mlx5_lag_is_mpesw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x54440b0f mlx5_lag_is_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xfcb61764 mlx5_lag_is_shared_fdb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xcc2693ce mlx5_lag_is_sriov drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4b337da8 mlx5_lag_mode_is_hash drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xaf038799 mlx5_lag_query_cong_counters drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x64fade05 mlx5_macsec_add_roce_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x37897e7f mlx5_macsec_add_roce_sa_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x42b43a38 mlx5_macsec_del_roce_rule drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x390b982c mlx5_macsec_del_roce_sa_rules drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x74aeba6e mlx5_modify_header_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc3cce4aa mlx5_modify_header_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x2216e9ce mlx5_mpfs_add_mac drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x8c466c5c mlx5_mpfs_del_mac drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x785ff1a2 mlx5_nic_vport_affiliate_multiport drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x26a3daf8 mlx5_nic_vport_disable_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x18f8aadf mlx5_nic_vport_enable_roce drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x934df90b mlx5_nic_vport_unaffiliate_multiport drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xd4460815 mlx5_nic_vport_update_local_lb drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3a64b9e1 mlx5_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x373ba416 mlx5_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe38c9c65 mlx5_packet_reformat_alloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x5b17166e mlx5_packet_reformat_dealloc drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x74f0c139 mlx5_put_uars_page drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x4728191d mlx5_qp_debugfs_cleanup drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x21a931f8 mlx5_qp_debugfs_init drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe74019b5 mlx5_query_hca_vport_context drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x317031e4 mlx5_query_hca_vport_gid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xd3105c51 mlx5_query_hca_vport_node_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x6301dd10 mlx5_query_hca_vport_pkey drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x10038586 mlx5_query_hca_vport_system_image_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x5d870b66 mlx5_query_ib_port_oper drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xc16a0028 mlx5_query_min_inline drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x8902a837 mlx5_query_nic_vport_mac_address drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x46616c23 mlx5_query_nic_vport_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xa30e5997 mlx5_query_nic_vport_node_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0xd2738080 mlx5_query_nic_vport_qkey_viol_cntr drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3efc67b5 mlx5_query_nic_vport_system_image_guid drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x3863725e mlx5_query_port_max_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x94b85d00 mlx5_query_port_oper_mtu drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x8ad7a2ce mlx5_query_port_ptys drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x23628c9c mlx5_query_port_vl_hw_cap drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x6fadae01 mlx5_rdma_rn_get_params drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x61485176 mlx5_rl_add_rate drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x75eec1f5 mlx5_rl_add_rate_raw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x61492bb7 mlx5_rl_are_equal drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xd3ce04c7 mlx5_rl_remove_rate drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x86f699d4 mlx5_rl_remove_rate_raw drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe13cab81 mlx5_rsc_dump_cmd_create drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xad6815cd mlx5_rsc_dump_cmd_destroy drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xe5dc58e3 mlx5_rsc_dump_next drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x37fd20ec mlx5_set_port_caps drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x5d79a2ee mlx5_sriov_blocking_notifier_register drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x932b78cb mlx5_sriov_blocking_notifier_unregister drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0xb683dc7b mlx5_vf_get_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x23998fae mlx5_vf_put_core_dev drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL -0x1b5d1bbf mlx5_vport_get_other_func_cap drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL_GPL -0x8c7b83e5 mlx5_wc_support_get drivers/net/ethernet/mellanox/mlx5/core/mlx5_core EXPORT_SYMBOL 0x1d434f3f mlxfw_firmware_flash drivers/net/ethernet/mellanox/mlxfw/mlxfw EXPORT_SYMBOL 0xe16986dd mlxsw_afa_block_activity_get drivers/net/ethernet/mellanox/mlxsw/mlxsw_core EXPORT_SYMBOL 0xd28256cf mlxsw_afa_block_append_allocated_counter drivers/net/ethernet/mellanox/mlxsw/mlxsw_core EXPORT_SYMBOL diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec index a4ee22b0d..06f642988 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec @@ -176,13 +176,13 @@ Summary: The Linux kernel # define buildid .local %define specversion 5.14.0 %define patchversion 5.14 -%define pkgrelease 687.13.1 +%define pkgrelease 687.15.1 %define kversion 5 %define tarfile_release 5.14.0-687.5.1.el9_8 # This is needed to do merge window version magic %define patchlevel 14 # This allows pkg_release to have configurable %%{?dist} tag -%define specrelease 687.13.1%{?buildid}%{?dist} +%define specrelease 687.15.1%{?buildid}%{?dist} # This defines the kabi tarball version %define kabiversion 5.14.0-687.5.1.el9_8 @@ -1147,6 +1147,21 @@ Patch1266: 1266-nvme-nvme-fc-ensure-ioerr-work-is-cancelled-in-nvme-fc-delet.pat Patch1267: 1267-s390-dasd-fix-gendisk-parent-after-copy-pair-swap.patch Patch1268: 1268-s390-dasd-move-quiesce-state-with-pprc-swap.patch Patch1269: 1269-s390-dasd-copy-detected-format-information-to-secondary-devi.patch +Patch1270: 1270-x86-kvm-avoid-freeing-stack-allocated-node-in-kvm-async-pf-q.patch +Patch1271: 1271-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch +Patch1272: 1272-scsi-target-iscsi-fix-use-after-free-in-iscsit-dec-conn-usag.patch +Patch1273: 1273-net-mana-fix-use-after-free-in-add-adev-error-path.patch +Patch1274: 1274-alsa-6fire-fix-use-after-free-on-disconnect.patch +Patch1275: 1275-dlm-validate-length-in-dlm-search-rsb-tree.patch +Patch1276: 1276-dlm-fix-buffer-overflow-from-negative-len-in-dlm-search-rsb-.patch +Patch1277: 1277-netfilter-ctnetlink-ensure-safe-access-to-master-conntrack.patch +Patch1278: 1278-rdma-rxe-fix-double-free-in-rxe-srq-from-init.patch +Patch1279: 1279-net-openvswitch-avoid-releasing-netdev-before-teardown-compl.patch +Patch1280: 1280-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch +Patch1281: 1281-ipv6-rpl-headroom.patch +Patch1282: 1282-rdma-mlx4-srq.patch +Patch1283: 1283-dpll-series-RHEL.patch +Patch1284: 1284-ice-rss-queues-RHEL.patch # END OF PATCH DEFINITIONS %description @@ -2061,6 +2076,21 @@ ApplyPatch 1266-nvme-nvme-fc-ensure-ioerr-work-is-cancelled-in-nvme-fc-delet.pat ApplyPatch 1267-s390-dasd-fix-gendisk-parent-after-copy-pair-swap.patch ApplyPatch 1268-s390-dasd-move-quiesce-state-with-pprc-swap.patch ApplyPatch 1269-s390-dasd-copy-detected-format-information-to-secondary-devi.patch +ApplyPatch 1270-x86-kvm-avoid-freeing-stack-allocated-node-in-kvm-async-pf-q.patch +ApplyPatch 1271-net-bonding-fix-use-after-free-in-bond-xmit-broadcast.patch +ApplyPatch 1272-scsi-target-iscsi-fix-use-after-free-in-iscsit-dec-conn-usag.patch +ApplyPatch 1273-net-mana-fix-use-after-free-in-add-adev-error-path.patch +ApplyPatch 1274-alsa-6fire-fix-use-after-free-on-disconnect.patch +ApplyPatch 1275-dlm-validate-length-in-dlm-search-rsb-tree.patch +ApplyPatch 1276-dlm-fix-buffer-overflow-from-negative-len-in-dlm-search-rsb-.patch +ApplyPatch 1277-netfilter-ctnetlink-ensure-safe-access-to-master-conntrack.patch +ApplyPatch 1278-rdma-rxe-fix-double-free-in-rxe-srq-from-init.patch +ApplyPatch 1279-net-openvswitch-avoid-releasing-netdev-before-teardown-compl.patch +ApplyPatch 1280-ip6-tunnel-clear-skb2-cb-in-ip4ip6-err.patch +ApplyPatch 1281-ipv6-rpl-headroom.patch +ApplyPatch 1282-rdma-mlx4-srq.patch +ApplyPatch 1283-dpll-series-RHEL.patch +ApplyPatch 1284-ice-rss-queues-RHEL.patch # END OF PATCH APPLICATIONS # Any further pre-build tree manipulations happen here. @@ -4135,6 +4165,49 @@ fi # # %changelog +* Wed Jun 11 2026 Andrew Lukoshko - 5.14.0-687.15.1 +- Recreate RHEL 5.14.0-687.15.1 from CentOS Stream 9 and upstream stable backports (1270-1284) +- redhat: Remove the mlx5 symbols from kabi: applied via updated Module.kabi_{aarch64,s390x,x86_64} (RHEL-181822) +- dpll/zl3073x and ice RSS-queue series consolidated (include RHEL kABI / RHEL-only files) +- RHEL changelog for 687.14.1..687.15.1 follows: + +* Wed Jun 10 2026 CKI KWF Bot [5.14.0-687.15.1.el9_8] +- ip6_tunnel: clear skb2->cb[] in ip4ip6_err() (Guillaume Nault) [RHEL-172646] {CVE-2026-43037} +- net: openvswitch: Avoid releasing netdev before teardown completes (CKI Backport Bot) [RHEL-170539] {CVE-2026-31508} + +* Tue Jun 09 2026 Tanishi Srivastava [5.14.0-687.14.1.el9_8] +- RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event() (Kamal Heib) [RHEL-179988] {CVE-2026-46181} +- redhat: Remove the mlx5 symbols from kabi (Kamal Heib) [RHEL-181822] +- ipv6: rpl: reserve mac_len headroom when recompressed SRH grows (Antoine Tenart) [RHEL-178408] {CVE-2026-43501} +- RDMA/rxe: Fix double free in rxe_srq_from_init (CKI Backport Bot) [RHEL-179712] {CVE-2026-45852} +- netfilter: ctnetlink: ensure safe access to master conntrack (Florian Westphal) [RHEL-173843] {CVE-2026-43116} +- ice: fix stats array overflow when VF requests more queues (Michal Schmidt) [RHEL-177526] +- ice: set max queues in alloc_etherdev_mqs() (Michal Schmidt) [RHEL-174336] +- ice: use netif_get_num_default_rss_queues() (Michal Schmidt) [RHEL-174336] +- ice: set default rss queues num to physical cores / 2 (Michal Schmidt) [RHEL-174336] +- dlm: fix buffer overflow from negative len in dlm_search_rsb_tree (Alexander Aring) [RHEL-173993] {CVE-2026-43125} +- dlm: validate length in dlm_search_rsb_tree (Alexander Aring) [RHEL-173993] {CVE-2026-43125} +- dpll: zl3073x: add ref-sync pair support (Ivan Vecera) [RHEL-167273] +- dpll: zl3073x: add ref sync and output clock type helpers (Ivan Vecera) [RHEL-167273] +- dpll: zl3073x: use FIELD_MODIFY() for clear-and-set patterns (Ivan Vecera) [RHEL-167273] +- dpll: zl3073x: clean up esync get/set and use zl3073x_out_is_ndiv() (Ivan Vecera) [RHEL-167273] +- dpll: zl3073x: implement frequency monitoring (Ivan Vecera) [RHEL-167833] +- dpll: add frequency monitoring callback ops (Ivan Vecera) [RHEL-167833] +- dpll: add frequency monitoring to netlink spec (Ivan Vecera) [RHEL-167833] +- dpll: zl3073x: drop selected and simplify connected ref getter (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: add reference priority to zl3073x_chan (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: add DPLL channel status fields to zl3073x_chan (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: introduce zl3073x_chan for DPLL channel state (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: add zl3073x_ref_state_update helper (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: use struct_group to partition states (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: add die temperature reporting for supported chips (Ivan Vecera) [RHEL-172938] +- dpll: zl3073x: detect DPLL channel count from chip ID at runtime (Ivan Vecera) [RHEL-172938] +- ALSA: 6fire: fix use-after-free on disconnect (CKI Backport Bot) [RHEL-172969] {CVE-2026-31581} +- net: mana: fix use-after-free in add_adev() error path (CKI Backport Bot) [RHEL-172768] {CVE-2026-43056} +- scsi: target: iscsi: Fix use-after-free in iscsit_dec_conn_usage_count() (CKI Backport Bot) [RHEL-165564] {CVE-2026-23216} +- net: bonding: fix use-after-free in bond_xmit_broadcast() (CKI Backport Bot) [RHEL-168068] {CVE-2026-31419} +- x86/kvm: Avoid freeing stack-allocated node in kvm_async_pf_queue_task (Ryosuke Yasuoka) [RHEL-158916] + * Wed Jun 11 2026 Andrew Lukoshko - 5.14.0-687.13.1 - Recreate RHEL 5.14.0-687.13.1 from CentOS Stream 9 and upstream stable backports (1253-1269) - RHEL changelog for 687.13.1 follows: