]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.6
authorSasha Levin <sashal@kernel.org>
Mon, 9 Dec 2024 11:18:29 +0000 (06:18 -0500)
committerSasha Levin <sashal@kernel.org>
Mon, 9 Dec 2024 11:18:29 +0000 (06:18 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
121 files changed:
queue-6.6/can-c_can-c_can_handle_bus_err-update-statistics-if-.patch [new file with mode: 0644]
queue-6.6/can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch [new file with mode: 0644]
queue-6.6/can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch [new file with mode: 0644]
queue-6.6/can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch [new file with mode: 0644]
queue-6.6/can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch [new file with mode: 0644]
queue-6.6/can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch [new file with mode: 0644]
queue-6.6/can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch [new file with mode: 0644]
queue-6.6/can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch [new file with mode: 0644]
queue-6.6/can-j1939-j1939_session_new-fix-skb-reference-counti.patch [new file with mode: 0644]
queue-6.6/can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch [new file with mode: 0644]
queue-6.6/can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch [new file with mode: 0644]
queue-6.6/can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch [new file with mode: 0644]
queue-6.6/can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch [new file with mode: 0644]
queue-6.6/dccp-fix-memory-leak-in-dccp_feat_change_recv.patch [new file with mode: 0644]
queue-6.6/driver-core-add-fwlink_flag_ignore-to-completely-ign.patch [new file with mode: 0644]
queue-6.6/driver-core-fw_devlink-improve-logs-for-cycle-detect.patch [new file with mode: 0644]
queue-6.6/driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch [new file with mode: 0644]
queue-6.6/drm-bridge-it6505-fix-inverted-reset-polarity.patch [new file with mode: 0644]
queue-6.6/drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch [new file with mode: 0644]
queue-6.6/ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch [new file with mode: 0644]
queue-6.6/f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch [new file with mode: 0644]
queue-6.6/geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch [new file with mode: 0644]
queue-6.6/gpio-grgpio-add-null-check-in-grgpio_probe.patch [new file with mode: 0644]
queue-6.6/gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch [new file with mode: 0644]
queue-6.6/i3c-master-add-enable-disable-hot-join-in-sys-entry.patch [new file with mode: 0644]
queue-6.6/i3c-master-extend-address-status-bit-to-4-and-add-i3.patch [new file with mode: 0644]
queue-6.6/i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch [new file with mode: 0644]
queue-6.6/i3c-master-fix-kernel-doc-check-warning.patch [new file with mode: 0644]
queue-6.6/i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch [new file with mode: 0644]
queue-6.6/i3c-master-support-to-adjust-first-broadcast-address.patch [new file with mode: 0644]
queue-6.6/i3c-master-svc-add-hot-join-support.patch [new file with mode: 0644]
queue-6.6/i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch [new file with mode: 0644]
queue-6.6/i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch [new file with mode: 0644]
queue-6.6/igb-fix-potential-invalid-memory-access-in-igb_init_.patch [new file with mode: 0644]
queue-6.6/iommu-add-iommu_ops-identity_domain.patch [new file with mode: 0644]
queue-6.6/iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch [new file with mode: 0644]
queue-6.6/iommu-clean-up-open-coded-ownership-checks.patch [new file with mode: 0644]
queue-6.6/iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch [new file with mode: 0644]
queue-6.6/ipv6-introduce-dst_rt6_info-helper.patch [new file with mode: 0644]
queue-6.6/ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch [new file with mode: 0644]
queue-6.6/itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch [new file with mode: 0644]
queue-6.6/ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch [new file with mode: 0644]
queue-6.6/ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch [new file with mode: 0644]
queue-6.6/kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch [new file with mode: 0644]
queue-6.6/kvm-arm64-don-t-retire-aborted-mmio-instruction.patch [new file with mode: 0644]
queue-6.6/mlxsw-add-ipv4_5-flex-key.patch [new file with mode: 0644]
queue-6.6/mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch [new file with mode: 0644]
queue-6.6/mlxsw-mark-high-entropy-key-blocks.patch [new file with mode: 0644]
queue-6.6/mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch [new file with mode: 0644]
queue-6.6/mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch [new file with mode: 0644]
queue-6.6/mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch [new file with mode: 0644]
queue-6.6/mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch [new file with mode: 0644]
queue-6.6/mmc-mtk-sd-fix-error-handle-of-probe-function.patch [new file with mode: 0644]
queue-6.6/mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch [new file with mode: 0644]
queue-6.6/mmc-mtk-sd-use-devm_mmc_alloc_host.patch [new file with mode: 0644]
queue-6.6/net-avoid-potential-uaf-in-default_operstate.patch [new file with mode: 0644]
queue-6.6/net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch [new file with mode: 0644]
queue-6.6/net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch [new file with mode: 0644]
queue-6.6/net-ipv6-release-expired-exception-dst-cached-in-soc.patch [new file with mode: 0644]
queue-6.6/net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch [new file with mode: 0644]
queue-6.6/net-qed-allow-old-cards-not-supporting-num_images-to.patch [new file with mode: 0644]
queue-6.6/net-sched-fix-erspan_opt-settings-in-cls_flower.patch [new file with mode: 0644]
queue-6.6/net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch [new file with mode: 0644]
queue-6.6/net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch [new file with mode: 0644]
queue-6.6/net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch [new file with mode: 0644]
queue-6.6/net-smc-compatible-with-128-bits-extended-gid-of-vir.patch [new file with mode: 0644]
queue-6.6/net-smc-define-a-reserved-chid-range-for-virtual-ism.patch [new file with mode: 0644]
queue-6.6/net-smc-fix-lgr-and-link-use-after-free-issue.patch [new file with mode: 0644]
queue-6.6/net-smc-initialize-close_work-early-to-avoid-warning.patch [new file with mode: 0644]
queue-6.6/net-smc-introduce-sub-functions-for-smc_clc_send_con.patch [new file with mode: 0644]
queue-6.6/net-smc-mark-optional-smcd_ops-and-check-for-support.patch [new file with mode: 0644]
queue-6.6/net-smc-refactoring-initialization-of-smc-sock.patch [new file with mode: 0644]
queue-6.6/net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch [new file with mode: 0644]
queue-6.6/net-smc-unify-the-structs-of-accept-or-confirm-messa.patch [new file with mode: 0644]
queue-6.6/net-timestamp-make-sk_tskey-more-predictable-in-erro.patch [new file with mode: 0644]
queue-6.6/netfilter-ipset-hold-module-reference-while-requesti.patch [new file with mode: 0644]
queue-6.6/netfilter-nft_inner-incorrect-percpu-area-handling-u.patch [new file with mode: 0644]
queue-6.6/netfilter-nft_set_hash-skip-duplicated-elements-pend.patch [new file with mode: 0644]
queue-6.6/netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch [new file with mode: 0644]
queue-6.6/netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch [new file with mode: 0644]
queue-6.6/ntp-clean-up-comments.patch [new file with mode: 0644]
queue-6.6/ntp-cleanup-formatting-of-code.patch [new file with mode: 0644]
queue-6.6/ntp-convert-functions-with-only-two-states-to-bool.patch [new file with mode: 0644]
queue-6.6/ntp-introduce-struct-ntp_data.patch [new file with mode: 0644]
queue-6.6/ntp-make-tick_usec-static.patch [new file with mode: 0644]
queue-6.6/ntp-move-tick_length-into-ntp_data.patch [new file with mode: 0644]
queue-6.6/ntp-move-tick_stat-into-ntp_data.patch [new file with mode: 0644]
queue-6.6/ntp-read-reference-time-only-once.patch [new file with mode: 0644]
queue-6.6/ntp-remove-invalid-cast-in-time-offset-math.patch [new file with mode: 0644]
queue-6.6/ntp-remove-unused-tick_nsec.patch [new file with mode: 0644]
queue-6.6/platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch [new file with mode: 0644]
queue-6.6/platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch [new file with mode: 0644]
queue-6.6/platform-x86-asus-wmi-ignore-return-value-when-writi.patch [new file with mode: 0644]
queue-6.6/powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch [new file with mode: 0644]
queue-6.6/powerpc-vdso-refactor-cflags-for-cvdso-build.patch [new file with mode: 0644]
queue-6.6/ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch [new file with mode: 0644]
queue-6.6/selftests-hid-fix-typo-and-exit-code.patch [new file with mode: 0644]
queue-6.6/serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch [new file with mode: 0644]
queue-6.6/serial-amba-pl011-use-port-lock-wrappers.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch [new file with mode: 0644]
queue-6.6/soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch [new file with mode: 0644]
queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch [new file with mode: 0644]
queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch [new file with mode: 0644]
queue-6.6/soc-fsl-cpm1-qmc-re-order-probe-operations.patch [new file with mode: 0644]
queue-6.6/soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch [new file with mode: 0644]
queue-6.6/tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch [new file with mode: 0644]
queue-6.6/usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch [new file with mode: 0644]
queue-6.6/usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch [new file with mode: 0644]
queue-6.6/usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch [new file with mode: 0644]
queue-6.6/watchdog-apple-actually-flush-writes-after-requestin.patch [new file with mode: 0644]
queue-6.6/watchdog-mediatek-make-sure-system-reset-gets-assert.patch [new file with mode: 0644]
queue-6.6/watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch [new file with mode: 0644]
queue-6.6/xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch [new file with mode: 0644]
queue-6.6/xhci-combine-two-if-statements-for-etron-xhci-host.patch [new file with mode: 0644]
queue-6.6/xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch [new file with mode: 0644]
queue-6.6/xhci-fix-control-transfer-error-on-etron-xhci-host.patch [new file with mode: 0644]
queue-6.6/xhci-remove-xhci_trust_tx_length-quirk.patch [new file with mode: 0644]
queue-6.6/zram-clear-idle-flag-in-mark_idle.patch [new file with mode: 0644]
queue-6.6/zram-do-not-mark-idle-slots-that-cannot-be-idle.patch [new file with mode: 0644]
queue-6.6/zram-split-memory-tracking-and-ac-time-tracking.patch [new file with mode: 0644]

diff --git a/queue-6.6/can-c_can-c_can_handle_bus_err-update-statistics-if-.patch b/queue-6.6/can-c_can-c_can_handle_bus_err-update-statistics-if-.patch
new file mode 100644 (file)
index 0000000..45f1df1
--- /dev/null
@@ -0,0 +1,96 @@
+From 03881dba95f32762f86a058a5c864b27e34427fd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:42 +0100
+Subject: can: c_can: c_can_handle_bus_err(): update statistics if skb
+ allocation fails
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 9e66242504f49e17481d8e197730faba7d99c934 ]
+
+Ensure that the statistics are always updated, even if the skb
+allocation fails.
+
+Fixes: 4d6d26537940 ("can: c_can: fix {rx,tx}_errors statistics")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-2-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/c_can/c_can_main.c | 26 +++++++++++++++++---------
+ 1 file changed, 17 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c
+index 511615dc33419..cc371d0c9f3c7 100644
+--- a/drivers/net/can/c_can/c_can_main.c
++++ b/drivers/net/can/c_can/c_can_main.c
+@@ -1014,49 +1014,57 @@ static int c_can_handle_bus_err(struct net_device *dev,
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(dev, &cf);
+-      if (unlikely(!skb))
+-              return 0;
+       /* check for 'last error code' which tells us the
+        * type of the last error to occur on the CAN bus
+        */
+-      cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
++      if (likely(skb))
++              cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+       switch (lec_type) {
+       case LEC_STUFF_ERROR:
+               netdev_dbg(dev, "stuff error\n");
+-              cf->data[2] |= CAN_ERR_PROT_STUFF;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_STUFF;
+               stats->rx_errors++;
+               break;
+       case LEC_FORM_ERROR:
+               netdev_dbg(dev, "form error\n");
+-              cf->data[2] |= CAN_ERR_PROT_FORM;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_FORM;
+               stats->rx_errors++;
+               break;
+       case LEC_ACK_ERROR:
+               netdev_dbg(dev, "ack error\n");
+-              cf->data[3] = CAN_ERR_PROT_LOC_ACK;
++              if (likely(skb))
++                      cf->data[3] = CAN_ERR_PROT_LOC_ACK;
+               stats->tx_errors++;
+               break;
+       case LEC_BIT1_ERROR:
+               netdev_dbg(dev, "bit1 error\n");
+-              cf->data[2] |= CAN_ERR_PROT_BIT1;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_BIT1;
+               stats->tx_errors++;
+               break;
+       case LEC_BIT0_ERROR:
+               netdev_dbg(dev, "bit0 error\n");
+-              cf->data[2] |= CAN_ERR_PROT_BIT0;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_BIT0;
+               stats->tx_errors++;
+               break;
+       case LEC_CRC_ERROR:
+               netdev_dbg(dev, "CRC error\n");
+-              cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
++              if (likely(skb))
++                      cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+               stats->rx_errors++;
+               break;
+       default:
+               break;
+       }
++      if (unlikely(!skb))
++              return 0;
++
+       netif_receive_skb(skb);
+       return 1;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch b/queue-6.6/can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch
new file mode 100644 (file)
index 0000000..6d779bc
--- /dev/null
@@ -0,0 +1,126 @@
+From 26ce242f03658fecc4c03ffefbc9fcb06a19c781 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:52 +0100
+Subject: can: ems_usb: ems_usb_rx_err(): fix {rx,tx}_errors statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 72a7e2e74b3075959f05e622bae09b115957dffe ]
+
+The ems_usb_rx_err() function only incremented the receive error counter
+and never the transmit error counter, even if the ECC_DIR flag reported
+that an error had occurred during transmission.
+
+Increment the receive/transmit error counter based on the value of the
+ECC_DIR flag.
+
+Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-12-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/usb/ems_usb.c | 58 ++++++++++++++++++++---------------
+ 1 file changed, 33 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
+index 050c0b49938a4..5355bac4dccbe 100644
+--- a/drivers/net/can/usb/ems_usb.c
++++ b/drivers/net/can/usb/ems_usb.c
+@@ -335,15 +335,14 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
+       struct net_device_stats *stats = &dev->netdev->stats;
+       skb = alloc_can_err_skb(dev->netdev, &cf);
+-      if (skb == NULL)
+-              return;
+       if (msg->type == CPC_MSG_TYPE_CAN_STATE) {
+               u8 state = msg->msg.can_state;
+               if (state & SJA1000_SR_BS) {
+                       dev->can.state = CAN_STATE_BUS_OFF;
+-                      cf->can_id |= CAN_ERR_BUSOFF;
++                      if (skb)
++                              cf->can_id |= CAN_ERR_BUSOFF;
+                       dev->can.can_stats.bus_off++;
+                       can_bus_off(dev->netdev);
+@@ -361,44 +360,53 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
+               /* bus error interrupt */
+               dev->can.can_stats.bus_error++;
+-              stats->rx_errors++;
+-              cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
++              if (skb) {
++                      cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+-              switch (ecc & SJA1000_ECC_MASK) {
+-              case SJA1000_ECC_BIT:
+-                      cf->data[2] |= CAN_ERR_PROT_BIT;
+-                      break;
+-              case SJA1000_ECC_FORM:
+-                      cf->data[2] |= CAN_ERR_PROT_FORM;
+-                      break;
+-              case SJA1000_ECC_STUFF:
+-                      cf->data[2] |= CAN_ERR_PROT_STUFF;
+-                      break;
+-              default:
+-                      cf->data[3] = ecc & SJA1000_ECC_SEG;
+-                      break;
++                      switch (ecc & SJA1000_ECC_MASK) {
++                      case SJA1000_ECC_BIT:
++                              cf->data[2] |= CAN_ERR_PROT_BIT;
++                              break;
++                      case SJA1000_ECC_FORM:
++                              cf->data[2] |= CAN_ERR_PROT_FORM;
++                              break;
++                      case SJA1000_ECC_STUFF:
++                              cf->data[2] |= CAN_ERR_PROT_STUFF;
++                              break;
++                      default:
++                              cf->data[3] = ecc & SJA1000_ECC_SEG;
++                              break;
++                      }
+               }
+               /* Error occurred during transmission? */
+-              if ((ecc & SJA1000_ECC_DIR) == 0)
+-                      cf->data[2] |= CAN_ERR_PROT_TX;
++              if ((ecc & SJA1000_ECC_DIR) == 0) {
++                      stats->tx_errors++;
++                      if (skb)
++                              cf->data[2] |= CAN_ERR_PROT_TX;
++              } else {
++                      stats->rx_errors++;
++              }
+-              if (dev->can.state == CAN_STATE_ERROR_WARNING ||
+-                  dev->can.state == CAN_STATE_ERROR_PASSIVE) {
++              if (skb && (dev->can.state == CAN_STATE_ERROR_WARNING ||
++                          dev->can.state == CAN_STATE_ERROR_PASSIVE)) {
+                       cf->can_id |= CAN_ERR_CRTL;
+                       cf->data[1] = (txerr > rxerr) ?
+                           CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE;
+               }
+       } else if (msg->type == CPC_MSG_TYPE_OVERRUN) {
+-              cf->can_id |= CAN_ERR_CRTL;
+-              cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
++              if (skb) {
++                      cf->can_id |= CAN_ERR_CRTL;
++                      cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
++              }
+               stats->rx_over_errors++;
+               stats->rx_errors++;
+       }
+-      netif_rx(skb);
++      if (skb)
++              netif_rx(skb);
+ }
+ /*
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch b/queue-6.6/can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch
new file mode 100644 (file)
index 0000000..0beef83
--- /dev/null
@@ -0,0 +1,59 @@
+From 79c18bbd3f10adf36c9e01319d04567db36b2481 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:53 +0100
+Subject: can: f81604: f81604_handle_can_bus_errors(): fix {rx,tx}_errors
+ statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit d7b916540c2ba3d2a88c27b2a6287b39d8eac052 ]
+
+The f81604_handle_can_bus_errors() function only incremented the receive
+error counter and never the transmit error counter, even if the ECC_DIR
+flag reported that an error had occurred during transmission.
+
+Increment the receive/transmit error counter based on the value of the
+ECC_DIR flag.
+
+Fixes: 88da17436973 ("can: usb: f81604: add Fintek F81604 support")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-13-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/usb/f81604.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
+index ec8cef7fd2d53..fb9fb16507f0b 100644
+--- a/drivers/net/can/usb/f81604.c
++++ b/drivers/net/can/usb/f81604.c
+@@ -526,7 +526,6 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv,
+               netdev_dbg(netdev, "bus error interrupt\n");
+               priv->can.can_stats.bus_error++;
+-              stats->rx_errors++;
+               if (skb) {
+                       cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+@@ -548,10 +547,15 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv,
+                       /* set error location */
+                       cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG;
++              }
+-                      /* Error occurred during transmission? */
+-                      if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0)
++              /* Error occurred during transmission? */
++              if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) {
++                      stats->tx_errors++;
++                      if (skb)
+                               cf->data[2] |= CAN_ERR_PROT_TX;
++              } else {
++                      stats->rx_errors++;
+               }
+               set_bit(F81604_CLEAR_ECC, &priv->clear_flags);
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch b/queue-6.6/can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch
new file mode 100644 (file)
index 0000000..e30e42d
--- /dev/null
@@ -0,0 +1,138 @@
+From ced30bbf6aa465629eccf76344bbd345e73e9df9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 18 Oct 2024 23:24:26 +0200
+Subject: can: gs_usb: add usb endpoint address detection at driver probe step
+
+From: Alexander Kozhinov <ak.alexander.kozhinov@gmail.com>
+
+[ Upstream commit 889b2ae9139a87b3390f7003cb1bb3d65bf90a26 ]
+
+There is an approach made to implement gs_usb firmware/driver based on
+Zephyr RTOS. It was found that USB stack of Zephyr RTOS overwrites USB
+EP addresses, if they have different last 4 bytes in absence of other
+endpoints.
+
+For example in case of gs_usb candlelight firmware EP-IN is 0x81 and
+EP-OUT 0x02. If there are no additional USB endpoints, Zephyr RTOS will
+overwrite EP-OUT to 0x01. More information can be found in the
+discussion with Zephyr RTOS USB stack maintainer here:
+
+https://github.com/zephyrproject-rtos/zephyr/issues/67812
+
+There are already two different gs_usb FW driver implementations based
+on Zephyr RTOS:
+
+1. https://github.com/CANnectivity/cannectivity
+   (by: https://github.com/henrikbrixandersen)
+2. https://github.com/zephyrproject-rtos/zephyr/compare/main...KozhinovAlexander:zephyr:gs_usb
+   (by: https://github.com/KozhinovAlexander)
+
+At the moment both Zephyr RTOS implementations use dummy USB endpoint,
+to overcome described USB stack behavior from Zephyr itself. Since
+Zephyr RTOS is intended to be used on microcontrollers with very
+constrained amount of resources (ROM, RAM) and additional endpoint
+requires memory, it is more convenient to update the gs_usb driver in
+the Linux kernel.
+
+To fix this problem, update the gs_usb driver from using hard coded
+endpoint numbers to evaluate the endpoint descriptors and use the
+endpoints provided there.
+
+Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices")
+Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
+Signed-off-by: Alexander Kozhinov <ak.alexander.kozhinov@gmail.com>
+Link: https://patch.msgid.link/20241018212450.31746-1-ak.alexander.kozhinov@gmail.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/usb/gs_usb.c | 25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
+index ed59451f03cdd..de616d6589c0b 100644
+--- a/drivers/net/can/usb/gs_usb.c
++++ b/drivers/net/can/usb/gs_usb.c
+@@ -43,9 +43,6 @@
+ #define USB_XYLANTA_SAINT3_VENDOR_ID 0x16d0
+ #define USB_XYLANTA_SAINT3_PRODUCT_ID 0x0f30
+-#define GS_USB_ENDPOINT_IN 1
+-#define GS_USB_ENDPOINT_OUT 2
+-
+ /* Timestamp 32 bit timer runs at 1 MHz (1 µs tick). Worker accounts
+  * for timer overflow (will be after ~71 minutes)
+  */
+@@ -336,6 +333,9 @@ struct gs_usb {
+       unsigned int hf_size_rx;
+       u8 active_channels;
++
++      unsigned int pipe_in;
++      unsigned int pipe_out;
+ };
+ /* 'allocate' a tx context.
+@@ -687,7 +687,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
+ resubmit_urb:
+       usb_fill_bulk_urb(urb, parent->udev,
+-                        usb_rcvbulkpipe(parent->udev, GS_USB_ENDPOINT_IN),
++                        parent->pipe_in,
+                         hf, dev->parent->hf_size_rx,
+                         gs_usb_receive_bulk_callback, parent);
+@@ -819,7 +819,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
+       }
+       usb_fill_bulk_urb(urb, dev->udev,
+-                        usb_sndbulkpipe(dev->udev, GS_USB_ENDPOINT_OUT),
++                        dev->parent->pipe_out,
+                         hf, dev->hf_size_tx,
+                         gs_usb_xmit_callback, txc);
+@@ -925,8 +925,7 @@ static int gs_can_open(struct net_device *netdev)
+                       /* fill, anchor, and submit rx urb */
+                       usb_fill_bulk_urb(urb,
+                                         dev->udev,
+-                                        usb_rcvbulkpipe(dev->udev,
+-                                                        GS_USB_ENDPOINT_IN),
++                                        dev->parent->pipe_in,
+                                         buf,
+                                         dev->parent->hf_size_rx,
+                                         gs_usb_receive_bulk_callback, parent);
+@@ -1413,6 +1412,7 @@ static int gs_usb_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+ {
+       struct usb_device *udev = interface_to_usbdev(intf);
++      struct usb_endpoint_descriptor *ep_in, *ep_out;
+       struct gs_host_frame *hf;
+       struct gs_usb *parent;
+       struct gs_host_config hconf = {
+@@ -1422,6 +1422,13 @@ static int gs_usb_probe(struct usb_interface *intf,
+       unsigned int icount, i;
+       int rc;
++      rc = usb_find_common_endpoints(intf->cur_altsetting,
++                                     &ep_in, &ep_out, NULL, NULL);
++      if (rc) {
++              dev_err(&intf->dev, "Required endpoints not found\n");
++              return rc;
++      }
++
+       /* send host config */
+       rc = usb_control_msg_send(udev, 0,
+                                 GS_USB_BREQ_HOST_FORMAT,
+@@ -1466,6 +1473,10 @@ static int gs_usb_probe(struct usb_interface *intf,
+       usb_set_intfdata(intf, parent);
+       parent->udev = udev;
++      /* store the detected endpoints */
++      parent->pipe_in = usb_rcvbulkpipe(parent->udev, ep_in->bEndpointAddress);
++      parent->pipe_out = usb_sndbulkpipe(parent->udev, ep_out->bEndpointAddress);
++
+       for (i = 0; i < icount; i++) {
+               unsigned int hf_size_rx = 0;
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch b/queue-6.6/can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch
new file mode 100644 (file)
index 0000000..4bb01af
--- /dev/null
@@ -0,0 +1,48 @@
+From c6584ec49db0d12f88974454e13041b9968a1c06 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Jun 2024 16:03:52 +0200
+Subject: can: gs_usb: add VID/PID for Xylanta SAINT3 product family
+
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+
+[ Upstream commit 69e2326a21ef409d6c709cb990565331727b9f27 ]
+
+Add support for the Xylanta SAINT3 product family.
+
+Cc: Andy Jackson <andy@xylanta.com>
+Cc: Ken Aitchison <ken@xylanta.com>
+Tested-by: Andy Jackson <andy@xylanta.com>
+Link: https://lore.kernel.org/all/20240625140353.769373-1-mkl@pengutronix.de
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Stable-dep-of: 889b2ae9139a ("can: gs_usb: add usb endpoint address detection at driver probe step")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/usb/gs_usb.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
+index 95b0fdb602c8f..ed59451f03cdd 100644
+--- a/drivers/net/can/usb/gs_usb.c
++++ b/drivers/net/can/usb/gs_usb.c
+@@ -40,6 +40,9 @@
+ #define USB_ABE_CANDEBUGGER_FD_VENDOR_ID 0x16d0
+ #define USB_ABE_CANDEBUGGER_FD_PRODUCT_ID 0x10b8
++#define USB_XYLANTA_SAINT3_VENDOR_ID 0x16d0
++#define USB_XYLANTA_SAINT3_PRODUCT_ID 0x0f30
++
+ #define GS_USB_ENDPOINT_IN 1
+ #define GS_USB_ENDPOINT_OUT 2
+@@ -1530,6 +1533,8 @@ static const struct usb_device_id gs_usb_table[] = {
+                                     USB_CES_CANEXT_FD_PRODUCT_ID, 0) },
+       { USB_DEVICE_INTERFACE_NUMBER(USB_ABE_CANDEBUGGER_FD_VENDOR_ID,
+                                     USB_ABE_CANDEBUGGER_FD_PRODUCT_ID, 0) },
++      { USB_DEVICE_INTERFACE_NUMBER(USB_XYLANTA_SAINT3_VENDOR_ID,
++                                    USB_XYLANTA_SAINT3_PRODUCT_ID, 0) },
+       {} /* Terminating entry */
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch b/queue-6.6/can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch
new file mode 100644 (file)
index 0000000..13f1d27
--- /dev/null
@@ -0,0 +1,55 @@
+From 48ecbd4bf967fc428cf9027685aef41bd86408e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:45 +0100
+Subject: can: hi311x: hi3110_can_ist(): fix potential use-after-free
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 9ad86d377ef4a19c75a9c639964879a5b25a433b ]
+
+The commit a22bd630cfff ("can: hi311x: do not report txerr and rxerr
+during bus-off") removed the reporting of rxerr and txerr even in case
+of correct operation (i. e. not bus-off).
+
+The error count information added to the CAN frame after netif_rx() is
+a potential use after free, since there is no guarantee that the skb
+is in the same state. It might be freed or reused.
+
+Fix the issue by postponing the netif_rx() call in case of txerr and
+rxerr reporting.
+
+Fixes: a22bd630cfff ("can: hi311x: do not report txerr and rxerr during bus-off")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-5-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/spi/hi311x.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
+index e1b8533a602e2..fb58e294f7b79 100644
+--- a/drivers/net/can/spi/hi311x.c
++++ b/drivers/net/can/spi/hi311x.c
+@@ -671,9 +671,9 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
+                       tx_state = txerr >= rxerr ? new_state : 0;
+                       rx_state = txerr <= rxerr ? new_state : 0;
+                       can_change_state(net, cf, tx_state, rx_state);
+-                      netif_rx(skb);
+                       if (new_state == CAN_STATE_BUS_OFF) {
++                              netif_rx(skb);
+                               can_bus_off(net);
+                               if (priv->can.restart_ms == 0) {
+                                       priv->force_quit = 1;
+@@ -684,6 +684,7 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
+                               cf->can_id |= CAN_ERR_CNT;
+                               cf->data[6] = txerr;
+                               cf->data[7] = rxerr;
++                              netif_rx(skb);
+                       }
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch b/queue-6.6/can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch
new file mode 100644 (file)
index 0000000..f525c90
--- /dev/null
@@ -0,0 +1,89 @@
+From a8c11ccdf258bded6d6ba5daee789ac661d2dd2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:49 +0100
+Subject: can: hi311x: hi3110_can_ist(): fix {rx,tx}_errors statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 3e4645931655776e757f9fb5ae29371cd7cb21a2 ]
+
+The hi3110_can_ist() function was incorrectly incrementing only the
+receive error counter, even in cases of bit or acknowledgment errors that
+occur during transmission.
+
+The fix the issue by incrementing the appropriate counter based on the
+type of error.
+
+Fixes: 57e83fb9b746 ("can: hi311x: Add Holt HI-311x CAN driver")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-9-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/spi/hi311x.c | 47 ++++++++++++++++++++++--------------
+ 1 file changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
+index fb58e294f7b79..b757555ed4c4f 100644
+--- a/drivers/net/can/spi/hi311x.c
++++ b/drivers/net/can/spi/hi311x.c
+@@ -697,27 +697,38 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
+                       /* Check for protocol errors */
+                       if (eflag & HI3110_ERR_PROTOCOL_MASK) {
+                               skb = alloc_can_err_skb(net, &cf);
+-                              if (!skb)
+-                                      break;
++                              if (skb)
++                                      cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+-                              cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+                               priv->can.can_stats.bus_error++;
+-                              priv->net->stats.rx_errors++;
+-                              if (eflag & HI3110_ERR_BITERR)
+-                                      cf->data[2] |= CAN_ERR_PROT_BIT;
+-                              else if (eflag & HI3110_ERR_FRMERR)
+-                                      cf->data[2] |= CAN_ERR_PROT_FORM;
+-                              else if (eflag & HI3110_ERR_STUFERR)
+-                                      cf->data[2] |= CAN_ERR_PROT_STUFF;
+-                              else if (eflag & HI3110_ERR_CRCERR)
+-                                      cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+-                              else if (eflag & HI3110_ERR_ACKERR)
+-                                      cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+-
+-                              cf->data[6] = hi3110_read(spi, HI3110_READ_TEC);
+-                              cf->data[7] = hi3110_read(spi, HI3110_READ_REC);
++                              if (eflag & HI3110_ERR_BITERR) {
++                                      priv->net->stats.tx_errors++;
++                                      if (skb)
++                                              cf->data[2] |= CAN_ERR_PROT_BIT;
++                              } else if (eflag & HI3110_ERR_FRMERR) {
++                                      priv->net->stats.rx_errors++;
++                                      if (skb)
++                                              cf->data[2] |= CAN_ERR_PROT_FORM;
++                              } else if (eflag & HI3110_ERR_STUFERR) {
++                                      priv->net->stats.rx_errors++;
++                                      if (skb)
++                                              cf->data[2] |= CAN_ERR_PROT_STUFF;
++                              } else if (eflag & HI3110_ERR_CRCERR) {
++                                      priv->net->stats.rx_errors++;
++                                      if (skb)
++                                              cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
++                              } else if (eflag & HI3110_ERR_ACKERR) {
++                                      priv->net->stats.tx_errors++;
++                                      if (skb)
++                                              cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
++                              }
++
+                               netdev_dbg(priv->net, "Bus Error\n");
+-                              netif_rx(skb);
++                              if (skb) {
++                                      cf->data[6] = hi3110_read(spi, HI3110_READ_TEC);
++                                      cf->data[7] = hi3110_read(spi, HI3110_READ_REC);
++                                      netif_rx(skb);
++                              }
+                       }
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch b/queue-6.6/can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch
new file mode 100644 (file)
index 0000000..2ff29a5
--- /dev/null
@@ -0,0 +1,118 @@
+From 94a8c514f07e7beec8df7de3c7407e1d7200c712 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:48 +0100
+Subject: can: ifi_canfd: ifi_canfd_handle_lec_err(): fix {rx,tx}_errors
+ statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit bb03d568bb21b4afe7935d1943bcf68ddea3ea45 ]
+
+The ifi_canfd_handle_lec_err() function was incorrectly incrementing only
+the receive error counter, even in cases of bit or acknowledgment errors
+that occur during transmission.
+
+Fix the issue by incrementing the appropriate counter based on the
+type of error.
+
+Fixes: 5bbd655a8bd0 ("can: ifi: Add more detailed error reporting")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Reviewed-by: Marek Vasut <marex@denx.de>
+Link: https://patch.msgid.link/20241122221650.633981-8-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/ifi_canfd/ifi_canfd.c | 58 ++++++++++++++++++---------
+ 1 file changed, 40 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
+index 72307297d75e4..5145a6a73d2d7 100644
+--- a/drivers/net/can/ifi_canfd/ifi_canfd.c
++++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
+@@ -390,36 +390,55 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev)
+               return 0;
+       priv->can.can_stats.bus_error++;
+-      stats->rx_errors++;
+       /* Propagate the error condition to the CAN stack. */
+       skb = alloc_can_err_skb(ndev, &cf);
+-      if (unlikely(!skb))
+-              return 0;
+       /* Read the error counter register and check for new errors. */
+-      cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
++      if (likely(skb))
++              cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+-      if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST)
+-              cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
++      if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) {
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
++      }
+-      if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST)
+-              cf->data[3] = CAN_ERR_PROT_LOC_ACK;
++      if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) {
++              stats->tx_errors++;
++              if (likely(skb))
++                      cf->data[3] = CAN_ERR_PROT_LOC_ACK;
++      }
+-      if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST)
+-              cf->data[2] |= CAN_ERR_PROT_BIT0;
++      if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) {
++              stats->tx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_BIT0;
++      }
+-      if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST)
+-              cf->data[2] |= CAN_ERR_PROT_BIT1;
++      if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) {
++              stats->tx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_BIT1;
++      }
+-      if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST)
+-              cf->data[2] |= CAN_ERR_PROT_STUFF;
++      if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) {
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_STUFF;
++      }
+-      if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST)
+-              cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
++      if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) {
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
++      }
+-      if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST)
+-              cf->data[2] |= CAN_ERR_PROT_FORM;
++      if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) {
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_FORM;
++      }
+       /* Reset the error counter, ack the IRQ and re-enable the counter. */
+       writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
+@@ -427,6 +446,9 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev)
+              priv->base + IFI_CANFD_INTERRUPT);
+       writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
++      if (unlikely(!skb))
++              return 0;
++
+       netif_receive_skb(skb);
+       return 1;
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-j1939-j1939_session_new-fix-skb-reference-counti.patch b/queue-6.6/can-j1939-j1939_session_new-fix-skb-reference-counti.patch
new file mode 100644 (file)
index 0000000..2c681bb
--- /dev/null
@@ -0,0 +1,43 @@
+From 43e9011e938c79bb47dac06337297dc3d49ed542 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2024 12:48:23 +0300
+Subject: can: j1939: j1939_session_new(): fix skb reference counting
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit a8c695005bfe6569acd73d777ca298ddddd66105 ]
+
+Since j1939_session_skb_queue() does an extra skb_get() for each new
+skb, do the same for the initial one in j1939_session_new() to avoid
+refcount underflow.
+
+Reported-by: syzbot+d4e8dc385d9258220c31@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=d4e8dc385d9258220c31
+Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol")
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Link: https://patch.msgid.link/20241105094823.2403806-1-dmantipov@yandex.ru
+[mkl: clean up commit message]
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/can/j1939/transport.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
+index 319f47df33300..95f7a7e65a73f 100644
+--- a/net/can/j1939/transport.c
++++ b/net/can/j1939/transport.c
+@@ -1505,7 +1505,7 @@ static struct j1939_session *j1939_session_new(struct j1939_priv *priv,
+       session->state = J1939_SESSION_NEW;
+       skb_queue_head_init(&session->skb_queue);
+-      skb_queue_tail(&session->skb_queue, skb);
++      skb_queue_tail(&session->skb_queue, skb_get(skb));
+       skcb = j1939_skb_to_cb(skb);
+       memcpy(&session->skcb, skcb, sizeof(session->skcb));
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch b/queue-6.6/can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch
new file mode 100644 (file)
index 0000000..ef9fe73
--- /dev/null
@@ -0,0 +1,103 @@
+From d554849a38eceb5f7452e832d9f70a9762a20a9d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:47 +0100
+Subject: can: m_can: m_can_handle_lec_err(): fix {rx,tx}_errors statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 988d4222bf9039a875a3d48f2fe35c317831ff68 ]
+
+The m_can_handle_lec_err() function was incorrectly incrementing only the
+receive error counter, even in cases of bit or acknowledgment errors that
+occur during transmission.
+
+Fix the issue by incrementing the appropriate counter based on the
+type of error.
+
+Fixes: e0d1f4816f2a ("can: m_can: add Bosch M_CAN controller support")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-7-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/m_can/m_can.c | 33 +++++++++++++++++++++++----------
+ 1 file changed, 23 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
+index ec6e740b03247..2a258986eed02 100644
+--- a/drivers/net/can/m_can/m_can.c
++++ b/drivers/net/can/m_can/m_can.c
+@@ -636,47 +636,60 @@ static int m_can_handle_lec_err(struct net_device *dev,
+       u32 timestamp = 0;
+       cdev->can.can_stats.bus_error++;
+-      stats->rx_errors++;
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(dev, &cf);
+-      if (unlikely(!skb))
+-              return 0;
+       /* check for 'last error code' which tells us the
+        * type of the last error to occur on the CAN bus
+        */
+-      cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
++      if (likely(skb))
++              cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+       switch (lec_type) {
+       case LEC_STUFF_ERROR:
+               netdev_dbg(dev, "stuff error\n");
+-              cf->data[2] |= CAN_ERR_PROT_STUFF;
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_STUFF;
+               break;
+       case LEC_FORM_ERROR:
+               netdev_dbg(dev, "form error\n");
+-              cf->data[2] |= CAN_ERR_PROT_FORM;
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_FORM;
+               break;
+       case LEC_ACK_ERROR:
+               netdev_dbg(dev, "ack error\n");
+-              cf->data[3] = CAN_ERR_PROT_LOC_ACK;
++              stats->tx_errors++;
++              if (likely(skb))
++                      cf->data[3] = CAN_ERR_PROT_LOC_ACK;
+               break;
+       case LEC_BIT1_ERROR:
+               netdev_dbg(dev, "bit1 error\n");
+-              cf->data[2] |= CAN_ERR_PROT_BIT1;
++              stats->tx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_BIT1;
+               break;
+       case LEC_BIT0_ERROR:
+               netdev_dbg(dev, "bit0 error\n");
+-              cf->data[2] |= CAN_ERR_PROT_BIT0;
++              stats->tx_errors++;
++              if (likely(skb))
++                      cf->data[2] |= CAN_ERR_PROT_BIT0;
+               break;
+       case LEC_CRC_ERROR:
+               netdev_dbg(dev, "CRC error\n");
+-              cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
++              stats->rx_errors++;
++              if (likely(skb))
++                      cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+               break;
+       default:
+               break;
+       }
++      if (unlikely(!skb))
++              return 0;
++
+       if (cdev->is_peripheral)
+               timestamp = m_can_get_timestamp(cdev);
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch b/queue-6.6/can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch
new file mode 100644 (file)
index 0000000..c772a61
--- /dev/null
@@ -0,0 +1,147 @@
+From c4170cc9ddec098126641ef47a7d1e08647a7262 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:50 +0100
+Subject: can: sja1000: sja1000_err(): fix {rx,tx}_errors statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 2c4ef3af4b028a0eaaf378df511d3b425b1df61f ]
+
+The sja1000_err() function only incremented the receive error counter
+and never the transmit error counter, even if the ECC_DIR flag reported
+that an error had occurred during transmission.
+
+Increment the receive/transmit error counter based on the value of the
+ECC_DIR flag.
+
+Fixes: 429da1cc841b ("can: Driver for the SJA1000 CAN controller")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-10-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/sja1000/sja1000.c | 67 ++++++++++++++++++-------------
+ 1 file changed, 39 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
+index 743c2eb62b877..10e211d917e31 100644
+--- a/drivers/net/can/sja1000/sja1000.c
++++ b/drivers/net/can/sja1000/sja1000.c
+@@ -416,8 +416,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
+       int ret = 0;
+       skb = alloc_can_err_skb(dev, &cf);
+-      if (skb == NULL)
+-              return -ENOMEM;
+       txerr = priv->read_reg(priv, SJA1000_TXERR);
+       rxerr = priv->read_reg(priv, SJA1000_RXERR);
+@@ -425,8 +423,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
+       if (isrc & IRQ_DOI) {
+               /* data overrun interrupt */
+               netdev_dbg(dev, "data overrun interrupt\n");
+-              cf->can_id |= CAN_ERR_CRTL;
+-              cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
++              if (skb) {
++                      cf->can_id |= CAN_ERR_CRTL;
++                      cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
++              }
++
+               stats->rx_over_errors++;
+               stats->rx_errors++;
+               sja1000_write_cmdreg(priv, CMD_CDO);    /* clear bit */
+@@ -452,7 +453,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
+               else
+                       state = CAN_STATE_ERROR_ACTIVE;
+       }
+-      if (state != CAN_STATE_BUS_OFF) {
++      if (state != CAN_STATE_BUS_OFF && skb) {
+               cf->can_id |= CAN_ERR_CNT;
+               cf->data[6] = txerr;
+               cf->data[7] = rxerr;
+@@ -460,33 +461,38 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
+       if (isrc & IRQ_BEI) {
+               /* bus error interrupt */
+               priv->can.can_stats.bus_error++;
+-              stats->rx_errors++;
+               ecc = priv->read_reg(priv, SJA1000_ECC);
++              if (skb) {
++                      cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+-              cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+-
+-              /* set error type */
+-              switch (ecc & ECC_MASK) {
+-              case ECC_BIT:
+-                      cf->data[2] |= CAN_ERR_PROT_BIT;
+-                      break;
+-              case ECC_FORM:
+-                      cf->data[2] |= CAN_ERR_PROT_FORM;
+-                      break;
+-              case ECC_STUFF:
+-                      cf->data[2] |= CAN_ERR_PROT_STUFF;
+-                      break;
+-              default:
+-                      break;
+-              }
++                      /* set error type */
++                      switch (ecc & ECC_MASK) {
++                      case ECC_BIT:
++                              cf->data[2] |= CAN_ERR_PROT_BIT;
++                              break;
++                      case ECC_FORM:
++                              cf->data[2] |= CAN_ERR_PROT_FORM;
++                              break;
++                      case ECC_STUFF:
++                              cf->data[2] |= CAN_ERR_PROT_STUFF;
++                              break;
++                      default:
++                              break;
++                      }
+-              /* set error location */
+-              cf->data[3] = ecc & ECC_SEG;
++                      /* set error location */
++                      cf->data[3] = ecc & ECC_SEG;
++              }
+               /* Error occurred during transmission? */
+-              if ((ecc & ECC_DIR) == 0)
+-                      cf->data[2] |= CAN_ERR_PROT_TX;
++              if ((ecc & ECC_DIR) == 0) {
++                      stats->tx_errors++;
++                      if (skb)
++                              cf->data[2] |= CAN_ERR_PROT_TX;
++              } else {
++                      stats->rx_errors++;
++              }
+       }
+       if (isrc & IRQ_EPI) {
+               /* error passive interrupt */
+@@ -502,8 +508,10 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
+               netdev_dbg(dev, "arbitration lost interrupt\n");
+               alc = priv->read_reg(priv, SJA1000_ALC);
+               priv->can.can_stats.arbitration_lost++;
+-              cf->can_id |= CAN_ERR_LOSTARB;
+-              cf->data[0] = alc & 0x1f;
++              if (skb) {
++                      cf->can_id |= CAN_ERR_LOSTARB;
++                      cf->data[0] = alc & 0x1f;
++              }
+       }
+       if (state != priv->can.state) {
+@@ -516,6 +524,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
+                       can_bus_off(dev);
+       }
++      if (!skb)
++              return -ENOMEM;
++
+       netif_rx(skb);
+       return ret;
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch b/queue-6.6/can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch
new file mode 100644 (file)
index 0000000..c4b1b88
--- /dev/null
@@ -0,0 +1,47 @@
+From 35de7f5125aa5f273724ee236659d0505689ca32 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:43 +0100
+Subject: can: sun4i_can: sun4i_can_err(): call can_change_state() even if cf
+ is NULL
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit ee6bf3677ae03569d833795064e17f605c2163c7 ]
+
+Call the function can_change_state() if the allocation of the skb
+fails, as it handles the cf parameter when it is null.
+
+Additionally, this ensures that the statistics related to state error
+counters (i. e. warning, passive, and bus-off) are updated.
+
+Fixes: 0738eff14d81 ("can: Allwinner A10/A20 CAN Controller support - Kernel module")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-3-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/sun4i_can.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
+index ab8d017846869..80f7aa2531dc0 100644
+--- a/drivers/net/can/sun4i_can.c
++++ b/drivers/net/can/sun4i_can.c
+@@ -629,10 +629,10 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
+               tx_state = txerr >= rxerr ? state : 0;
+               rx_state = txerr <= rxerr ? state : 0;
+-              if (likely(skb))
+-                      can_change_state(dev, cf, tx_state, rx_state);
+-              else
+-                      priv->can.state = state;
++              /* The skb allocation might fail, but can_change_state()
++               * handles cf == NULL.
++               */
++              can_change_state(dev, cf, tx_state, rx_state);
+               if (state == CAN_STATE_BUS_OFF)
+                       can_bus_off(dev);
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch b/queue-6.6/can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch
new file mode 100644 (file)
index 0000000..12d3ddb
--- /dev/null
@@ -0,0 +1,63 @@
+From 5b370f0c836b3fd419bf6595def425ab0355c4d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Nov 2024 23:15:51 +0100
+Subject: can: sun4i_can: sun4i_can_err(): fix {rx,tx}_errors statistics
+
+From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+
+[ Upstream commit 595a81988a6fe06eb5849e972c8b9cb21c4e0d54 ]
+
+The sun4i_can_err() function only incremented the receive error counter
+and never the transmit error counter, even if the STA_ERR_DIR flag
+reported that an error had occurred during transmission.
+
+Increment the receive/transmit error counter based on the value of the
+STA_ERR_DIR flag.
+
+Fixes: 0738eff14d81 ("can: Allwinner A10/A20 CAN Controller support - Kernel module")
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+Link: https://patch.msgid.link/20241122221650.633981-11-dario.binacchi@amarulasolutions.com
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/sun4i_can.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
+index 80f7aa2531dc0..283fbf59e66d5 100644
+--- a/drivers/net/can/sun4i_can.c
++++ b/drivers/net/can/sun4i_can.c
+@@ -579,11 +579,9 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
+               /* bus error interrupt */
+               netdev_dbg(dev, "bus error interrupt\n");
+               priv->can.can_stats.bus_error++;
+-              stats->rx_errors++;
++              ecc = readl(priv->base + SUN4I_REG_STA_ADDR);
+               if (likely(skb)) {
+-                      ecc = readl(priv->base + SUN4I_REG_STA_ADDR);
+-
+                       cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+                       switch (ecc & SUN4I_STA_MASK_ERR) {
+@@ -601,9 +599,15 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
+                                              >> 16;
+                               break;
+                       }
+-                      /* error occurred during transmission? */
+-                      if ((ecc & SUN4I_STA_ERR_DIR) == 0)
++              }
++
++              /* error occurred during transmission? */
++              if ((ecc & SUN4I_STA_ERR_DIR) == 0) {
++                      if (likely(skb))
+                               cf->data[2] |= CAN_ERR_PROT_TX;
++                      stats->tx_errors++;
++              } else {
++                      stats->rx_errors++;
+               }
+       }
+       if (isrc & SUN4I_INT_ERR_PASSIVE) {
+-- 
+2.43.0
+
diff --git a/queue-6.6/dccp-fix-memory-leak-in-dccp_feat_change_recv.patch b/queue-6.6/dccp-fix-memory-leak-in-dccp_feat_change_recv.patch
new file mode 100644 (file)
index 0000000..b06d5ad
--- /dev/null
@@ -0,0 +1,78 @@
+From e7eea6fe3e6c2be7662d028c17c68348915eda5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 26 Nov 2024 17:39:02 +0300
+Subject: dccp: Fix memory leak in dccp_feat_change_recv
+
+From: Ivan Solodovnikov <solodovnikov.ia@phystech.edu>
+
+[ Upstream commit 22be4727a8f898442066bcac34f8a1ad0bc72e14 ]
+
+If dccp_feat_push_confirm() fails after new value for SP feature was accepted
+without reconciliation ('entry == NULL' branch), memory allocated for that value
+with dccp_feat_clone_sp_val() is never freed.
+
+Here is the kmemleak stack for this:
+
+unreferenced object 0xffff88801d4ab488 (size 8):
+  comm "syz-executor310", pid 1127, jiffies 4295085598 (age 41.666s)
+  hex dump (first 8 bytes):
+    01 b4 4a 1d 80 88 ff ff                          ..J.....
+  backtrace:
+    [<00000000db7cabfe>] kmemdup+0x23/0x50 mm/util.c:128
+    [<0000000019b38405>] kmemdup include/linux/string.h:465 [inline]
+    [<0000000019b38405>] dccp_feat_clone_sp_val net/dccp/feat.c:371 [inline]
+    [<0000000019b38405>] dccp_feat_clone_sp_val net/dccp/feat.c:367 [inline]
+    [<0000000019b38405>] dccp_feat_change_recv net/dccp/feat.c:1145 [inline]
+    [<0000000019b38405>] dccp_feat_parse_options+0x1196/0x2180 net/dccp/feat.c:1416
+    [<00000000b1f6d94a>] dccp_parse_options+0xa2a/0x1260 net/dccp/options.c:125
+    [<0000000030d7b621>] dccp_rcv_state_process+0x197/0x13d0 net/dccp/input.c:650
+    [<000000001f74c72e>] dccp_v4_do_rcv+0xf9/0x1a0 net/dccp/ipv4.c:688
+    [<00000000a6c24128>] sk_backlog_rcv include/net/sock.h:1041 [inline]
+    [<00000000a6c24128>] __release_sock+0x139/0x3b0 net/core/sock.c:2570
+    [<00000000cf1f3a53>] release_sock+0x54/0x1b0 net/core/sock.c:3111
+    [<000000008422fa23>] inet_wait_for_connect net/ipv4/af_inet.c:603 [inline]
+    [<000000008422fa23>] __inet_stream_connect+0x5d0/0xf70 net/ipv4/af_inet.c:696
+    [<0000000015b6f64d>] inet_stream_connect+0x53/0xa0 net/ipv4/af_inet.c:735
+    [<0000000010122488>] __sys_connect_file+0x15c/0x1a0 net/socket.c:1865
+    [<00000000b4b70023>] __sys_connect+0x165/0x1a0 net/socket.c:1882
+    [<00000000f4cb3815>] __do_sys_connect net/socket.c:1892 [inline]
+    [<00000000f4cb3815>] __se_sys_connect net/socket.c:1889 [inline]
+    [<00000000f4cb3815>] __x64_sys_connect+0x6e/0xb0 net/socket.c:1889
+    [<00000000e7b1e839>] do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46
+    [<0000000055e91434>] entry_SYSCALL_64_after_hwframe+0x67/0xd1
+
+Clean up the allocated memory in case of dccp_feat_push_confirm() failure
+and bail out with an error reset code.
+
+Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
+
+Fixes: e77b8363b2ea ("dccp: Process incoming Change feature-negotiation options")
+Signed-off-by: Ivan Solodovnikov <solodovnikov.ia@phystech.edu>
+Link: https://patch.msgid.link/20241126143902.190853-1-solodovnikov.ia@phystech.edu
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/dccp/feat.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/net/dccp/feat.c b/net/dccp/feat.c
+index 54086bb05c42c..f7554dcdaaba9 100644
+--- a/net/dccp/feat.c
++++ b/net/dccp/feat.c
+@@ -1166,8 +1166,12 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+                       goto not_valid_or_not_known;
+               }
+-              return dccp_feat_push_confirm(fn, feat, local, &fval);
++              if (dccp_feat_push_confirm(fn, feat, local, &fval)) {
++                      kfree(fval.sp.vec);
++                      return DCCP_RESET_CODE_TOO_BUSY;
++              }
++              return 0;
+       } else if (entry->state == FEAT_UNSTABLE) {     /* 6.6.2 */
+               return 0;
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/driver-core-add-fwlink_flag_ignore-to-completely-ign.patch b/queue-6.6/driver-core-add-fwlink_flag_ignore-to-completely-ign.patch
new file mode 100644 (file)
index 0000000..76af4dd
--- /dev/null
@@ -0,0 +1,86 @@
+From 04376b4e41eddbdc05a4b2b617aae9e80ec3448b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Mar 2024 21:04:55 -0800
+Subject: driver core: Add FWLINK_FLAG_IGNORE to completely ignore a fwnode
+ link
+
+From: Saravana Kannan <saravanak@google.com>
+
+[ Upstream commit b7e1241d8f77ed64404a5e4450f43a319310fc91 ]
+
+A fwnode link between specific supplier-consumer fwnodes can be added
+multiple times for multiple reasons. If that dependency doesn't exist,
+deleting the fwnode link once doesn't guarantee that it won't get created
+again.
+
+So, add FWLINK_FLAG_IGNORE flag to mark a fwnode link as one that needs to
+be completely ignored. Since a fwnode link's flags is an OR of all the
+flags passed to all the fwnode_link_add() calls to create that specific
+fwnode link, the FWLINK_FLAG_IGNORE flag is preserved and can be used to
+mark a fwnode link as on that need to be completely ignored until it is
+deleted.
+
+Signed-off-by: Saravana Kannan <saravanak@google.com>
+Acked-by: "Rafael J. Wysocki" <rafael@kernel.org>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20240305050458.1400667-3-saravanak@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bac3b10b78e5 ("driver core: fw_devlink: Stop trying to optimize cycle detection logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/core.c    | 9 ++++++++-
+ include/linux/fwnode.h | 2 ++
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index 499904f1ba6b3..3aaf234dbb088 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -1025,7 +1025,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers(
+               return NULL;
+       list_for_each_entry(link, &fwnode->suppliers, c_hook)
+-              if (!(link->flags & FWLINK_FLAG_CYCLE))
++              if (!(link->flags &
++                    (FWLINK_FLAG_CYCLE | FWLINK_FLAG_IGNORE)))
+                       return link->supplier;
+       return NULL;
+@@ -1976,6 +1977,9 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+       }
+       list_for_each_entry(link, &sup_handle->suppliers, c_hook) {
++              if (link->flags & FWLINK_FLAG_IGNORE)
++                      continue;
++
+               if (__fw_devlink_relax_cycles(con, link->supplier)) {
+                       __fwnode_link_cycle(link);
+                       ret = true;
+@@ -2054,6 +2058,9 @@ static int fw_devlink_create_devlink(struct device *con,
+       int ret = 0;
+       u32 flags;
++      if (link->flags & FWLINK_FLAG_IGNORE)
++              return 0;
++
+       if (con->fwnode == link->consumer)
+               flags = fw_devlink_get_flags(link->flags);
+       else
+diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
+index 5700451b300fb..525cc031596b6 100644
+--- a/include/linux/fwnode.h
++++ b/include/linux/fwnode.h
+@@ -51,8 +51,10 @@ struct fwnode_handle {
+  * fwnode link flags
+  *
+  * CYCLE:     The fwnode link is part of a cycle. Don't defer probe.
++ * IGNORE:    Completely ignore this link, even during cycle detection.
+  */
+ #define FWLINK_FLAG_CYCLE                     BIT(0)
++#define FWLINK_FLAG_IGNORE                    BIT(1)
+ struct fwnode_link {
+       struct fwnode_handle *supplier;
+-- 
+2.43.0
+
diff --git a/queue-6.6/driver-core-fw_devlink-improve-logs-for-cycle-detect.patch b/queue-6.6/driver-core-fw_devlink-improve-logs-for-cycle-detect.patch
new file mode 100644 (file)
index 0000000..baac5b9
--- /dev/null
@@ -0,0 +1,79 @@
+From 6a716baa913705f983ed10a53b944a57994d0378 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2024 01:56:35 -0800
+Subject: driver core: fw_devlink: Improve logs for cycle detection
+
+From: Saravana Kannan <saravanak@google.com>
+
+[ Upstream commit 6e7ad1aebb4fc9fed0217dd50ef6e58a53f17d81 ]
+
+The links in a cycle are not all logged in a consistent manner or not
+logged at all. Make them consistent by adding a "cycle:" string and log all
+the link in the cycles (even the child ==> parent dependency) so that it's
+easier to debug cycle detection code. Also, mark the start and end of a
+cycle so it's easy to tell when multiple cycles are logged back to back.
+
+Signed-off-by: Saravana Kannan <saravanak@google.com>
+Tested-by: Xu Yang <xu.yang_2@nxp.com>
+Link: https://lore.kernel.org/r/20240202095636.868578-4-saravanak@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: bac3b10b78e5 ("driver core: fw_devlink: Stop trying to optimize cycle detection logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/core.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index c9fb3243e353e..499904f1ba6b3 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -125,7 +125,7 @@ static void __fwnode_link_del(struct fwnode_link *link)
+  */
+ static void __fwnode_link_cycle(struct fwnode_link *link)
+ {
+-      pr_debug("%pfwf: Relaxing link with %pfwf\n",
++      pr_debug("%pfwf: cycle: depends on %pfwf\n",
+                link->consumer, link->supplier);
+       link->flags |= FWLINK_FLAG_CYCLE;
+ }
+@@ -1959,6 +1959,7 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+       /* Termination condition. */
+       if (sup_dev == con) {
++              pr_debug("----- cycle: start -----\n");
+               ret = true;
+               goto out;
+       }
+@@ -1990,8 +1991,11 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+       else
+               par_dev = fwnode_get_next_parent_dev(sup_handle);
+-      if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode))
++      if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) {
++              pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle,
++                       par_dev->fwnode);
+               ret = true;
++      }
+       if (!sup_dev)
+               goto out;
+@@ -2007,6 +2011,8 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+               if (__fw_devlink_relax_cycles(con,
+                                             dev_link->supplier->fwnode)) {
++                      pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle,
++                               dev_link->supplier->fwnode);
+                       fw_devlink_relax_link(dev_link);
+                       dev_link->flags |= DL_FLAG_CYCLE;
+                       ret = true;
+@@ -2086,6 +2092,7 @@ static int fw_devlink_create_devlink(struct device *con,
+               if (__fw_devlink_relax_cycles(con, sup_handle)) {
+                       __fwnode_link_cycle(link);
+                       flags = fw_devlink_get_flags(link->flags);
++                      pr_debug("----- cycle: end -----\n");
+                       dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
+                                sup_handle);
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.6/driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch b/queue-6.6/driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch
new file mode 100644 (file)
index 0000000..8d69fc5
--- /dev/null
@@ -0,0 +1,169 @@
+From 387f86ff58a2578db852ab96354437d3b960c322 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Oct 2024 10:10:07 -0700
+Subject: driver core: fw_devlink: Stop trying to optimize cycle detection
+ logic
+
+From: Saravana Kannan <saravanak@google.com>
+
+[ Upstream commit bac3b10b78e54b7da3cede397258f75a2180609b ]
+
+In attempting to optimize fw_devlink runtime, I introduced numerous cycle
+detection bugs by foregoing cycle detection logic under specific
+conditions. Each fix has further narrowed the conditions for optimization.
+
+It's time to give up on these optimization attempts and just run the cycle
+detection logic every time fw_devlink tries to create a device link.
+
+The specific bug report that triggered this fix involved a supplier fwnode
+that never gets a device created for it. Instead, the supplier fwnode is
+represented by the device that corresponds to an ancestor fwnode.
+
+In this case, fw_devlink didn't do any cycle detection because the cycle
+detection logic is only run when a device link is created between the
+devices that correspond to the actual consumer and supplier fwnodes.
+
+With this change, fw_devlink will run cycle detection logic even when
+creating SYNC_STATE_ONLY proxy device links from a device that is an
+ancestor of a consumer fwnode.
+
+Reported-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+Closes: https://lore.kernel.org/all/1a1ab663-d068-40fb-8c94-f0715403d276@ideasonboard.com/
+Fixes: 6442d79d880c ("driver core: fw_devlink: Improve detection of overlapping cycles")
+Cc: stable <stable@kernel.org>
+Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+Signed-off-by: Saravana Kannan <saravanak@google.com>
+Link: https://lore.kernel.org/r/20241030171009.1853340-1-saravanak@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/core.c | 55 ++++++++++++++++++++-------------------------
+ 1 file changed, 24 insertions(+), 31 deletions(-)
+
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index 3aaf234dbb088..18a73e4921026 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -1936,10 +1936,10 @@ static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode)
+  *
+  * Return true if one or more cycles were found. Otherwise, return false.
+  */
+-static bool __fw_devlink_relax_cycles(struct device *con,
++static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,
+                                struct fwnode_handle *sup_handle)
+ {
+-      struct device *sup_dev = NULL, *par_dev = NULL;
++      struct device *sup_dev = NULL, *par_dev = NULL, *con_dev = NULL;
+       struct fwnode_link *link;
+       struct device_link *dev_link;
+       bool ret = false;
+@@ -1956,22 +1956,22 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+       sup_handle->flags |= FWNODE_FLAG_VISITED;
+-      sup_dev = get_dev_from_fwnode(sup_handle);
+-
+       /* Termination condition. */
+-      if (sup_dev == con) {
++      if (sup_handle == con_handle) {
+               pr_debug("----- cycle: start -----\n");
+               ret = true;
+               goto out;
+       }
++      sup_dev = get_dev_from_fwnode(sup_handle);
++      con_dev = get_dev_from_fwnode(con_handle);
+       /*
+        * If sup_dev is bound to a driver and @con hasn't started binding to a
+        * driver, sup_dev can't be a consumer of @con. So, no need to check
+        * further.
+        */
+       if (sup_dev && sup_dev->links.status ==  DL_DEV_DRIVER_BOUND &&
+-          con->links.status == DL_DEV_NO_DRIVER) {
++          con_dev && con_dev->links.status == DL_DEV_NO_DRIVER) {
+               ret = false;
+               goto out;
+       }
+@@ -1980,7 +1980,7 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+               if (link->flags & FWLINK_FLAG_IGNORE)
+                       continue;
+-              if (__fw_devlink_relax_cycles(con, link->supplier)) {
++              if (__fw_devlink_relax_cycles(con_handle, link->supplier)) {
+                       __fwnode_link_cycle(link);
+                       ret = true;
+               }
+@@ -1995,7 +1995,7 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+       else
+               par_dev = fwnode_get_next_parent_dev(sup_handle);
+-      if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) {
++      if (par_dev && __fw_devlink_relax_cycles(con_handle, par_dev->fwnode)) {
+               pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle,
+                        par_dev->fwnode);
+               ret = true;
+@@ -2013,7 +2013,7 @@ static bool __fw_devlink_relax_cycles(struct device *con,
+                   !(dev_link->flags & DL_FLAG_CYCLE))
+                       continue;
+-              if (__fw_devlink_relax_cycles(con,
++              if (__fw_devlink_relax_cycles(con_handle,
+                                             dev_link->supplier->fwnode)) {
+                       pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle,
+                                dev_link->supplier->fwnode);
+@@ -2061,11 +2061,6 @@ static int fw_devlink_create_devlink(struct device *con,
+       if (link->flags & FWLINK_FLAG_IGNORE)
+               return 0;
+-      if (con->fwnode == link->consumer)
+-              flags = fw_devlink_get_flags(link->flags);
+-      else
+-              flags = FW_DEVLINK_FLAGS_PERMISSIVE;
+-
+       /*
+        * In some cases, a device P might also be a supplier to its child node
+        * C. However, this would defer the probe of C until the probe of P
+@@ -2086,25 +2081,23 @@ static int fw_devlink_create_devlink(struct device *con,
+               return -EINVAL;
+       /*
+-       * SYNC_STATE_ONLY device links don't block probing and supports cycles.
+-       * So, one might expect that cycle detection isn't necessary for them.
+-       * However, if the device link was marked as SYNC_STATE_ONLY because
+-       * it's part of a cycle, then we still need to do cycle detection. This
+-       * is because the consumer and supplier might be part of multiple cycles
+-       * and we need to detect all those cycles.
++       * Don't try to optimize by not calling the cycle detection logic under
++       * certain conditions. There's always some corner case that won't get
++       * detected.
+        */
+-      if (!device_link_flag_is_sync_state_only(flags) ||
+-          flags & DL_FLAG_CYCLE) {
+-              device_links_write_lock();
+-              if (__fw_devlink_relax_cycles(con, sup_handle)) {
+-                      __fwnode_link_cycle(link);
+-                      flags = fw_devlink_get_flags(link->flags);
+-                      pr_debug("----- cycle: end -----\n");
+-                      dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
+-                               sup_handle);
+-              }
+-              device_links_write_unlock();
++      device_links_write_lock();
++      if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) {
++              __fwnode_link_cycle(link);
++              pr_debug("----- cycle: end -----\n");
++              pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n",
++                      link->consumer, sup_handle);
+       }
++      device_links_write_unlock();
++
++      if (con->fwnode == link->consumer)
++              flags = fw_devlink_get_flags(link->flags);
++      else
++              flags = FW_DEVLINK_FLAGS_PERMISSIVE;
+       if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE)
+               sup_dev = fwnode_get_next_parent_dev(sup_handle);
+-- 
+2.43.0
+
diff --git a/queue-6.6/drm-bridge-it6505-fix-inverted-reset-polarity.patch b/queue-6.6/drm-bridge-it6505-fix-inverted-reset-polarity.patch
new file mode 100644 (file)
index 0000000..e5b9135
--- /dev/null
@@ -0,0 +1,74 @@
+From 6d2e02bd1251f26dc78b83d6ffe7c38933d8c763 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Oct 2024 17:54:10 +0800
+Subject: drm/bridge: it6505: Fix inverted reset polarity
+
+From: Chen-Yu Tsai <wenst@chromium.org>
+
+[ Upstream commit c5f3f21728b069412e8072b8b1d0a3d9d3ab0265 ]
+
+The IT6505 bridge chip has a active low reset line. Since it is a
+"reset" and not an "enable" line, the GPIO should be asserted to
+put it in reset and deasserted to bring it out of reset during
+the power on sequence.
+
+The polarity was inverted when the driver was first introduced, likely
+because the device family that was targeted had an inverting level
+shifter on the reset line.
+
+The MT8186 Corsola devices already have the IT6505 in their device tree,
+but the whole display pipeline is actually disabled and won't be enabled
+until some remaining issues are sorted out. The other known user is
+the MT8183 Kukui / Jacuzzi family; their device trees currently do not
+have the IT6505 included.
+
+Fix the polarity in the driver while there are no actual users.
+
+Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver")
+Cc: stable@vger.kernel.org
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241029095411.657616-1-wenst@chromium.org
+Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/ite-it6505.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
+index fda2c565fdb31..2a7c620626a03 100644
+--- a/drivers/gpu/drm/bridge/ite-it6505.c
++++ b/drivers/gpu/drm/bridge/ite-it6505.c
+@@ -2611,9 +2611,9 @@ static int it6505_poweron(struct it6505 *it6505)
+       /* time interval between OVDD and SYSRSTN at least be 10ms */
+       if (pdata->gpiod_reset) {
+               usleep_range(10000, 20000);
+-              gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+-              usleep_range(1000, 2000);
+               gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
++              usleep_range(1000, 2000);
++              gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+               usleep_range(25000, 35000);
+       }
+@@ -2640,7 +2640,7 @@ static int it6505_poweroff(struct it6505 *it6505)
+       }
+       if (pdata->gpiod_reset)
+-              gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
++              gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
+       if (pdata->pwr18) {
+               err = regulator_disable(pdata->pwr18);
+@@ -3132,7 +3132,7 @@ static int it6505_init_pdata(struct it6505 *it6505)
+               return PTR_ERR(pdata->ovdd);
+       }
+-      pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
++      pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(pdata->gpiod_reset)) {
+               dev_err(dev, "gpiod_reset gpio not found");
+               return PTR_ERR(pdata->gpiod_reset);
+-- 
+2.43.0
+
diff --git a/queue-6.6/drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch b/queue-6.6/drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch
new file mode 100644 (file)
index 0000000..adcbb42
--- /dev/null
@@ -0,0 +1,39 @@
+From 0937493f1deb1ffe52c20244c9736a0015fe8fc3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jun 2024 10:44:05 +0800
+Subject: drm/bridge: it6505: update usleep_range for RC circuit charge time
+
+From: Kuro Chung <kuro.chung@ite.com.tw>
+
+[ Upstream commit 8814444e62b8a8b573fba2cbbb327d5817b74eb0 ]
+
+The spec of timing between IVDD/OVDD and SYSRTEN is 10ms, but SYSRSTN RC
+circuit need at least 25ms for rising time, update for match spec
+
+Signed-off-by: Kuro Chung <kuro.chung@ite.com.tw>
+Signed-off-by: Hermes Wu <hermes.wu@ite.com.tw>
+Reviewed-by: Robert Foss <rfoss@kernel.org>
+Signed-off-by: Robert Foss <rfoss@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240604024405.1122488-1-kuro.chung@ite.com.tw
+Stable-dep-of: c5f3f21728b0 ("drm/bridge: it6505: Fix inverted reset polarity")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/ite-it6505.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
+index 93eb8fba23d42..fda2c565fdb31 100644
+--- a/drivers/gpu/drm/bridge/ite-it6505.c
++++ b/drivers/gpu/drm/bridge/ite-it6505.c
+@@ -2614,7 +2614,7 @@ static int it6505_poweron(struct it6505 *it6505)
+               gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+               usleep_range(1000, 2000);
+               gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
+-              usleep_range(10000, 20000);
++              usleep_range(25000, 35000);
+       }
+       it6505->powered = true;
+-- 
+2.43.0
+
diff --git a/queue-6.6/ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch b/queue-6.6/ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch
new file mode 100644 (file)
index 0000000..50d0fa2
--- /dev/null
@@ -0,0 +1,127 @@
+From b846b02e7a5210a64c3d7c2f7d664c6534d9fc82 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Dec 2024 16:33:57 +0100
+Subject: ethtool: Fix wrong mod state in case of verbose and no_mask bitset
+
+From: Kory Maincent <kory.maincent@bootlin.com>
+
+[ Upstream commit 910c4788d6155b2202ec88273376cd7ecdc24f0a ]
+
+A bitset without mask in a _SET request means we want exactly the bits in
+the bitset to be set. This works correctly for compact format but when
+verbose format is parsed, ethnl_update_bitset32_verbose() only sets the
+bits present in the request bitset but does not clear the rest. The commit
+6699170376ab ("ethtool: fix application of verbose no_mask bitset") fixes
+this issue by clearing the whole target bitmap before we start iterating.
+The solution proposed brought an issue with the behavior of the mod
+variable. As the bitset is always cleared the old value will always
+differ to the new value.
+
+Fix it by adding a new function to compare bitmaps and a temporary variable
+which save the state of the old bitmap.
+
+Fixes: 6699170376ab ("ethtool: fix application of verbose no_mask bitset")
+Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
+Link: https://patch.msgid.link/20241202153358.1142095-1-kory.maincent@bootlin.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ethtool/bitset.c | 48 ++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 44 insertions(+), 4 deletions(-)
+
+diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c
+index 0515d6604b3b9..f0883357d12e5 100644
+--- a/net/ethtool/bitset.c
++++ b/net/ethtool/bitset.c
+@@ -425,12 +425,32 @@ static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
+       return 0;
+ }
++/**
++ * ethnl_bitmap32_equal() - Compare two bitmaps
++ * @map1:  first bitmap
++ * @map2:  second bitmap
++ * @nbits: bit size to compare
++ *
++ * Return: true if first @nbits are equal, false if not
++ */
++static bool ethnl_bitmap32_equal(const u32 *map1, const u32 *map2,
++                               unsigned int nbits)
++{
++      if (memcmp(map1, map2, nbits / 32 * sizeof(u32)))
++              return false;
++      if (nbits % 32 == 0)
++              return true;
++      return !((map1[nbits / 32] ^ map2[nbits / 32]) &
++               ethnl_lower_bits(nbits % 32));
++}
++
+ static int
+ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
+                             const struct nlattr *attr, struct nlattr **tb,
+                             ethnl_string_array_t names,
+                             struct netlink_ext_ack *extack, bool *mod)
+ {
++      u32 *saved_bitmap = NULL;
+       struct nlattr *bit_attr;
+       bool no_mask;
+       int rem;
+@@ -448,8 +468,20 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
+       }
+       no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
+-      if (no_mask)
+-              ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
++      if (no_mask) {
++              unsigned int nwords = DIV_ROUND_UP(nbits, 32);
++              unsigned int nbytes = nwords * sizeof(u32);
++              bool dummy;
++
++              /* The bitmap size is only the size of the map part without
++               * its mask part.
++               */
++              saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL);
++              if (!saved_bitmap)
++                      return -ENOMEM;
++              memcpy(saved_bitmap, bitmap, nbytes);
++              ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
++      }
+       nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
+               bool old_val, new_val;
+@@ -458,22 +490,30 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
+               if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
+                       NL_SET_ERR_MSG_ATTR(extack, bit_attr,
+                                           "only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
++                      kfree(saved_bitmap);
+                       return -EINVAL;
+               }
+               ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
+                                     names, extack);
+-              if (ret < 0)
++              if (ret < 0) {
++                      kfree(saved_bitmap);
+                       return ret;
++              }
+               old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
+               if (new_val != old_val) {
+                       if (new_val)
+                               bitmap[idx / 32] |= ((u32)1 << (idx % 32));
+                       else
+                               bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
+-                      *mod = true;
++                      if (!no_mask)
++                              *mod = true;
+               }
+       }
++      if (no_mask && !ethnl_bitmap32_equal(saved_bitmap, bitmap, nbits))
++              *mod = true;
++
++      kfree(saved_bitmap);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch b/queue-6.6/f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch
new file mode 100644 (file)
index 0000000..70d1add
--- /dev/null
@@ -0,0 +1,103 @@
+From 4b9b904a869202f57de21ba665362b51809569d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 Nov 2024 22:17:16 +0800
+Subject: f2fs: fix to drop all discards after creating snapshot on lvm device
+
+From: Chao Yu <chao@kernel.org>
+
+[ Upstream commit bc8aeb04fd80cb8cfae3058445c84410fd0beb5e ]
+
+Piergiorgio reported a bug in bugzilla as below:
+
+------------[ cut here ]------------
+WARNING: CPU: 2 PID: 969 at fs/f2fs/segment.c:1330
+RIP: 0010:__submit_discard_cmd+0x27d/0x400 [f2fs]
+Call Trace:
+ __issue_discard_cmd+0x1ca/0x350 [f2fs]
+ issue_discard_thread+0x191/0x480 [f2fs]
+ kthread+0xcf/0x100
+ ret_from_fork+0x31/0x50
+ ret_from_fork_asm+0x1a/0x30
+
+w/ below testcase, it can reproduce this bug quickly:
+- pvcreate /dev/vdb
+- vgcreate myvg1 /dev/vdb
+- lvcreate -L 1024m -n mylv1 myvg1
+- mount /dev/myvg1/mylv1 /mnt/f2fs
+- dd if=/dev/zero of=/mnt/f2fs/file bs=1M count=20
+- sync
+- rm /mnt/f2fs/file
+- sync
+- lvcreate -L 1024m -s -n mylv1-snapshot /dev/myvg1/mylv1
+- umount /mnt/f2fs
+
+The root cause is: it will update discard_max_bytes of mounted lvm
+device to zero after creating snapshot on this lvm device, then,
+__submit_discard_cmd() will pass parameter @nr_sects w/ zero value
+to __blkdev_issue_discard(), it returns a NULL bio pointer, result
+in panic.
+
+This patch changes as below for fixing:
+1. Let's drop all remained discards in f2fs_unfreeze() if snapshot
+of lvm device is created.
+2. Checking discard_max_bytes before submitting discard during
+__submit_discard_cmd().
+
+Cc: stable@vger.kernel.org
+Fixes: 35ec7d574884 ("f2fs: split discard command in prior to block layer")
+Reported-by: Piergiorgio Sartor <piergiorgio.sartor@nexgo.de>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219484
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/segment.c |  9 +++++++++
+ fs/f2fs/super.c   | 12 ++++++++++++
+ 2 files changed, 21 insertions(+)
+
+diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
+index 670104628ddbe..156d92b945258 100644
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -1282,6 +1282,15 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
+       }
+ #endif
++      /*
++       * stop issuing discard for any of below cases:
++       * 1. device is conventional zone, but it doesn't support discard.
++       * 2. device is regulare device, after snapshot it doesn't support
++       * discard.
++       */
++      if (!bdev_max_discard_sectors(bdev))
++              return -EOPNOTSUPP;
++
+       trace_f2fs_issue_discard(bdev, dc->di.start, dc->di.len);
+       lstart = dc->di.lstart;
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index f05d0e43db9e2..b72fa103b9632 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1735,6 +1735,18 @@ static int f2fs_freeze(struct super_block *sb)
+ static int f2fs_unfreeze(struct super_block *sb)
+ {
++      struct f2fs_sb_info *sbi = F2FS_SB(sb);
++
++      /*
++       * It will update discard_max_bytes of mounted lvm device to zero
++       * after creating snapshot on this lvm device, let's drop all
++       * remained discards.
++       * We don't need to disable real-time discard because discard_max_bytes
++       * will recover after removal of snapshot.
++       */
++      if (test_opt(sbi, DISCARD) && !f2fs_hw_support_discard(sbi))
++              f2fs_issue_discard_timeout(sbi);
++
+       clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch b/queue-6.6/geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch
new file mode 100644 (file)
index 0000000..9ebafc9
--- /dev/null
@@ -0,0 +1,85 @@
+From 1f8d7560d3a7f72d5a0075aea45c9302ae46bf06 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 18:21:21 +0000
+Subject: geneve: do not assume mac header is set in geneve_xmit_skb()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 8588c99c7d47448fcae39e3227d6e2bb97aad86d ]
+
+We should not assume mac header is set in output path.
+
+Use skb_eth_hdr() instead of eth_hdr() to fix the issue.
+
+sysbot reported the following :
+
+ WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 skb_mac_header include/linux/skbuff.h:3052 [inline]
+ WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 eth_hdr include/linux/if_ether.h:24 [inline]
+ WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 geneve_xmit_skb drivers/net/geneve.c:898 [inline]
+ WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 geneve_xmit+0x4c38/0x5730 drivers/net/geneve.c:1039
+Modules linked in:
+CPU: 0 UID: 0 PID: 11635 Comm: syz.4.1423 Not tainted 6.12.0-syzkaller-10296-gaaf20f870da0 #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024
+ RIP: 0010:skb_mac_header include/linux/skbuff.h:3052 [inline]
+ RIP: 0010:eth_hdr include/linux/if_ether.h:24 [inline]
+ RIP: 0010:geneve_xmit_skb drivers/net/geneve.c:898 [inline]
+ RIP: 0010:geneve_xmit+0x4c38/0x5730 drivers/net/geneve.c:1039
+Code: 21 c6 02 e9 35 d4 ff ff e8 a5 48 4c fb 90 0f 0b 90 e9 fd f5 ff ff e8 97 48 4c fb 90 0f 0b 90 e9 d8 f5 ff ff e8 89 48 4c fb 90 <0f> 0b 90 e9 41 e4 ff ff e8 7b 48 4c fb 90 0f 0b 90 e9 cd e7 ff ff
+RSP: 0018:ffffc90003b2f870 EFLAGS: 00010283
+RAX: 000000000000037a RBX: 000000000000ffff RCX: ffffc9000dc3d000
+RDX: 0000000000080000 RSI: ffffffff86428417 RDI: 0000000000000003
+RBP: ffffc90003b2f9f0 R08: 0000000000000003 R09: 000000000000ffff
+R10: 000000000000ffff R11: 0000000000000002 R12: ffff88806603c000
+R13: 0000000000000000 R14: ffff8880685b2780 R15: 0000000000000e23
+FS:  00007fdc2deed6c0(0000) GS:ffff8880b8600000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000001b30a1dff8 CR3: 0000000056b8c000 CR4: 00000000003526f0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+ <TASK>
+  __netdev_start_xmit include/linux/netdevice.h:5002 [inline]
+  netdev_start_xmit include/linux/netdevice.h:5011 [inline]
+  __dev_direct_xmit+0x58a/0x720 net/core/dev.c:4490
+  dev_direct_xmit include/linux/netdevice.h:3181 [inline]
+  packet_xmit+0x1e4/0x360 net/packet/af_packet.c:285
+  packet_snd net/packet/af_packet.c:3146 [inline]
+  packet_sendmsg+0x2700/0x5660 net/packet/af_packet.c:3178
+  sock_sendmsg_nosec net/socket.c:711 [inline]
+  __sock_sendmsg net/socket.c:726 [inline]
+  __sys_sendto+0x488/0x4f0 net/socket.c:2197
+  __do_sys_sendto net/socket.c:2204 [inline]
+  __se_sys_sendto net/socket.c:2200 [inline]
+  __x64_sys_sendto+0xe0/0x1c0 net/socket.c:2200
+  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+  do_syscall_64+0xcd/0x250 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fixes: a025fb5f49ad ("geneve: Allow configuration of DF behaviour")
+Reported-by: syzbot+3ec5271486d7cb2d242a@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/674f4b72.050a0220.17bd51.004a.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
+Link: https://patch.msgid.link/20241203182122.2725517-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/geneve.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
+index 8333a5620deff..b939d4711c59b 100644
+--- a/drivers/net/geneve.c
++++ b/drivers/net/geneve.c
+@@ -986,7 +986,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
+               if (geneve->cfg.df == GENEVE_DF_SET) {
+                       df = htons(IP_DF);
+               } else if (geneve->cfg.df == GENEVE_DF_INHERIT) {
+-                      struct ethhdr *eth = eth_hdr(skb);
++                      struct ethhdr *eth = skb_eth_hdr(skb);
+                       if (ntohs(eth->h_proto) == ETH_P_IPV6) {
+                               df = htons(IP_DF);
+-- 
+2.43.0
+
diff --git a/queue-6.6/gpio-grgpio-add-null-check-in-grgpio_probe.patch b/queue-6.6/gpio-grgpio-add-null-check-in-grgpio_probe.patch
new file mode 100644 (file)
index 0000000..8067b6f
--- /dev/null
@@ -0,0 +1,41 @@
+From 841304a688e9aaa79f09f51434501954bcc59198 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Nov 2024 17:18:22 +0800
+Subject: gpio: grgpio: Add NULL check in grgpio_probe
+
+From: Charles Han <hanchunchao@inspur.com>
+
+[ Upstream commit 050b23d081da0f29474de043e9538c1f7a351b3b ]
+
+devm_kasprintf() can return a NULL pointer on failure,but this
+returned value in grgpio_probe is not checked.
+Add NULL check in grgpio_probe, to handle kernel NULL
+pointer dereference error.
+
+Cc: stable@vger.kernel.org
+Fixes: 7eb6ce2f2723 ("gpio: Convert to using %pOF instead of full_name")
+Signed-off-by: Charles Han <hanchunchao@inspur.com>
+Link: https://lore.kernel.org/r/20241114091822.78199-1-hanchunchao@inspur.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-grgpio.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
+index fe919d9bd46a3..637a4d45f8c77 100644
+--- a/drivers/gpio/gpio-grgpio.c
++++ b/drivers/gpio/gpio-grgpio.c
+@@ -362,6 +362,9 @@ static int grgpio_probe(struct platform_device *ofdev)
+       gc->owner = THIS_MODULE;
+       gc->to_irq = grgpio_to_irq;
+       gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
++      if (!gc->label)
++              return -ENOMEM;
++
+       gc->base = -1;
+       err = of_property_read_u32(np, "nbits", &prop);
+-- 
+2.43.0
+
diff --git a/queue-6.6/gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch b/queue-6.6/gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch
new file mode 100644 (file)
index 0000000..f341818
--- /dev/null
@@ -0,0 +1,114 @@
+From 53b0b618e0ea7c1ffbaa4e291f212de4d6c98084 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 15 Oct 2024 15:18:31 +0200
+Subject: gpio: grgpio: use a helper variable to store the address of
+ ofdev->dev
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit d036ae41cebdfae92666024163c109b8fef516fa ]
+
+Instead of dereferencing the platform device pointer repeatedly, just
+store its address in a helper variable.
+
+Link: https://lore.kernel.org/r/20241015131832.44678-3-brgl@bgdev.pl
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Stable-dep-of: 050b23d081da ("gpio: grgpio: Add NULL check in grgpio_probe")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-grgpio.c | 23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
+index 0163c95f6dd75..fe919d9bd46a3 100644
+--- a/drivers/gpio/gpio-grgpio.c
++++ b/drivers/gpio/gpio-grgpio.c
+@@ -328,6 +328,7 @@ static const struct irq_domain_ops grgpio_irq_domain_ops = {
+ static int grgpio_probe(struct platform_device *ofdev)
+ {
+       struct device_node *np = ofdev->dev.of_node;
++      struct device *dev = &ofdev->dev;
+       void  __iomem *regs;
+       struct gpio_chip *gc;
+       struct grgpio_priv *priv;
+@@ -337,7 +338,7 @@ static int grgpio_probe(struct platform_device *ofdev)
+       int size;
+       int i;
+-      priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+@@ -346,28 +347,28 @@ static int grgpio_probe(struct platform_device *ofdev)
+               return PTR_ERR(regs);
+       gc = &priv->gc;
+-      err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA,
++      err = bgpio_init(gc, dev, 4, regs + GRGPIO_DATA,
+                        regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
+                        BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+       if (err) {
+-              dev_err(&ofdev->dev, "bgpio_init() failed\n");
++              dev_err(dev, "bgpio_init() failed\n");
+               return err;
+       }
+       priv->regs = regs;
+       priv->imask = gc->read_reg(regs + GRGPIO_IMASK);
+-      priv->dev = &ofdev->dev;
++      priv->dev = dev;
+       gc->owner = THIS_MODULE;
+       gc->to_irq = grgpio_to_irq;
+-      gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np);
++      gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
+       gc->base = -1;
+       err = of_property_read_u32(np, "nbits", &prop);
+       if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) {
+               gc->ngpio = GRGPIO_MAX_NGPIO;
+-              dev_dbg(&ofdev->dev,
+-                      "No or invalid nbits property: assume %d\n", gc->ngpio);
++              dev_dbg(dev, "No or invalid nbits property: assume %d\n",
++                      gc->ngpio);
+       } else {
+               gc->ngpio = prop;
+       }
+@@ -379,7 +380,7 @@ static int grgpio_probe(struct platform_device *ofdev)
+       irqmap = (s32 *)of_get_property(np, "irqmap", &size);
+       if (irqmap) {
+               if (size < gc->ngpio) {
+-                      dev_err(&ofdev->dev,
++                      dev_err(dev,
+                               "irqmap shorter than ngpio (%d < %d)\n",
+                               size, gc->ngpio);
+                       return -EINVAL;
+@@ -389,7 +390,7 @@ static int grgpio_probe(struct platform_device *ofdev)
+                                                    &grgpio_irq_domain_ops,
+                                                    priv);
+               if (!priv->domain) {
+-                      dev_err(&ofdev->dev, "Could not add irq domain\n");
++                      dev_err(dev, "Could not add irq domain\n");
+                       return -EINVAL;
+               }
+@@ -419,13 +420,13 @@ static int grgpio_probe(struct platform_device *ofdev)
+       err = gpiochip_add_data(gc, priv);
+       if (err) {
+-              dev_err(&ofdev->dev, "Could not add gpiochip\n");
++              dev_err(dev, "Could not add gpiochip\n");
+               if (priv->domain)
+                       irq_domain_remove(priv->domain);
+               return err;
+       }
+-      dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
++      dev_info(dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
+                priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off");
+       return 0;
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-add-enable-disable-hot-join-in-sys-entry.patch b/queue-6.6/i3c-master-add-enable-disable-hot-join-in-sys-entry.patch
new file mode 100644 (file)
index 0000000..b9a7624
--- /dev/null
@@ -0,0 +1,159 @@
+From bb1cfc79ceb7defbe32db97cf3662821eabced56 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Dec 2023 17:25:27 -0500
+Subject: i3c: master: add enable(disable) hot join in sys entry
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 317bacf960a4879af22d12175f47d284930b3273 ]
+
+Add hotjoin entry in sys file system allow user enable/disable hotjoin
+feature.
+
+Add (*enable(disable)_hotjoin)() to i3c_master_controller_ops.
+Add api i3c_master_enable(disable)_hotjoin();
+
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20231201222532.2431484-2-Frank.Li@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master.c       | 83 ++++++++++++++++++++++++++++++++++++++
+ include/linux/i3c/master.h |  5 +++
+ 2 files changed, 88 insertions(+)
+
+diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
+index 70d120dfb0908..bbd5dc89be229 100644
+--- a/drivers/i3c/master.c
++++ b/drivers/i3c/master.c
+@@ -526,6 +526,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev,
+ }
+ static DEVICE_ATTR_RO(i2c_scl_frequency);
++static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
++{
++      int ret;
++
++      if (!master || !master->ops)
++              return -EINVAL;
++
++      if (!master->ops->enable_hotjoin || !master->ops->disable_hotjoin)
++              return -EINVAL;
++
++      i3c_bus_normaluse_lock(&master->bus);
++
++      if (enable)
++              ret = master->ops->enable_hotjoin(master);
++      else
++              ret = master->ops->disable_hotjoin(master);
++
++      master->hotjoin = enable;
++
++      i3c_bus_normaluse_unlock(&master->bus);
++
++      return ret;
++}
++
++static ssize_t hotjoin_store(struct device *dev, struct device_attribute *attr,
++                           const char *buf, size_t count)
++{
++      struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
++      int ret;
++      bool res;
++
++      if (!i3cbus->cur_master)
++              return -EINVAL;
++
++      if (kstrtobool(buf, &res))
++              return -EINVAL;
++
++      ret = i3c_set_hotjoin(i3cbus->cur_master->common.master, res);
++      if (ret)
++              return ret;
++
++      return count;
++}
++
++/*
++ * i3c_master_enable_hotjoin - Enable hotjoin
++ * @master: I3C master object
++ *
++ * Return: a 0 in case of success, an negative error code otherwise.
++ */
++int i3c_master_enable_hotjoin(struct i3c_master_controller *master)
++{
++      return i3c_set_hotjoin(master, true);
++}
++EXPORT_SYMBOL_GPL(i3c_master_enable_hotjoin);
++
++/*
++ * i3c_master_disable_hotjoin - Disable hotjoin
++ * @master: I3C master object
++ *
++ * Return: a 0 in case of success, an negative error code otherwise.
++ */
++int i3c_master_disable_hotjoin(struct i3c_master_controller *master)
++{
++      return i3c_set_hotjoin(master, false);
++}
++EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin);
++
++static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, char *buf)
++{
++      struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
++      ssize_t ret;
++
++      i3c_bus_normaluse_lock(i3cbus);
++      ret = sysfs_emit(buf, "%d\n", i3cbus->cur_master->common.master->hotjoin);
++      i3c_bus_normaluse_unlock(i3cbus);
++
++      return ret;
++}
++
++static DEVICE_ATTR_RW(hotjoin);
++
+ static struct attribute *i3c_masterdev_attrs[] = {
+       &dev_attr_mode.attr,
+       &dev_attr_current_master.attr,
+@@ -536,6 +618,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
+       &dev_attr_pid.attr,
+       &dev_attr_dynamic_address.attr,
+       &dev_attr_hdrcap.attr,
++      &dev_attr_hotjoin.attr,
+       NULL,
+ };
+ ATTRIBUTE_GROUPS(i3c_masterdev);
+diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
+index 0b52da4f23467..65b8965968af2 100644
+--- a/include/linux/i3c/master.h
++++ b/include/linux/i3c/master.h
+@@ -452,6 +452,8 @@ struct i3c_master_controller_ops {
+       int (*disable_ibi)(struct i3c_dev_desc *dev);
+       void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
+                                struct i3c_ibi_slot *slot);
++      int (*enable_hotjoin)(struct i3c_master_controller *master);
++      int (*disable_hotjoin)(struct i3c_master_controller *master);
+ };
+ /**
+@@ -487,6 +489,7 @@ struct i3c_master_controller {
+       const struct i3c_master_controller_ops *ops;
+       unsigned int secondary : 1;
+       unsigned int init_done : 1;
++      unsigned int hotjoin: 1;
+       struct {
+               struct list_head i3c;
+               struct list_head i2c;
+@@ -543,6 +546,8 @@ int i3c_master_register(struct i3c_master_controller *master,
+                       const struct i3c_master_controller_ops *ops,
+                       bool secondary);
+ void i3c_master_unregister(struct i3c_master_controller *master);
++int i3c_master_enable_hotjoin(struct i3c_master_controller *master);
++int i3c_master_disable_hotjoin(struct i3c_master_controller *master);
+ /**
+  * i3c_dev_get_master_data() - get master private data attached to an I3C
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-extend-address-status-bit-to-4-and-add-i3.patch b/queue-6.6/i3c-master-extend-address-status-bit-to-4-and-add-i3.patch
new file mode 100644 (file)
index 0000000..9e1908f
--- /dev/null
@@ -0,0 +1,197 @@
+From 9d585a4b26f05be49f34f3da16658d20781f0f7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Oct 2024 11:45:07 -0400
+Subject: i3c: master: Extend address status bit to 4 and add
+ I3C_ADDR_SLOT_EXT_DESIRED
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 2f552fa280590e61bd3dbe66a7b54b99caa642a4 ]
+
+Extend the address status bit to 4 and introduce the
+I3C_ADDR_SLOT_EXT_DESIRED macro to indicate that a device prefers a
+specific address. This is generally set by the 'assigned-address' in the
+device tree source (dts) file.
+
+ ┌────┬─────────────┬───┬─────────┬───┐
+ │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA  │ T ├────┐
+ └────┴─────────────┴───┴─────────┴───┘    │
+ ┌─────────────────────────────────────────┘
+ │  ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐
+ └─►│Sr│7'h7E RnW=1  │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│
+    └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘
+
+Some master controllers (such as HCI) need to prepare the entire above
+transaction before sending it out to the I3C bus. This means that a 7-bit
+dynamic address needs to be allocated before knowing the target device's
+UID information.
+
+However, some I3C targets may request specific addresses (called as
+"init_dyn_addr"), which is typically specified by the DT-'s
+assigned-address property. Lower addresses having higher IBI priority. If
+it is available, i3c_bus_get_free_addr() preferably return a free address
+that is not in the list of desired addresses (called as "init_dyn_addr").
+This allows the device with the "init_dyn_addr" to switch to its
+"init_dyn_addr" when it hot-joins the I3C bus. Otherwise, if the
+"init_dyn_addr" is already in use by another I3C device, the target device
+will not be able to switch to its desired address.
+
+If the previous step fails, fallback returning one of the remaining
+unassigned address, regardless of its state in the desired list.
+
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20241021-i3c_dts_assign-v8-2-4098b8bde01e@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 851bd21cdb55 ("i3c: master: Fix dynamic address leak when 'assigned-address' is present")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master.c       | 65 +++++++++++++++++++++++++++++++-------
+ include/linux/i3c/master.h |  7 ++--
+ 2 files changed, 59 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
+index 2b6bc03652139..d2a08a9a54414 100644
+--- a/drivers/i3c/master.c
++++ b/drivers/i3c/master.c
+@@ -342,7 +342,7 @@ struct bus_type i3c_bus_type = {
+ };
+ static enum i3c_addr_slot_status
+-i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
++i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask)
+ {
+       unsigned long status;
+       int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
+@@ -353,11 +353,17 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
+       status = bus->addrslots[bitpos / BITS_PER_LONG];
+       status >>= bitpos % BITS_PER_LONG;
+-      return status & I3C_ADDR_SLOT_STATUS_MASK;
++      return status & mask;
+ }
+-static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
+-                                       enum i3c_addr_slot_status status)
++static enum i3c_addr_slot_status
++i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
++{
++      return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK);
++}
++
++static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr,
++                                            enum i3c_addr_slot_status status, u32 mask)
+ {
+       int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
+       unsigned long *ptr;
+@@ -366,9 +372,14 @@ static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
+               return;
+       ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
+-      *ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK <<
+-                                              (bitpos % BITS_PER_LONG));
+-      *ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG);
++      *ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG));
++      *ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG);
++}
++
++static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
++                                       enum i3c_addr_slot_status status)
++{
++      i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK);
+ }
+ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
+@@ -380,13 +391,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
+       return status == I3C_ADDR_SLOT_FREE;
+ }
++/*
++ * ┌────┬─────────────┬───┬─────────┬───┐
++ * │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA  │ T ├────┐
++ * └────┴─────────────┴───┴─────────┴───┘    │
++ * ┌─────────────────────────────────────────┘
++ * │  ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐
++ * └─►│Sr│7'h7E RnW=1  │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│
++ *    └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘
++ * Some master controllers (such as HCI) need to prepare the entire above transaction before
++ * sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated
++ * before knowing the target device's UID information.
++ *
++ * However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is
++ * typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI
++ * priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is
++ * not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with
++ * the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise,
++ * if the "init_dyn_addr" is already in use by another I3C device, the target device will not be
++ * able to switch to its desired address.
++ *
++ * If the previous step fails, fallback returning one of the remaining unassigned address,
++ * regardless of its state in the desired list.
++ */
+ static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr)
+ {
+       enum i3c_addr_slot_status status;
+       u8 addr;
+       for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
+-              status = i3c_bus_get_addr_slot_status(bus, addr);
++              status = i3c_bus_get_addr_slot_status_mask(bus, addr,
++                                                         I3C_ADDR_SLOT_EXT_STATUS_MASK);
++              if (status == I3C_ADDR_SLOT_FREE)
++                      return addr;
++      }
++
++      for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
++              status = i3c_bus_get_addr_slot_status_mask(bus, addr,
++                                                         I3C_ADDR_SLOT_STATUS_MASK);
+               if (status == I3C_ADDR_SLOT_FREE)
+                       return addr;
+       }
+@@ -1877,9 +1919,10 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
+                       goto err_rstdaa;
+               }
+-              i3c_bus_set_addr_slot_status(&master->bus,
+-                                           i3cboardinfo->init_dyn_addr,
+-                                           I3C_ADDR_SLOT_I3C_DEV);
++              i3c_bus_set_addr_slot_status_mask(&master->bus,
++                                                i3cboardinfo->init_dyn_addr,
++                                                I3C_ADDR_SLOT_I3C_DEV | I3C_ADDR_SLOT_EXT_DESIRED,
++                                                I3C_ADDR_SLOT_EXT_STATUS_MASK);
+               /*
+                * Only try to create/attach devices that have a static
+diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
+index ed6b153481021..f2eb2452ffa5f 100644
+--- a/include/linux/i3c/master.h
++++ b/include/linux/i3c/master.h
+@@ -290,7 +290,8 @@ enum i3c_open_drain_speed {
+  * @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device
+  * @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device
+  * @I3C_ADDR_SLOT_STATUS_MASK: address slot mask
+- *
++ * @I3C_ADDR_SLOT_EXT_DESIRED: the bitmask represents addresses that are preferred by some devices,
++ *                           such as the "assigned-address" property in a device tree source.
+  * On an I3C bus, addresses are assigned dynamically, and we need to know which
+  * addresses are free to use and which ones are already assigned.
+  *
+@@ -303,9 +304,11 @@ enum i3c_addr_slot_status {
+       I3C_ADDR_SLOT_I2C_DEV,
+       I3C_ADDR_SLOT_I3C_DEV,
+       I3C_ADDR_SLOT_STATUS_MASK = 3,
++      I3C_ADDR_SLOT_EXT_STATUS_MASK = 7,
++      I3C_ADDR_SLOT_EXT_DESIRED = BIT(2),
+ };
+-#define I3C_ADDR_SLOT_STATUS_BITS 2
++#define I3C_ADDR_SLOT_STATUS_BITS 4
+ /**
+  * struct i3c_bus - I3C bus object
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch b/queue-6.6/i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch
new file mode 100644 (file)
index 0000000..e9ac1d7
--- /dev/null
@@ -0,0 +1,104 @@
+From 8bd2096f0d46d0300978f67165577286bfddb7c8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Oct 2024 11:45:08 -0400
+Subject: i3c: master: Fix dynamic address leak when 'assigned-address' is
+ present
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 851bd21cdb55e727ab29280bc9f6b678164f802a ]
+
+If the DTS contains 'assigned-address', a dynamic address leak occurs
+during hotjoin events.
+
+Assume a device have assigned-address 0xb.
+  - Device issue Hotjoin
+  - Call i3c_master_do_daa()
+  - Call driver xxx_do_daa()
+  - Call i3c_master_get_free_addr() to get dynamic address 0x9
+  - i3c_master_add_i3c_dev_locked(0x9)
+  -     expected_dyn_addr  = newdev->boardinfo->init_dyn_addr (0xb);
+  -     i3c_master_reattach_i3c_dev(newdev(0xb), old_dyn_addr(0x9));
+  -         if (dev->info.dyn_addr != old_dyn_addr &&
+                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0xb != 0x9 -> TRUE
+                (!dev->boardinfo ||
+                 ^^^^^^^^^^^^^^^ ->  FALSE
+                 dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) {
+                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+                 0xb != 0xb      ->  FALSE
+                 ...
+                 i3c_bus_set_addr_slot_status(&master->bus, old_dyn_addr,
+                                                     I3C_ADDR_SLOT_FREE);
+                ^^^
+                 This will be skipped. So old_dyn_addr never free
+            }
+
+  - i3c_master_get_free_addr() will return increased sequence number.
+
+Remove dev->info.dyn_addr != dev->boardinfo->init_dyn_addr condition check.
+dev->info.dyn_addr should be checked before calling this function because
+i3c_master_setnewda_locked() has already been called and the target device
+has already accepted dyn_addr. It is too late to check if dyn_addr is free
+in i3c_master_reattach_i3c_dev().
+
+Add check to ensure expected_dyn_addr is free before
+i3c_master_setnewda_locked().
+
+Fixes: cc3a392d69b6 ("i3c: master: fix for SETDASA and DAA process")
+Cc: stable@kernel.org
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20241021-i3c_dts_assign-v8-3-4098b8bde01e@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master.c | 15 +++++----------
+ 1 file changed, 5 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
+index d2a08a9a54414..5d737bdbfe478 100644
+--- a/drivers/i3c/master.c
++++ b/drivers/i3c/master.c
+@@ -1507,16 +1507,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
+                                      u8 old_dyn_addr)
+ {
+       struct i3c_master_controller *master = i3c_dev_get_master(dev);
+-      enum i3c_addr_slot_status status;
+       int ret;
+-      if (dev->info.dyn_addr != old_dyn_addr &&
+-          (!dev->boardinfo ||
+-           dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) {
+-              status = i3c_bus_get_addr_slot_status(&master->bus,
+-                                                    dev->info.dyn_addr);
+-              if (status != I3C_ADDR_SLOT_FREE)
+-                      return -EBUSY;
++      if (dev->info.dyn_addr != old_dyn_addr) {
+               i3c_bus_set_addr_slot_status(&master->bus,
+                                            dev->info.dyn_addr,
+                                            I3C_ADDR_SLOT_I3C_DEV);
+@@ -1919,9 +1912,10 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
+                       goto err_rstdaa;
+               }
++              /* Do not mark as occupied until real device exist in bus */
+               i3c_bus_set_addr_slot_status_mask(&master->bus,
+                                                 i3cboardinfo->init_dyn_addr,
+-                                                I3C_ADDR_SLOT_I3C_DEV | I3C_ADDR_SLOT_EXT_DESIRED,
++                                                I3C_ADDR_SLOT_EXT_DESIRED,
+                                                 I3C_ADDR_SLOT_EXT_STATUS_MASK);
+               /*
+@@ -2085,7 +2079,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
+       else
+               expected_dyn_addr = newdev->info.dyn_addr;
+-      if (newdev->info.dyn_addr != expected_dyn_addr) {
++      if (newdev->info.dyn_addr != expected_dyn_addr &&
++          i3c_bus_get_addr_slot_status(&master->bus, expected_dyn_addr) == I3C_ADDR_SLOT_FREE) {
+               /*
+                * Try to apply the expected dynamic address. If it fails, keep
+                * the address assigned by the master.
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-fix-kernel-doc-check-warning.patch b/queue-6.6/i3c-master-fix-kernel-doc-check-warning.patch
new file mode 100644 (file)
index 0000000..cb08faf
--- /dev/null
@@ -0,0 +1,50 @@
+From 6b70fb834f8fa3e49b9d0fce093cd47b90d6057f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Jan 2024 00:25:48 -0500
+Subject: i3c: master: fix kernel-doc check warning
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 34d946b723b53488ab39d8ac540ddf9db255317a ]
+
+Fix warning found by
+       'scripts/kernel-doc -v -none include/linux/i3c/master.h'
+
+include/linux/i3c/master.h:457: warning: Function parameter or member 'enable_hotjoin' not described in 'i3c_master_controller_ops'
+include/linux/i3c/master.h:457: warning: Function parameter or member 'disable_hotjoin' not described in 'i3c_master_controller_ops'
+include/linux/i3c/master.h:499: warning: Function parameter or member 'hotjoin' not described in 'i3c_master_controller'
+
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/r/20240109052548.2128133-1-Frank.Li@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/i3c/master.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
+index 65b8965968af2..1cbf0baca65fe 100644
+--- a/include/linux/i3c/master.h
++++ b/include/linux/i3c/master.h
+@@ -426,6 +426,8 @@ struct i3c_bus {
+  *                  for a future IBI
+  *                  This method is mandatory only if ->request_ibi is not
+  *                  NULL.
++ * @enable_hotjoin: enable hot join event detect.
++ * @disable_hotjoin: disable hot join event detect.
+  */
+ struct i3c_master_controller_ops {
+       int (*bus_init)(struct i3c_master_controller *master);
+@@ -467,6 +469,7 @@ struct i3c_master_controller_ops {
+  * @ops: master operations. See &struct i3c_master_controller_ops
+  * @secondary: true if the master is a secondary master
+  * @init_done: true when the bus initialization is done
++ * @hotjoin: true if the master support hotjoin
+  * @boardinfo.i3c: list of I3C  boardinfo objects
+  * @boardinfo.i2c: list of I2C boardinfo objects
+  * @boardinfo: board-level information attached to devices connected on the bus
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch b/queue-6.6/i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch
new file mode 100644 (file)
index 0000000..58271c6
--- /dev/null
@@ -0,0 +1,72 @@
+From 05199ecbf1aac4835dd62c110407083df6113bd3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Oct 2024 11:45:06 -0400
+Subject: i3c: master: Replace hard code 2 with macro I3C_ADDR_SLOT_STATUS_BITS
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 16aed0a6520ba01b7d22c32e193fc1ec674f92d4 ]
+
+Replace the hardcoded value 2, which indicates 2 bits for I3C address
+status, with the predefined macro I3C_ADDR_SLOT_STATUS_BITS.
+
+Improve maintainability and extensibility of the code.
+
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20241021-i3c_dts_assign-v8-1-4098b8bde01e@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 851bd21cdb55 ("i3c: master: Fix dynamic address leak when 'assigned-address' is present")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master.c       | 4 ++--
+ include/linux/i3c/master.h | 4 +++-
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
+index 78171a754a3f8..2b6bc03652139 100644
+--- a/drivers/i3c/master.c
++++ b/drivers/i3c/master.c
+@@ -345,7 +345,7 @@ static enum i3c_addr_slot_status
+ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
+ {
+       unsigned long status;
+-      int bitpos = addr * 2;
++      int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
+       if (addr > I2C_MAX_ADDR)
+               return I3C_ADDR_SLOT_RSVD;
+@@ -359,7 +359,7 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
+ static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
+                                        enum i3c_addr_slot_status status)
+ {
+-      int bitpos = addr * 2;
++      int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
+       unsigned long *ptr;
+       if (addr > I2C_MAX_ADDR)
+diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
+index f0aa4c549aa7f..ed6b153481021 100644
+--- a/include/linux/i3c/master.h
++++ b/include/linux/i3c/master.h
+@@ -305,6 +305,8 @@ enum i3c_addr_slot_status {
+       I3C_ADDR_SLOT_STATUS_MASK = 3,
+ };
++#define I3C_ADDR_SLOT_STATUS_BITS 2
++
+ /**
+  * struct i3c_bus - I3C bus object
+  * @cur_master: I3C master currently driving the bus. Since I3C is multi-master
+@@ -346,7 +348,7 @@ enum i3c_addr_slot_status {
+ struct i3c_bus {
+       struct i3c_dev_desc *cur_master;
+       int id;
+-      unsigned long addrslots[((I2C_MAX_ADDR + 1) * 2) / BITS_PER_LONG];
++      unsigned long addrslots[((I2C_MAX_ADDR + 1) * I3C_ADDR_SLOT_STATUS_BITS) / BITS_PER_LONG];
+       enum i3c_bus_mode mode;
+       struct {
+               unsigned long i3c;
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-support-to-adjust-first-broadcast-address.patch b/queue-6.6/i3c-master-support-to-adjust-first-broadcast-address.patch
new file mode 100644 (file)
index 0000000..143eda6
--- /dev/null
@@ -0,0 +1,101 @@
+From 9941ab62d3766426b1b56b7260a8049bcc7559ef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Sep 2024 13:16:25 +0800
+Subject: i3c: master: support to adjust first broadcast address speed
+
+From: Carlos Song <carlos.song@nxp.com>
+
+[ Upstream commit aef79e189ba2b32f78bd35daf2c0b41f3868a321 ]
+
+According to I3C spec 6.2 Timing Specification, the Open Drain High Period
+of SCL Clock timing for first broadcast address should be adjusted to 200ns
+at least. I3C device working as i2c device will see the broadcast to close
+its Spike Filter then change to work at I3C mode. After that I3C open drain
+SCL high level should be adjusted back.
+
+Signed-off-by: Carlos Song <carlos.song@nxp.com>
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20240910051626.4052552-1-carlos.song@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master.c       | 12 ++++++++++++
+ include/linux/i3c/master.h | 16 ++++++++++++++++
+ 2 files changed, 28 insertions(+)
+
+diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
+index bbd5dc89be229..78171a754a3f8 100644
+--- a/drivers/i3c/master.c
++++ b/drivers/i3c/master.c
+@@ -1827,6 +1827,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
+               goto err_bus_cleanup;
+       }
++      if (master->ops->set_speed) {
++              ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED);
++              if (ret)
++                      goto err_bus_cleanup;
++      }
++
+       /*
+        * Reset all dynamic address that may have been assigned before
+        * (assigned by the bootloader for example).
+@@ -1835,6 +1841,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
+       if (ret && ret != I3C_ERROR_M2)
+               goto err_bus_cleanup;
++      if (master->ops->set_speed) {
++              master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED);
++              if (ret)
++                      goto err_bus_cleanup;
++      }
++
+       /* Disable all slave events before starting DAA. */
+       ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
+                                     I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
+diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
+index 1cbf0baca65fe..f0aa4c549aa7f 100644
+--- a/include/linux/i3c/master.h
++++ b/include/linux/i3c/master.h
+@@ -269,6 +269,20 @@ enum i3c_bus_mode {
+       I3C_BUS_MODE_MIXED_SLOW,
+ };
++/**
++ * enum i3c_open_drain_speed - I3C open-drain speed
++ * @I3C_OPEN_DRAIN_SLOW_SPEED: Slow open-drain speed for sending the first
++ *                            broadcast address. The first broadcast address at this speed
++ *                            will be visible to all devices on the I3C bus. I3C devices
++ *                            working in I2C mode will turn off their spike filter when
++ *                            switching into I3C mode.
++ * @I3C_OPEN_DRAIN_NORMAL_SPEED: Normal open-drain speed in I3C bus mode.
++ */
++enum i3c_open_drain_speed {
++      I3C_OPEN_DRAIN_SLOW_SPEED,
++      I3C_OPEN_DRAIN_NORMAL_SPEED,
++};
++
+ /**
+  * enum i3c_addr_slot_status - I3C address slot status
+  * @I3C_ADDR_SLOT_FREE: address is free
+@@ -428,6 +442,7 @@ struct i3c_bus {
+  *                  NULL.
+  * @enable_hotjoin: enable hot join event detect.
+  * @disable_hotjoin: disable hot join event detect.
++ * @set_speed: adjust I3C open drain mode timing.
+  */
+ struct i3c_master_controller_ops {
+       int (*bus_init)(struct i3c_master_controller *master);
+@@ -456,6 +471,7 @@ struct i3c_master_controller_ops {
+                                struct i3c_ibi_slot *slot);
+       int (*enable_hotjoin)(struct i3c_master_controller *master);
+       int (*disable_hotjoin)(struct i3c_master_controller *master);
++      int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed);
+ };
+ /**
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-svc-add-hot-join-support.patch b/queue-6.6/i3c-master-svc-add-hot-join-support.patch
new file mode 100644 (file)
index 0000000..eee164f
--- /dev/null
@@ -0,0 +1,165 @@
+From 0a946b7a1c1b94c3473ef41ff7e2582b451701da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Dec 2023 17:25:28 -0500
+Subject: i3c: master: svc: add hot join support
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 05b26c31a4859af9e75b7de77458e99358364fe1 ]
+
+Add hot join support for svc master controller. Disable hot join by
+default.
+User can use sysfs entry to enable hot join.
+
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20231201222532.2431484-3-Frank.Li@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master/svc-i3c-master.c | 61 +++++++++++++++++++++++++++--
+ 1 file changed, 57 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
+index dca266d9dd122..139b51a575366 100644
+--- a/drivers/i3c/master/svc-i3c-master.c
++++ b/drivers/i3c/master/svc-i3c-master.c
+@@ -128,6 +128,9 @@
+ /* This parameter depends on the implementation and may be tuned */
+ #define SVC_I3C_FIFO_SIZE 16
++#define SVC_I3C_EVENT_IBI     BIT(0)
++#define SVC_I3C_EVENT_HOTJOIN BIT(1)
++
+ struct svc_i3c_cmd {
+       u8 addr;
+       bool rnw;
+@@ -178,6 +181,7 @@ struct svc_i3c_regs_save {
+  * @ibi.tbq_slot: To be queued IBI slot
+  * @ibi.lock: IBI lock
+  * @lock: Transfer lock, protect between IBI work thread and callbacks from master
++ * @enabled_events: Bit masks for enable events (IBI, HotJoin).
+  */
+ struct svc_i3c_master {
+       struct i3c_master_controller base;
+@@ -207,6 +211,7 @@ struct svc_i3c_master {
+               spinlock_t lock;
+       } ibi;
+       struct mutex lock;
++      int enabled_events;
+ };
+ /**
+@@ -221,6 +226,11 @@ struct svc_i3c_i2c_dev_data {
+       struct i3c_generic_ibi_pool *ibi_pool;
+ };
++static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask)
++{
++      return !!(master->enabled_events & mask);
++}
++
+ static bool svc_i3c_master_error(struct svc_i3c_master *master)
+ {
+       u32 mstatus, merrwarn;
+@@ -440,13 +450,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
+       switch (ibitype) {
+       case SVC_I3C_MSTATUS_IBITYPE_IBI:
+               dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
+-              if (!dev)
++              if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
+                       svc_i3c_master_nack_ibi(master);
+               else
+                       svc_i3c_master_handle_ibi(master, dev);
+               break;
+       case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
+-              svc_i3c_master_ack_ibi(master, false);
++              if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
++                      svc_i3c_master_ack_ibi(master, false);
++              else
++                      svc_i3c_master_nack_ibi(master);
+               break;
+       case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+               svc_i3c_master_nack_ibi(master);
+@@ -483,7 +496,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
+               svc_i3c_master_emit_stop(master);
+               break;
+       case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
+-              queue_work(master->base.wq, &master->hj_work);
++              svc_i3c_master_emit_stop(master);
++              if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
++                      queue_work(master->base.wq, &master->hj_work);
+               break;
+       case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+       default:
+@@ -1520,6 +1535,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
+               return ret;
+       }
++      master->enabled_events |= SVC_I3C_EVENT_IBI;
+       svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
+       return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+@@ -1531,7 +1547,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
+       struct svc_i3c_master *master = to_svc_i3c_master(m);
+       int ret;
+-      svc_i3c_master_disable_interrupts(master);
++      master->enabled_events &= ~SVC_I3C_EVENT_IBI;
++      if (!master->enabled_events)
++              svc_i3c_master_disable_interrupts(master);
+       ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+@@ -1541,6 +1559,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
+       return ret;
+ }
++static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
++{
++      struct svc_i3c_master *master = to_svc_i3c_master(m);
++      int ret;
++
++      ret = pm_runtime_resume_and_get(master->dev);
++      if (ret < 0) {
++              dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
++              return ret;
++      }
++
++      master->enabled_events |= SVC_I3C_EVENT_HOTJOIN;
++
++      svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
++
++      return 0;
++}
++
++static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
++{
++      struct svc_i3c_master *master = to_svc_i3c_master(m);
++
++      master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN;
++
++      if (!master->enabled_events)
++              svc_i3c_master_disable_interrupts(master);
++
++      pm_runtime_mark_last_busy(master->dev);
++      pm_runtime_put_autosuspend(master->dev);
++
++      return 0;
++}
++
+ static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
+                                           struct i3c_ibi_slot *slot)
+ {
+@@ -1567,6 +1618,8 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
+       .recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot,
+       .enable_ibi = svc_i3c_master_enable_ibi,
+       .disable_ibi = svc_i3c_master_disable_ibi,
++      .enable_hotjoin = svc_i3c_master_enable_hotjoin,
++      .disable_hotjoin = svc_i3c_master_disable_hotjoin,
+ };
+ static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch b/queue-6.6/i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch
new file mode 100644 (file)
index 0000000..c4de59d
--- /dev/null
@@ -0,0 +1,71 @@
+From d8047b227b244170788bf808b11850c550b2687c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Nov 2024 12:50:02 -0400
+Subject: i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable
+ counter
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 25bc99be5fe53853053ceeaa328068c49dc1e799 ]
+
+Fix issue where disabling IBI on one device disables the entire IBI
+interrupt. Modify bit 7:0 of enabled_events to serve as an IBI enable
+counter, ensuring that the system IBI interrupt is disabled only when all
+I3C devices have IBI disabled.
+
+Cc: stable@kernel.org
+Fixes: 7ff730ca458e ("i3c: master: svc: enable the interrupt in the enable ibi function")
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20241101165002.2479794-1-Frank.Li@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master/svc-i3c-master.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
+index 97d03d755a61f..77bc0db17fc6f 100644
+--- a/drivers/i3c/master/svc-i3c-master.c
++++ b/drivers/i3c/master/svc-i3c-master.c
+@@ -128,8 +128,8 @@
+ /* This parameter depends on the implementation and may be tuned */
+ #define SVC_I3C_FIFO_SIZE 16
+-#define SVC_I3C_EVENT_IBI     BIT(0)
+-#define SVC_I3C_EVENT_HOTJOIN BIT(1)
++#define SVC_I3C_EVENT_IBI     GENMASK(7, 0)
++#define SVC_I3C_EVENT_HOTJOIN BIT(31)
+ struct svc_i3c_cmd {
+       u8 addr;
+@@ -212,7 +212,7 @@ struct svc_i3c_master {
+               spinlock_t lock;
+       } ibi;
+       struct mutex lock;
+-      int enabled_events;
++      u32 enabled_events;
+       u32 mctrl_config;
+ };
+@@ -1586,7 +1586,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
+               return ret;
+       }
+-      master->enabled_events |= SVC_I3C_EVENT_IBI;
++      master->enabled_events++;
+       svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
+       return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+@@ -1598,7 +1598,7 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
+       struct svc_i3c_master *master = to_svc_i3c_master(m);
+       int ret;
+-      master->enabled_events &= ~SVC_I3C_EVENT_IBI;
++      master->enabled_events--;
+       if (!master->enabled_events)
+               svc_i3c_master_disable_interrupts(master);
+-- 
+2.43.0
+
diff --git a/queue-6.6/i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch b/queue-6.6/i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch
new file mode 100644 (file)
index 0000000..636145e
--- /dev/null
@@ -0,0 +1,117 @@
+From 437724003fdaf6d9b0bf16895fc182f178249b67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Sep 2024 13:16:26 +0800
+Subject: i3c: master: svc: use slow speed for first broadcast address
+
+From: Carlos Song <carlos.song@nxp.com>
+
+[ Upstream commit 20ade67bb1645f5ce8f37fa79ddfebbc5b5b24ef ]
+
+I3C controller should support adjusting open drain timing for the first
+broadcast address to make I3C device working as a i2c device can see slow
+broadcast address to close its Spike Filter to change working at i3c mode.
+
+Signed-off-by: Carlos Song <carlos.song@nxp.com>
+Reviewed-by: Frank Li <frank.li@nxp.com>
+Link: https://lore.kernel.org/r/20240910051626.4052552-2-carlos.song@nxp.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i3c/master/svc-i3c-master.c | 52 +++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
+index 139b51a575366..97d03d755a61f 100644
+--- a/drivers/i3c/master/svc-i3c-master.c
++++ b/drivers/i3c/master/svc-i3c-master.c
+@@ -182,6 +182,7 @@ struct svc_i3c_regs_save {
+  * @ibi.lock: IBI lock
+  * @lock: Transfer lock, protect between IBI work thread and callbacks from master
+  * @enabled_events: Bit masks for enable events (IBI, HotJoin).
++ * @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back.
+  */
+ struct svc_i3c_master {
+       struct i3c_master_controller base;
+@@ -212,6 +213,7 @@ struct svc_i3c_master {
+       } ibi;
+       struct mutex lock;
+       int enabled_events;
++      u32 mctrl_config;
+ };
+ /**
+@@ -529,6 +531,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
+       return IRQ_HANDLED;
+ }
++static int svc_i3c_master_set_speed(struct i3c_master_controller *m,
++                                   enum i3c_open_drain_speed speed)
++{
++      struct svc_i3c_master *master = to_svc_i3c_master(m);
++      struct i3c_bus *bus = i3c_master_get_bus(&master->base);
++      u32 ppbaud, odbaud, odhpp, mconfig;
++      unsigned long fclk_rate;
++      int ret;
++
++      ret = pm_runtime_resume_and_get(master->dev);
++      if (ret < 0) {
++              dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
++              return ret;
++      }
++
++      switch (speed) {
++      case I3C_OPEN_DRAIN_SLOW_SPEED:
++              fclk_rate = clk_get_rate(master->fclk);
++              if (!fclk_rate) {
++                      ret = -EINVAL;
++                      goto rpm_out;
++              }
++              /*
++               * Set 50% duty-cycle I2C speed to I3C OPEN-DRAIN mode, so the first
++               * broadcast address is visible to all I2C/I3C devices on the I3C bus.
++               * I3C device working as a I2C device will turn off its 50ns Spike
++               * Filter to change to I3C mode.
++               */
++              mconfig = master->mctrl_config;
++              ppbaud = FIELD_GET(GENMASK(11, 8), mconfig);
++              odhpp = 0;
++              odbaud = DIV_ROUND_UP(fclk_rate, bus->scl_rate.i2c * (2 + 2 * ppbaud)) - 1;
++              mconfig &= ~GENMASK(24, 16);
++              mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) | SVC_I3C_MCONFIG_ODHPP(odhpp);
++              writel(mconfig, master->regs + SVC_I3C_MCONFIG);
++              break;
++      case I3C_OPEN_DRAIN_NORMAL_SPEED:
++              writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
++              break;
++      }
++
++rpm_out:
++      pm_runtime_mark_last_busy(master->dev);
++      pm_runtime_put_autosuspend(master->dev);
++
++      return ret;
++}
++
+ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
+ {
+       struct svc_i3c_master *master = to_svc_i3c_master(m);
+@@ -611,6 +661,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
+             SVC_I3C_MCONFIG_I2CBAUD(i2cbaud);
+       writel(reg, master->regs + SVC_I3C_MCONFIG);
++      master->mctrl_config = reg;
+       /* Master core's registration */
+       ret = i3c_master_get_free_addr(m, 0);
+       if (ret < 0)
+@@ -1620,6 +1671,7 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
+       .disable_ibi = svc_i3c_master_disable_ibi,
+       .enable_hotjoin = svc_i3c_master_enable_hotjoin,
+       .disable_hotjoin = svc_i3c_master_disable_hotjoin,
++      .set_speed = svc_i3c_master_set_speed,
+ };
+ static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
+-- 
+2.43.0
+
diff --git a/queue-6.6/igb-fix-potential-invalid-memory-access-in-igb_init_.patch b/queue-6.6/igb-fix-potential-invalid-memory-access-in-igb_init_.patch
new file mode 100644 (file)
index 0000000..5ae7ed6
--- /dev/null
@@ -0,0 +1,40 @@
+From 2e196081539e223a9d4f88fedb176bb00a1a1d31 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Oct 2024 20:10:48 +0800
+Subject: igb: Fix potential invalid memory access in igb_init_module()
+
+From: Yuan Can <yuancan@huawei.com>
+
+[ Upstream commit 0566f83d206c7a864abcd741fe39d6e0ae5eef29 ]
+
+The pci_register_driver() can fail and when this happened, the dca_notifier
+needs to be unregistered, otherwise the dca_notifier can be called when
+igb fails to install, resulting to invalid memory access.
+
+Fixes: bbd98fe48a43 ("igb: Fix DCA errors and do not use context index for 82576")
+Signed-off-by: Yuan Can <yuancan@huawei.com>
+Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/igb/igb_main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
+index 49b349fa22542..c38be2880efcf 100644
+--- a/drivers/net/ethernet/intel/igb/igb_main.c
++++ b/drivers/net/ethernet/intel/igb/igb_main.c
+@@ -665,6 +665,10 @@ static int __init igb_init_module(void)
+       dca_register_notify(&dca_notifier);
+ #endif
+       ret = pci_register_driver(&igb_driver);
++#ifdef CONFIG_IGB_DCA
++      if (ret)
++              dca_unregister_notify(&dca_notifier);
++#endif
+       return ret;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/iommu-add-iommu_ops-identity_domain.patch b/queue-6.6/iommu-add-iommu_ops-identity_domain.patch
new file mode 100644 (file)
index 0000000..a3a3147
--- /dev/null
@@ -0,0 +1,147 @@
+From b0a7b2647cf144cc009330beba9e75dbc2249a91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Sep 2023 10:43:34 -0300
+Subject: iommu: Add iommu_ops->identity_domain
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit df31b298477e65a01deff0af352be3a61524d930 ]
+
+This allows a driver to set a global static to an IDENTITY domain and
+the core code will automatically use it whenever an IDENTITY domain
+is requested.
+
+By making it always available it means the IDENTITY can be used in error
+handling paths to force the iommu driver into a known state. Devices
+implementing global static identity domains should avoid failing their
+attach_dev ops.
+
+To make global static domains simpler allow drivers to omit their free
+function and update the iommufd selftest.
+
+Convert rockchip to use the new mechanism.
+
+Tested-by: Steven Price <steven.price@arm.com>
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Tested-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/1-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Stable-dep-of: 229e6ee43d2a ("iommu/arm-smmu: Defer probe of clients after smmu device bound")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/iommu.c            | 6 +++++-
+ drivers/iommu/iommufd/selftest.c | 5 -----
+ drivers/iommu/rockchip-iommu.c   | 9 +--------
+ include/linux/iommu.h            | 3 +++
+ 4 files changed, 9 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
+index 3f1029c0825e9..e97299987d43f 100644
+--- a/drivers/iommu/iommu.c
++++ b/drivers/iommu/iommu.c
+@@ -1979,6 +1979,9 @@ static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus,
+       if (bus == NULL || bus->iommu_ops == NULL)
+               return NULL;
++      if (alloc_type == IOMMU_DOMAIN_IDENTITY && bus->iommu_ops->identity_domain)
++              return bus->iommu_ops->identity_domain;
++
+       domain = bus->iommu_ops->domain_alloc(alloc_type);
+       if (!domain)
+               return NULL;
+@@ -2012,7 +2015,8 @@ void iommu_domain_free(struct iommu_domain *domain)
+       if (domain->type == IOMMU_DOMAIN_SVA)
+               mmdrop(domain->mm);
+       iommu_put_dma_cookie(domain);
+-      domain->ops->free(domain);
++      if (domain->ops->free)
++              domain->ops->free(domain);
+ }
+ EXPORT_SYMBOL_GPL(iommu_domain_free);
+diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c
+index 00b794d74e03b..d29e438377405 100644
+--- a/drivers/iommu/iommufd/selftest.c
++++ b/drivers/iommu/iommufd/selftest.c
+@@ -126,10 +126,6 @@ struct selftest_obj {
+       };
+ };
+-static void mock_domain_blocking_free(struct iommu_domain *domain)
+-{
+-}
+-
+ static int mock_domain_nop_attach(struct iommu_domain *domain,
+                                 struct device *dev)
+ {
+@@ -137,7 +133,6 @@ static int mock_domain_nop_attach(struct iommu_domain *domain,
+ }
+ static const struct iommu_domain_ops mock_blocking_ops = {
+-      .free = mock_domain_blocking_free,
+       .attach_dev = mock_domain_nop_attach,
+ };
+diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
+index 8ff69fbf9f65d..033678f2f8b3a 100644
+--- a/drivers/iommu/rockchip-iommu.c
++++ b/drivers/iommu/rockchip-iommu.c
+@@ -989,13 +989,8 @@ static int rk_iommu_identity_attach(struct iommu_domain *identity_domain,
+       return 0;
+ }
+-static void rk_iommu_identity_free(struct iommu_domain *domain)
+-{
+-}
+-
+ static struct iommu_domain_ops rk_identity_ops = {
+       .attach_dev = rk_iommu_identity_attach,
+-      .free = rk_iommu_identity_free,
+ };
+ static struct iommu_domain rk_identity_domain = {
+@@ -1059,9 +1054,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
+ {
+       struct rk_iommu_domain *rk_domain;
+-      if (type == IOMMU_DOMAIN_IDENTITY)
+-              return &rk_identity_domain;
+-
+       if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
+               return NULL;
+@@ -1186,6 +1178,7 @@ static int rk_iommu_of_xlate(struct device *dev,
+ }
+ static const struct iommu_ops rk_iommu_ops = {
++      .identity_domain = &rk_identity_domain,
+       .domain_alloc = rk_iommu_domain_alloc,
+       .probe_device = rk_iommu_probe_device,
+       .release_device = rk_iommu_release_device,
+diff --git a/include/linux/iommu.h b/include/linux/iommu.h
+index b6ef263e85c06..0274d12a48e1b 100644
+--- a/include/linux/iommu.h
++++ b/include/linux/iommu.h
+@@ -260,6 +260,8 @@ struct iommu_iotlb_gather {
+  *                    will be blocked by the hardware.
+  * @pgsize_bitmap: bitmap of all possible supported page sizes
+  * @owner: Driver module providing these ops
++ * @identity_domain: An always available, always attachable identity
++ *                   translation.
+  */
+ struct iommu_ops {
+       bool (*capable)(struct device *dev, enum iommu_cap);
+@@ -294,6 +296,7 @@ struct iommu_ops {
+       const struct iommu_domain_ops *default_domain_ops;
+       unsigned long pgsize_bitmap;
+       struct module *owner;
++      struct iommu_domain *identity_domain;
+ };
+ /**
+-- 
+2.43.0
+
diff --git a/queue-6.6/iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch b/queue-6.6/iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch
new file mode 100644 (file)
index 0000000..03116ae
--- /dev/null
@@ -0,0 +1,86 @@
+From 62dc845a353efab2254480df8ae7d06175627313 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Oct 2024 14:34:28 +0530
+Subject: iommu/arm-smmu: Defer probe of clients after smmu device bound
+
+From: Pratyush Brahma <quic_pbrahma@quicinc.com>
+
+[ Upstream commit 229e6ee43d2a160a1592b83aad620d6027084aad ]
+
+Null pointer dereference occurs due to a race between smmu
+driver probe and client driver probe, when of_dma_configure()
+for client is called after the iommu_device_register() for smmu driver
+probe has executed but before the driver_bound() for smmu driver
+has been called.
+
+Following is how the race occurs:
+
+T1:Smmu device probe           T2: Client device probe
+
+really_probe()
+arm_smmu_device_probe()
+iommu_device_register()
+                                       really_probe()
+                                       platform_dma_configure()
+                                       of_dma_configure()
+                                       of_dma_configure_id()
+                                       of_iommu_configure()
+                                       iommu_probe_device()
+                                       iommu_init_device()
+                                       arm_smmu_probe_device()
+                                       arm_smmu_get_by_fwnode()
+                                               driver_find_device_by_fwnode()
+                                               driver_find_device()
+                                               next_device()
+                                               klist_next()
+                                                   /* null ptr
+                                                      assigned to smmu */
+                                       /* null ptr dereference
+                                          while smmu->streamid_mask */
+driver_bound()
+       klist_add_tail()
+
+When this null smmu pointer is dereferenced later in
+arm_smmu_probe_device, the device crashes.
+
+Fix this by deferring the probe of the client device
+until the smmu device has bound to the arm smmu driver.
+
+Fixes: 021bb8420d44 ("iommu/arm-smmu: Wire up generic configuration support")
+Cc: stable@vger.kernel.org
+Co-developed-by: Prakash Gupta <quic_guptap@quicinc.com>
+Signed-off-by: Prakash Gupta <quic_guptap@quicinc.com>
+Signed-off-by: Pratyush Brahma <quic_pbrahma@quicinc.com>
+Link: https://lore.kernel.org/r/20241004090428.2035-1-quic_pbrahma@quicinc.com
+[will: Add comment]
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu/arm-smmu.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
+index 8203a06014d71..b40ffa1ec2db6 100644
+--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
+@@ -1354,6 +1354,17 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
+                       goto out_free;
+       } else {
+               smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
++
++              /*
++               * Defer probe if the relevant SMMU instance hasn't finished
++               * probing yet. This is a fragile hack and we'd ideally
++               * avoid this race in the core code. Until that's ironed
++               * out, however, this is the most pragmatic option on the
++               * table.
++               */
++              if (!smmu)
++                      return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER,
++                                              "smmu dev has not bound yet\n"));
+       }
+       ret = -EINVAL;
+-- 
+2.43.0
+
diff --git a/queue-6.6/iommu-clean-up-open-coded-ownership-checks.patch b/queue-6.6/iommu-clean-up-open-coded-ownership-checks.patch
new file mode 100644 (file)
index 0000000..1903d6e
--- /dev/null
@@ -0,0 +1,194 @@
+From 302639dd441533017096f8ebccb02440090fb09d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Nov 2023 18:04:03 +0000
+Subject: iommu: Clean up open-coded ownership checks
+
+From: Robin Murphy <robin.murphy@arm.com>
+
+[ Upstream commit e7080665c977ea1aafb8547a9c7bd08b199311d6 ]
+
+Some drivers already implement their own defence against the possibility
+of being given someone else's device. Since this is now taken care of by
+the core code (and via a slightly different path from the original
+fwspec-based idea), let's clean them up.
+
+Acked-by: Will Deacon <will@kernel.org>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Link: https://lore.kernel.org/r/58a9879ce3f03562bb061e6714fe6efb554c3907.1700589539.git.robin.murphy@arm.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Stable-dep-of: 229e6ee43d2a ("iommu/arm-smmu: Defer probe of clients after smmu device bound")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c |  3 ---
+ drivers/iommu/arm/arm-smmu/arm-smmu.c       |  9 +--------
+ drivers/iommu/arm/arm-smmu/qcom_iommu.c     | 16 +++-------------
+ drivers/iommu/mtk_iommu.c                   |  7 +------
+ drivers/iommu/mtk_iommu_v1.c                |  3 ---
+ drivers/iommu/sprd-iommu.c                  |  8 +-------
+ drivers/iommu/virtio-iommu.c                |  3 ---
+ 7 files changed, 6 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index 68b81f9c2f4b1..c24584754d252 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -2658,9 +2658,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
+       struct arm_smmu_master *master;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+-      if (!fwspec || fwspec->ops != &arm_smmu_ops)
+-              return ERR_PTR(-ENODEV);
+-
+       if (WARN_ON_ONCE(dev_iommu_priv_get(dev)))
+               return ERR_PTR(-EBUSY);
+diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
+index d6d1a2a55cc06..8203a06014d71 100644
+--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
+@@ -1116,11 +1116,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
+       struct arm_smmu_device *smmu;
+       int ret;
+-      if (!fwspec || fwspec->ops != &arm_smmu_ops) {
+-              dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
+-              return -ENXIO;
+-      }
+-
+       /*
+        * FIXME: The arch/arm DMA API code tries to attach devices to its own
+        * domains between of_xlate() and probe_device() - we have no way to cope
+@@ -1357,10 +1352,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
+               fwspec = dev_iommu_fwspec_get(dev);
+               if (ret)
+                       goto out_free;
+-      } else if (fwspec && fwspec->ops == &arm_smmu_ops) {
+-              smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
+       } else {
+-              return ERR_PTR(-ENODEV);
++              smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
+       }
+       ret = -EINVAL;
+diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+index bc45d18f350cb..3b8c4b33842d1 100644
+--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+@@ -79,16 +79,6 @@ static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom)
+ static const struct iommu_ops qcom_iommu_ops;
+-static struct qcom_iommu_dev * to_iommu(struct device *dev)
+-{
+-      struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+-
+-      if (!fwspec || fwspec->ops != &qcom_iommu_ops)
+-              return NULL;
+-
+-      return dev_iommu_priv_get(dev);
+-}
+-
+ static struct qcom_iommu_ctx * to_ctx(struct qcom_iommu_domain *d, unsigned asid)
+ {
+       struct qcom_iommu_dev *qcom_iommu = d->iommu;
+@@ -374,7 +364,7 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain)
+ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+ {
+-      struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
++      struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
+       struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
+       int ret;
+@@ -406,7 +396,7 @@ static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain,
+       struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+       struct qcom_iommu_domain *qcom_domain;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+-      struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
++      struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
+       unsigned int i;
+       if (domain == identity_domain || !domain)
+@@ -537,7 +527,7 @@ static bool qcom_iommu_capable(struct device *dev, enum iommu_cap cap)
+ static struct iommu_device *qcom_iommu_probe_device(struct device *dev)
+ {
+-      struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
++      struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
+       struct device_link *link;
+       if (!qcom_iommu)
+diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
+index de698463e94ad..23c7eec46fff6 100644
+--- a/drivers/iommu/mtk_iommu.c
++++ b/drivers/iommu/mtk_iommu.c
+@@ -843,16 +843,11 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
+ static struct iommu_device *mtk_iommu_probe_device(struct device *dev)
+ {
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+-      struct mtk_iommu_data *data;
++      struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
+       struct device_link *link;
+       struct device *larbdev;
+       unsigned int larbid, larbidx, i;
+-      if (!fwspec || fwspec->ops != &mtk_iommu_ops)
+-              return ERR_PTR(-ENODEV); /* Not a iommu client device */
+-
+-      data = dev_iommu_priv_get(dev);
+-
+       if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
+               return &data->iommu;
+diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
+index f1754efcfe74e..027b2ff7f33ef 100644
+--- a/drivers/iommu/mtk_iommu_v1.c
++++ b/drivers/iommu/mtk_iommu_v1.c
+@@ -478,9 +478,6 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
+               idx++;
+       }
+-      if (!fwspec || fwspec->ops != &mtk_iommu_v1_ops)
+-              return ERR_PTR(-ENODEV); /* Not a iommu client device */
+-
+       data = dev_iommu_priv_get(dev);
+       /* Link the consumer device with the smi-larb device(supplier) */
+diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
+index c8e79a2d8b4c6..b5570ef887023 100644
+--- a/drivers/iommu/sprd-iommu.c
++++ b/drivers/iommu/sprd-iommu.c
+@@ -388,13 +388,7 @@ static phys_addr_t sprd_iommu_iova_to_phys(struct iommu_domain *domain,
+ static struct iommu_device *sprd_iommu_probe_device(struct device *dev)
+ {
+-      struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+-      struct sprd_iommu_device *sdev;
+-
+-      if (!fwspec || fwspec->ops != &sprd_iommu_ops)
+-              return ERR_PTR(-ENODEV);
+-
+-      sdev = dev_iommu_priv_get(dev);
++      struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
+       return &sdev->iommu;
+ }
+diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
+index 17dcd826f5c20..bb2e795a80d0f 100644
+--- a/drivers/iommu/virtio-iommu.c
++++ b/drivers/iommu/virtio-iommu.c
+@@ -969,9 +969,6 @@ static struct iommu_device *viommu_probe_device(struct device *dev)
+       struct viommu_dev *viommu = NULL;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+-      if (!fwspec || fwspec->ops != &viommu_ops)
+-              return ERR_PTR(-ENODEV);
+-
+       viommu = viommu_get_by_fwnode(fwspec->iommu_fwnode);
+       if (!viommu)
+               return ERR_PTR(-ENODEV);
+-- 
+2.43.0
+
diff --git a/queue-6.6/iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch b/queue-6.6/iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch
new file mode 100644 (file)
index 0000000..cd1b556
--- /dev/null
@@ -0,0 +1,84 @@
+From f13d79171ee3a3c2f8da7c45dd3d8f6fb25bbf81 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Sep 2023 10:43:49 -0300
+Subject: iommu/qcom_iommu: Add an IOMMU_IDENTITIY_DOMAIN
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 786478a90294ea5b149ed1156a43e82d63ea61ff ]
+
+This brings back the ops->detach_dev() code that commit
+1b932ceddd19 ("iommu: Remove detach_dev callbacks") deleted and turns it
+into an IDENTITY domain.
+
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/16-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Stable-dep-of: 229e6ee43d2a ("iommu/arm-smmu: Defer probe of clients after smmu device bound")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu/qcom_iommu.c | 39 +++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+index 775a3cbaff4ed..bc45d18f350cb 100644
+--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+@@ -400,6 +400,44 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev
+       return 0;
+ }
++static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain,
++                                    struct device *dev)
++{
++      struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
++      struct qcom_iommu_domain *qcom_domain;
++      struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
++      struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
++      unsigned int i;
++
++      if (domain == identity_domain || !domain)
++              return 0;
++
++      qcom_domain = to_qcom_iommu_domain(domain);
++      if (WARN_ON(!qcom_domain->iommu))
++              return -EINVAL;
++
++      pm_runtime_get_sync(qcom_iommu->dev);
++      for (i = 0; i < fwspec->num_ids; i++) {
++              struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
++
++              /* Disable the context bank: */
++              iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0);
++
++              ctx->domain = NULL;
++      }
++      pm_runtime_put_sync(qcom_iommu->dev);
++      return 0;
++}
++
++static struct iommu_domain_ops qcom_iommu_identity_ops = {
++      .attach_dev = qcom_iommu_identity_attach,
++};
++
++static struct iommu_domain qcom_iommu_identity_domain = {
++      .type = IOMMU_DOMAIN_IDENTITY,
++      .ops = &qcom_iommu_identity_ops,
++};
++
+ static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
+                         phys_addr_t paddr, size_t pgsize, size_t pgcount,
+                         int prot, gfp_t gfp, size_t *mapped)
+@@ -565,6 +603,7 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
+ }
+ static const struct iommu_ops qcom_iommu_ops = {
++      .identity_domain = &qcom_iommu_identity_domain,
+       .capable        = qcom_iommu_capable,
+       .domain_alloc   = qcom_iommu_domain_alloc,
+       .probe_device   = qcom_iommu_probe_device,
+-- 
+2.43.0
+
diff --git a/queue-6.6/ipv6-introduce-dst_rt6_info-helper.patch b/queue-6.6/ipv6-introduce-dst_rt6_info-helper.patch
new file mode 100644 (file)
index 0000000..c99290e
--- /dev/null
@@ -0,0 +1,841 @@
+From 8b69e72dcc554a2fddf7d8ef33cad7057c1c922b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Apr 2024 15:19:52 +0000
+Subject: ipv6: introduce dst_rt6_info() helper
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit e8dfd42c17faf183415323db1ef0c977be0d6489 ]
+
+Instead of (struct rt6_info *)dst casts, we can use :
+
+ #define dst_rt6_info(_ptr) \
+         container_of_const(_ptr, struct rt6_info, dst)
+
+Some places needed missing const qualifiers :
+
+ip6_confirm_neigh(), ipv6_anycast_destination(),
+ipv6_unicast_destination(), has_gateway()
+
+v2: added missing parts (David Ahern)
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 3301ab7d5aeb ("net/ipv6: release expired exception dst cached in socket")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/core/addr.c                |  6 ++--
+ .../ethernet/mellanox/mlxsw/spectrum_span.c   |  2 +-
+ drivers/net/vrf.c                             |  2 +-
+ drivers/net/vxlan/vxlan_core.c                |  2 +-
+ drivers/s390/net/qeth_core.h                  |  4 +--
+ include/net/ip6_fib.h                         |  6 ++--
+ include/net/ip6_route.h                       | 11 ++++----
+ net/bluetooth/6lowpan.c                       |  2 +-
+ net/core/dst_cache.c                          |  2 +-
+ net/core/filter.c                             |  2 +-
+ net/ipv4/ip_tunnel.c                          |  2 +-
+ net/ipv6/icmp.c                               |  8 +++---
+ net/ipv6/ila/ila_lwt.c                        |  4 +--
+ net/ipv6/ip6_output.c                         | 18 ++++++------
+ net/ipv6/ip6mr.c                              |  2 +-
+ net/ipv6/ndisc.c                              |  2 +-
+ net/ipv6/ping.c                               |  2 +-
+ net/ipv6/raw.c                                |  4 +--
+ net/ipv6/route.c                              | 28 +++++++++----------
+ net/ipv6/tcp_ipv6.c                           |  4 +--
+ net/ipv6/udp.c                                | 11 +++-----
+ net/ipv6/xfrm6_policy.c                       |  2 +-
+ net/l2tp/l2tp_ip6.c                           |  2 +-
+ net/mpls/mpls_iptunnel.c                      |  2 +-
+ net/netfilter/ipvs/ip_vs_xmit.c               | 14 +++++-----
+ net/netfilter/nf_flow_table_core.c            |  8 ++----
+ net/netfilter/nf_flow_table_ip.c              |  4 +--
+ net/netfilter/nft_rt.c                        |  2 +-
+ net/sctp/ipv6.c                               |  2 +-
+ net/xfrm/xfrm_policy.c                        |  3 +-
+ 30 files changed, 77 insertions(+), 86 deletions(-)
+
+diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
+index f253295795f0a..f20dfe70fa0e4 100644
+--- a/drivers/infiniband/core/addr.c
++++ b/drivers/infiniband/core/addr.c
+@@ -348,15 +348,15 @@ static int dst_fetch_ha(const struct dst_entry *dst,
+ static bool has_gateway(const struct dst_entry *dst, sa_family_t family)
+ {
+-      struct rtable *rt;
+-      struct rt6_info *rt6;
++      const struct rtable *rt;
++      const struct rt6_info *rt6;
+       if (family == AF_INET) {
+               rt = container_of(dst, struct rtable, dst);
+               return rt->rt_uses_gateway;
+       }
+-      rt6 = container_of(dst, struct rt6_info, dst);
++      rt6 = dst_rt6_info(dst);
+       return rt6->rt6i_flags & RTF_GATEWAY;
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+index b3472fb946177..dcd198104141f 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+@@ -539,7 +539,7 @@ mlxsw_sp_span_gretap6_route(const struct net_device *to_dev,
+       if (!dst || dst->error)
+               goto out;
+-      rt6 = container_of(dst, struct rt6_info, dst);
++      rt6 = dst_rt6_info(dst);
+       dev = dst->dev;
+       *saddrp = fl6.saddr;
+diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
+index 27761a884dc62..5968a3ab81770 100644
+--- a/drivers/net/vrf.c
++++ b/drivers/net/vrf.c
+@@ -655,7 +655,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
+       skb->dev = dev;
+       rcu_read_lock();
+-      nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
++      nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr);
+       neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
+       if (unlikely(!neigh))
+               neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
+diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
+index c114c91b558bd..ee02a92338da1 100644
+--- a/drivers/net/vxlan/vxlan_core.c
++++ b/drivers/net/vxlan/vxlan_core.c
+@@ -2629,7 +2629,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
+               }
+               if (!info) {
+-                      u32 rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
++                      u32 rt6i_flags = dst_rt6_info(ndst)->rt6i_flags;
+                       err = encap_bypass_if_local(skb, dev, vxlan, dst,
+                                                   dst_port, ifindex, vni,
+diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
+index 613eab7297046..5f17a2a5d0e33 100644
+--- a/drivers/s390/net/qeth_core.h
++++ b/drivers/s390/net/qeth_core.h
+@@ -956,7 +956,7 @@ static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb,
+       struct dst_entry *dst = skb_dst(skb);
+       struct rt6_info *rt;
+-      rt = (struct rt6_info *) dst;
++      rt = dst_rt6_info(dst);
+       if (dst) {
+               if (proto == htons(ETH_P_IPV6))
+                       dst = dst_check(dst, rt6_get_cookie(rt));
+@@ -978,7 +978,7 @@ static inline __be32 qeth_next_hop_v4_rcu(struct sk_buff *skb,
+ static inline struct in6_addr *qeth_next_hop_v6_rcu(struct sk_buff *skb,
+                                                   struct dst_entry *dst)
+ {
+-      struct rt6_info *rt = (struct rt6_info *) dst;
++      struct rt6_info *rt = dst_rt6_info(dst);
+       if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
+               return &rt->rt6i_gateway;
+diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
+index 9ba6413fd2e3e..1121d614942c8 100644
+--- a/include/net/ip6_fib.h
++++ b/include/net/ip6_fib.h
+@@ -237,9 +237,11 @@ struct fib6_result {
+       for (rt = (w)->leaf; rt;                                        \
+            rt = rcu_dereference_protected(rt->fib6_next, 1))
+-static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
++#define dst_rt6_info(_ptr) container_of_const(_ptr, struct rt6_info, dst)
++
++static inline struct inet6_dev *ip6_dst_idev(const struct dst_entry *dst)
+ {
+-      return ((struct rt6_info *)dst)->rt6i_idev;
++      return dst_rt6_info(dst)->rt6i_idev;
+ }
+ static inline bool fib6_requires_src(const struct fib6_info *rt)
+diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
+index 61cfc8891f820..392232fcd703c 100644
+--- a/include/net/ip6_route.h
++++ b/include/net/ip6_route.h
+@@ -218,12 +218,11 @@ void rt6_uncached_list_del(struct rt6_info *rt);
+ static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
+ {
+       const struct dst_entry *dst = skb_dst(skb);
+-      const struct rt6_info *rt6 = NULL;
+       if (dst)
+-              rt6 = container_of(dst, struct rt6_info, dst);
++              return dst_rt6_info(dst);
+-      return rt6;
++      return NULL;
+ }
+ /*
+@@ -235,7 +234,7 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
+ {
+       struct ipv6_pinfo *np = inet6_sk(sk);
+-      np->dst_cookie = rt6_get_cookie((struct rt6_info *)dst);
++      np->dst_cookie = rt6_get_cookie(dst_rt6_info(dst));
+       sk_setup_caps(sk, dst);
+       np->daddr_cache = daddr;
+ #ifdef CONFIG_IPV6_SUBTREES
+@@ -248,7 +247,7 @@ void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
+ static inline bool ipv6_unicast_destination(const struct sk_buff *skb)
+ {
+-      struct rt6_info *rt = (struct rt6_info *) skb_dst(skb);
++      const struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
+       return rt->rt6i_flags & RTF_LOCAL;
+ }
+@@ -256,7 +255,7 @@ static inline bool ipv6_unicast_destination(const struct sk_buff *skb)
+ static inline bool ipv6_anycast_destination(const struct dst_entry *dst,
+                                           const struct in6_addr *daddr)
+ {
+-      struct rt6_info *rt = (struct rt6_info *)dst;
++      const struct rt6_info *rt = dst_rt6_info(dst);
+       return rt->rt6i_flags & RTF_ANYCAST ||
+               (rt->rt6i_dst.plen < 127 &&
+diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
+index 4eb1b3ced0d27..3bcc15c9415fc 100644
+--- a/net/bluetooth/6lowpan.c
++++ b/net/bluetooth/6lowpan.c
+@@ -133,7 +133,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
+                                                 struct in6_addr *daddr,
+                                                 struct sk_buff *skb)
+ {
+-      struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
++      struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
+       int count = atomic_read(&dev->peer_count);
+       const struct in6_addr *nexthop;
+       struct lowpan_peer *peer;
+diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c
+index 0ccfd5fa5cb9b..b17171345d649 100644
+--- a/net/core/dst_cache.c
++++ b/net/core/dst_cache.c
+@@ -112,7 +112,7 @@ void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst,
+-                                rt6_get_cookie((struct rt6_info *)dst));
++                                rt6_get_cookie(dst_rt6_info(dst)));
+       idst->in6_saddr = *saddr;
+ }
+ EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
+diff --git a/net/core/filter.c b/net/core/filter.c
+index b64e7139eae19..bc52ab3374f3a 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -2215,7 +2215,7 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb,
+       rcu_read_lock();
+       if (!nh) {
+               dst = skb_dst(skb);
+-              nexthop = rt6_nexthop(container_of(dst, struct rt6_info, dst),
++              nexthop = rt6_nexthop(dst_rt6_info(dst),
+                                     &ipv6_hdr(skb)->daddr);
+       } else {
+               nexthop = &nh->ipv6_nh;
+diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
+index acf93f34a8213..72b2d68ef4da5 100644
+--- a/net/ipv4/ip_tunnel.c
++++ b/net/ipv4/ip_tunnel.c
+@@ -544,7 +544,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
+               struct rt6_info *rt6;
+               __be32 daddr;
+-              rt6 = skb_valid_dst(skb) ? (struct rt6_info *)skb_dst(skb) :
++              rt6 = skb_valid_dst(skb) ? dst_rt6_info(skb_dst(skb)) :
+                                          NULL;
+               daddr = md ? dst : tunnel->parms.iph.daddr;
+diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
+index a790294d31048..25a3a726fa117 100644
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -214,7 +214,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
+       } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
+               res = true;
+       } else {
+-              struct rt6_info *rt = (struct rt6_info *)dst;
++              struct rt6_info *rt = dst_rt6_info(dst);
+               int tmo = net->ipv6.sysctl.icmpv6_time;
+               struct inet_peer *peer;
+@@ -245,7 +245,7 @@ static bool icmpv6_rt_has_prefsrc(struct sock *sk, u8 type,
+       dst = ip6_route_output(net, sk, fl6);
+       if (!dst->error) {
+-              struct rt6_info *rt = (struct rt6_info *)dst;
++              struct rt6_info *rt = dst_rt6_info(dst);
+               struct in6_addr prefsrc;
+               rt6_get_prefsrc(rt, &prefsrc);
+@@ -622,7 +622,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
+       if (ip6_append_data(sk, icmpv6_getfrag, &msg,
+                           len + sizeof(struct icmp6hdr),
+                           sizeof(struct icmp6hdr),
+-                          &ipc6, &fl6, (struct rt6_info *)dst,
++                          &ipc6, &fl6, dst_rt6_info(dst),
+                           MSG_DONTWAIT)) {
+               ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
+               ip6_flush_pending_frames(sk);
+@@ -811,7 +811,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
+       if (ip6_append_data(sk, icmpv6_getfrag, &msg,
+                           skb->len + sizeof(struct icmp6hdr),
+                           sizeof(struct icmp6hdr), &ipc6, &fl6,
+-                          (struct rt6_info *)dst, MSG_DONTWAIT)) {
++                          dst_rt6_info(dst), MSG_DONTWAIT)) {
+               __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
+               ip6_flush_pending_frames(sk);
+       } else {
+diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
+index 9d37f7164e732..ff7e734e335b0 100644
+--- a/net/ipv6/ila/ila_lwt.c
++++ b/net/ipv6/ila/ila_lwt.c
+@@ -38,7 +38,7 @@ static inline struct ila_params *ila_params_lwtunnel(
+ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+ {
+       struct dst_entry *orig_dst = skb_dst(skb);
+-      struct rt6_info *rt = (struct rt6_info *)orig_dst;
++      struct rt6_info *rt = dst_rt6_info(orig_dst);
+       struct ila_lwt *ilwt = ila_lwt_lwtunnel(orig_dst->lwtstate);
+       struct dst_entry *dst;
+       int err = -EINVAL;
+@@ -72,7 +72,7 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+               memset(&fl6, 0, sizeof(fl6));
+               fl6.flowi6_oif = orig_dst->dev->ifindex;
+               fl6.flowi6_iif = LOOPBACK_IFINDEX;
+-              fl6.daddr = *rt6_nexthop((struct rt6_info *)orig_dst,
++              fl6.daddr = *rt6_nexthop(dst_rt6_info(orig_dst),
+                                        &ip6h->daddr);
+               dst = ip6_route_output(net, NULL, &fl6);
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 65e2f19814358..2341a4373bb94 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -124,7 +124,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
+       IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
+       rcu_read_lock();
+-      nexthop = rt6_nexthop((struct rt6_info *)dst, daddr);
++      nexthop = rt6_nexthop(dst_rt6_info(dst), daddr);
+       neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
+       if (unlikely(IS_ERR_OR_NULL(neigh))) {
+@@ -606,7 +606,7 @@ int ip6_forward(struct sk_buff *skb)
+                *      send a redirect.
+                */
+-              rt = (struct rt6_info *) dst;
++              rt = dst_rt6_info(dst);
+               if (rt->rt6i_flags & RTF_GATEWAY)
+                       target = &rt->rt6i_gateway;
+               else
+@@ -861,7 +861,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
+                int (*output)(struct net *, struct sock *, struct sk_buff *))
+ {
+       struct sk_buff *frag;
+-      struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
++      struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
+       bool mono_delivery_time = skb->mono_delivery_time;
+@@ -1069,7 +1069,7 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
+               return NULL;
+       }
+-      rt = (struct rt6_info *)dst;
++      rt = dst_rt6_info(dst);
+       /* Yes, checking route validity in not connected
+        * case is not very simple. Take into account,
+        * that we do not support routing by source, TOS,
+@@ -1124,7 +1124,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
+               struct rt6_info *rt;
+               *dst = ip6_route_output(net, sk, fl6);
+-              rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
++              rt = (*dst)->error ? NULL : dst_rt6_info(*dst);
+               rcu_read_lock();
+               from = rt ? rcu_dereference(rt->from) : NULL;
+@@ -1166,7 +1166,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
+        * dst entry and replace it instead with the
+        * dst entry of the nexthop router
+        */
+-      rt = (struct rt6_info *) *dst;
++      rt = dst_rt6_info(*dst);
+       rcu_read_lock();
+       n = __ipv6_neigh_lookup_noref(rt->dst.dev,
+                                     rt6_nexthop(rt, &fl6->daddr));
+@@ -1500,7 +1500,7 @@ static int __ip6_append_data(struct sock *sk,
+       int offset = 0;
+       bool zc = false;
+       u32 tskey = 0;
+-      struct rt6_info *rt = (struct rt6_info *)cork->dst;
++      struct rt6_info *rt = dst_rt6_info(cork->dst);
+       bool paged, hold_tskey, extra_uref = false;
+       struct ipv6_txoptions *opt = v6_cork->opt;
+       int csummode = CHECKSUM_NONE;
+@@ -1959,7 +1959,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
+       struct net *net = sock_net(sk);
+       struct ipv6hdr *hdr;
+       struct ipv6_txoptions *opt = v6_cork->opt;
+-      struct rt6_info *rt = (struct rt6_info *)cork->base.dst;
++      struct rt6_info *rt = dst_rt6_info(cork->base.dst);
+       struct flowi6 *fl6 = &cork->fl.u.ip6;
+       unsigned char proto = fl6->flowi6_proto;
+@@ -2031,7 +2031,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
+ int ip6_send_skb(struct sk_buff *skb)
+ {
+       struct net *net = sock_net(skb->sk);
+-      struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
++      struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
+       int err;
+       rcu_read_lock();
+diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
+index e24fa0843c7d1..1571e85a3531e 100644
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -2290,7 +2290,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
+       int err;
+       struct mr_table *mrt;
+       struct mfc6_cache *cache;
+-      struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
++      struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
+       rcu_read_lock();
+       mrt = __ip6mr_get_table(net, RT6_TABLE_DFLT);
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 2062ab94721e3..23b46b5705c53 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1710,7 +1710,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
+       if (IS_ERR(dst))
+               return;
+-      rt = (struct rt6_info *) dst;
++      rt = dst_rt6_info(dst);
+       if (rt->rt6i_flags & RTF_GATEWAY) {
+               ND_PRINTK(2, warn,
+diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
+index 25243737fbc42..878ed02b299d7 100644
+--- a/net/ipv6/ping.c
++++ b/net/ipv6/ping.c
+@@ -154,7 +154,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+       dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, false);
+       if (IS_ERR(dst))
+               return PTR_ERR(dst);
+-      rt = (struct rt6_info *) dst;
++      rt = dst_rt6_info(dst);
+       if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+               fl6.flowi6_oif = np->mcast_oif;
+diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
+index 0a3e12502b05a..4f526606bc894 100644
+--- a/net/ipv6/raw.c
++++ b/net/ipv6/raw.c
+@@ -592,7 +592,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
+       struct ipv6hdr *iph;
+       struct sk_buff *skb;
+       int err;
+-      struct rt6_info *rt = (struct rt6_info *)*dstp;
++      struct rt6_info *rt = dst_rt6_info(*dstp);
+       int hlen = LL_RESERVED_SPACE(rt->dst.dev);
+       int tlen = rt->dst.dev->needed_tailroom;
+@@ -911,7 +911,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+               ipc6.opt = opt;
+               lock_sock(sk);
+               err = ip6_append_data(sk, raw6_getfrag, &rfv,
+-                      len, 0, &ipc6, &fl6, (struct rt6_info *)dst,
++                      len, 0, &ipc6, &fl6, dst_rt6_info(dst),
+                       msg->msg_flags);
+               if (err)
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index e320dfa7fe7fc..0fdd062d4b05b 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -227,7 +227,7 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
+                                             struct sk_buff *skb,
+                                             const void *daddr)
+ {
+-      const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
++      const struct rt6_info *rt = dst_rt6_info(dst);
+       return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any),
+                               dst->dev, skb, daddr);
+@@ -235,8 +235,8 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
+ static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
+ {
++      const struct rt6_info *rt = dst_rt6_info(dst);
+       struct net_device *dev = dst->dev;
+-      struct rt6_info *rt = (struct rt6_info *)dst;
+       daddr = choose_neigh_daddr(rt6_nexthop(rt, &in6addr_any), NULL, daddr);
+       if (!daddr)
+@@ -355,7 +355,7 @@ EXPORT_SYMBOL(ip6_dst_alloc);
+ static void ip6_dst_destroy(struct dst_entry *dst)
+ {
+-      struct rt6_info *rt = (struct rt6_info *)dst;
++      struct rt6_info *rt = dst_rt6_info(dst);
+       struct fib6_info *from;
+       struct inet6_dev *idev;
+@@ -374,7 +374,7 @@ static void ip6_dst_destroy(struct dst_entry *dst)
+ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
+ {
+-      struct rt6_info *rt = (struct rt6_info *)dst;
++      struct rt6_info *rt = dst_rt6_info(dst);
+       struct inet6_dev *idev = rt->rt6i_idev;
+       struct fib6_info *from;
+@@ -1284,7 +1284,7 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
+       dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
+       if (dst->error == 0)
+-              return (struct rt6_info *) dst;
++              return dst_rt6_info(dst);
+       dst_release(dst);
+@@ -2641,7 +2641,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net,
+       rcu_read_lock();
+       dst = ip6_route_output_flags_noref(net, sk, fl6, flags);
+-      rt6 = (struct rt6_info *)dst;
++      rt6 = dst_rt6_info(dst);
+       /* For dst cached in uncached_list, refcnt is already taken. */
+       if (list_empty(&rt6->dst.rt_uncached) && !dst_hold_safe(dst)) {
+               dst = &net->ipv6.ip6_null_entry->dst;
+@@ -2655,7 +2655,7 @@ EXPORT_SYMBOL_GPL(ip6_route_output_flags);
+ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
+ {
+-      struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
++      struct rt6_info *rt, *ort = dst_rt6_info(dst_orig);
+       struct net_device *loopback_dev = net->loopback_dev;
+       struct dst_entry *new = NULL;
+@@ -2738,7 +2738,7 @@ INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst,
+       struct fib6_info *from;
+       struct rt6_info *rt;
+-      rt = container_of(dst, struct rt6_info, dst);
++      rt = dst_rt6_info(dst);
+       if (rt->sernum)
+               return rt6_is_valid(rt) ? dst : NULL;
+@@ -2767,7 +2767,7 @@ EXPORT_INDIRECT_CALLABLE(ip6_dst_check);
+ static void ip6_negative_advice(struct sock *sk,
+                               struct dst_entry *dst)
+ {
+-      struct rt6_info *rt = (struct rt6_info *) dst;
++      struct rt6_info *rt = dst_rt6_info(dst);
+       if (rt->rt6i_flags & RTF_CACHE) {
+               rcu_read_lock();
+@@ -2790,7 +2790,7 @@ static void ip6_link_failure(struct sk_buff *skb)
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
+-      rt = (struct rt6_info *) skb_dst(skb);
++      rt = dst_rt6_info(skb_dst(skb));
+       if (rt) {
+               rcu_read_lock();
+               if (rt->rt6i_flags & RTF_CACHE) {
+@@ -2846,7 +2846,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
+                                bool confirm_neigh)
+ {
+       const struct in6_addr *daddr, *saddr;
+-      struct rt6_info *rt6 = (struct rt6_info *)dst;
++      struct rt6_info *rt6 = dst_rt6_info(dst);
+       /* Note: do *NOT* check dst_metric_locked(dst, RTAX_MTU)
+        * IPv6 pmtu discovery isn't optional, so 'mtu lock' cannot disable it.
+@@ -4169,7 +4169,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
+               }
+       }
+-      rt = (struct rt6_info *) dst;
++      rt = dst_rt6_info(dst);
+       if (rt->rt6i_flags & RTF_REJECT) {
+               net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
+               return;
+@@ -5604,7 +5604,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
+                        int iif, int type, u32 portid, u32 seq,
+                        unsigned int flags)
+ {
+-      struct rt6_info *rt6 = (struct rt6_info *)dst;
++      struct rt6_info *rt6 = dst_rt6_info(dst);
+       struct rt6key *rt6_dst, *rt6_src;
+       u32 *pmetrics, table, rt6_flags;
+       unsigned char nh_flags = 0;
+@@ -6107,7 +6107,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
+       }
+-      rt = container_of(dst, struct rt6_info, dst);
++      rt = dst_rt6_info(dst);
+       if (rt->dst.error) {
+               err = rt->dst.error;
+               ip6_rt_put(rt);
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 83b48dc2b3ee2..64bdb6d978eed 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -101,11 +101,9 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+       struct dst_entry *dst = skb_dst(skb);
+       if (dst && dst_hold_safe(dst)) {
+-              const struct rt6_info *rt = (const struct rt6_info *)dst;
+-
+               rcu_assign_pointer(sk->sk_rx_dst, dst);
+               sk->sk_rx_dst_ifindex = skb->skb_iif;
+-              sk->sk_rx_dst_cookie = rt6_get_cookie(rt);
++              sk->sk_rx_dst_cookie = rt6_get_cookie(dst_rt6_info(dst));
+       }
+ }
+diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
+index c77ee9a3cde24..954afe6ba883e 100644
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -913,11 +913,8 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
+ static void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
+ {
+-      if (udp_sk_rx_dst_set(sk, dst)) {
+-              const struct rt6_info *rt = (const struct rt6_info *)dst;
+-
+-              sk->sk_rx_dst_cookie = rt6_get_cookie(rt);
+-      }
++      if (udp_sk_rx_dst_set(sk, dst))
++              sk->sk_rx_dst_cookie = rt6_get_cookie(dst_rt6_info(dst));
+ }
+ /* wrapper for udp_queue_rcv_skb tacking care of csum conversion and
+@@ -1587,7 +1584,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+               skb = ip6_make_skb(sk, getfrag, msg, ulen,
+                                  sizeof(struct udphdr), &ipc6,
+-                                 (struct rt6_info *)dst,
++                                 dst_rt6_info(dst),
+                                  msg->msg_flags, &cork);
+               err = PTR_ERR(skb);
+               if (!IS_ERR_OR_NULL(skb))
+@@ -1614,7 +1611,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+               ipc6.dontfrag = np->dontfrag;
+       up->len += ulen;
+       err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
+-                            &ipc6, fl6, (struct rt6_info *)dst,
++                            &ipc6, fl6, dst_rt6_info(dst),
+                             corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+       if (err)
+               udp_v6_flush_pending_frames(sk);
+diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
+index 4cd625af91e6c..f24faa78ee82d 100644
+--- a/net/ipv6/xfrm6_policy.c
++++ b/net/ipv6/xfrm6_policy.c
+@@ -77,7 +77,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr,
+ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
+                         const struct flowi *fl)
+ {
+-      struct rt6_info *rt = (struct rt6_info *)xdst->route;
++      struct rt6_info *rt = dst_rt6_info(xdst->route);
+       xdst->u.dst.dev = dev;
+       netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
+diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
+index db4971d52802b..1b7a7b4f7273a 100644
+--- a/net/l2tp/l2tp_ip6.c
++++ b/net/l2tp/l2tp_ip6.c
+@@ -630,7 +630,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+       ulen = len + (skb_queue_empty(&sk->sk_write_queue) ? transhdrlen : 0);
+       err = ip6_append_data(sk, ip_generic_getfrag, msg,
+                             ulen, transhdrlen, &ipc6,
+-                            &fl6, (struct rt6_info *)dst,
++                            &fl6, dst_rt6_info(dst),
+                             msg->msg_flags);
+       if (err)
+               ip6_flush_pending_frames(sk);
+diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
+index ef59e25dc4827..8985abcb7a058 100644
+--- a/net/mpls/mpls_iptunnel.c
++++ b/net/mpls/mpls_iptunnel.c
+@@ -92,7 +92,7 @@ static int mpls_xmit(struct sk_buff *skb)
+                       ttl = net->mpls.default_ttl;
+               else
+                       ttl = ipv6_hdr(skb)->hop_limit;
+-              rt6 = (struct rt6_info *)dst;
++              rt6 = dst_rt6_info(dst);
+       } else {
+               goto drop;
+       }
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index 65e0259178da4..5cd511162bc03 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -180,7 +180,7 @@ static inline bool crosses_local_route_boundary(int skb_af, struct sk_buff *skb,
+                       (!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
+                       (addr_type & IPV6_ADDR_LOOPBACK);
+               old_rt_is_local = __ip_vs_is_local_route6(
+-                      (struct rt6_info *)skb_dst(skb));
++                      dst_rt6_info(skb_dst(skb)));
+       } else
+ #endif
+       {
+@@ -481,7 +481,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
+       if (dest) {
+               dest_dst = __ip_vs_dst_check(dest);
+               if (likely(dest_dst))
+-                      rt = (struct rt6_info *) dest_dst->dst_cache;
++                      rt = dst_rt6_info(dest_dst->dst_cache);
+               else {
+                       u32 cookie;
+@@ -501,7 +501,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
+                               ip_vs_dest_dst_free(dest_dst);
+                               goto err_unreach;
+                       }
+-                      rt = (struct rt6_info *) dst;
++                      rt = dst_rt6_info(dst);
+                       cookie = rt6_get_cookie(rt);
+                       __ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie);
+                       spin_unlock_bh(&dest->dst_lock);
+@@ -517,7 +517,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
+                                             rt_mode);
+               if (!dst)
+                       goto err_unreach;
+-              rt = (struct rt6_info *) dst;
++              rt = dst_rt6_info(dst);
+       }
+       local = __ip_vs_is_local_route6(rt);
+@@ -862,7 +862,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+                                     IP_VS_RT_MODE_RDR);
+       if (local < 0)
+               goto tx_error;
+-      rt = (struct rt6_info *) skb_dst(skb);
++      rt = dst_rt6_info(skb_dst(skb));
+       /*
+        * Avoid duplicate tuple in reply direction for NAT traffic
+        * to local address when connection is sync-ed
+@@ -1288,7 +1288,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+       if (local)
+               return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
+-      rt = (struct rt6_info *) skb_dst(skb);
++      rt = dst_rt6_info(skb_dst(skb));
+       tdev = rt->dst.dev;
+       /*
+@@ -1590,7 +1590,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+                                     &cp->daddr.in6, NULL, ipvsh, 0, rt_mode);
+       if (local < 0)
+               goto tx_error;
+-      rt = (struct rt6_info *) skb_dst(skb);
++      rt = dst_rt6_info(skb_dst(skb));
+       /*
+        * Avoid duplicate tuple in reply direction for NAT traffic
+        * to local address when connection is sync-ed
+diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
+index a0571339239c4..5c1ff07eaee0b 100644
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -77,12 +77,8 @@ EXPORT_SYMBOL_GPL(flow_offload_alloc);
+ static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple)
+ {
+-      const struct rt6_info *rt;
+-
+-      if (flow_tuple->l3proto == NFPROTO_IPV6) {
+-              rt = (const struct rt6_info *)flow_tuple->dst_cache;
+-              return rt6_get_cookie(rt);
+-      }
++      if (flow_tuple->l3proto == NFPROTO_IPV6)
++              return rt6_get_cookie(dst_rt6_info(flow_tuple->dst_cache));
+       return 0;
+ }
+diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
+index 846fa2ad7c858..20dd4eeac78b1 100644
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -732,7 +732,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+               return NF_ACCEPT;
+       if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
+-              rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
++              rt = dst_rt6_info(tuplehash->tuple.dst_cache);
+               memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+               IP6CB(skb)->iif = skb->dev->ifindex;
+               IP6CB(skb)->flags = IP6SKB_FORWARDED;
+@@ -744,7 +744,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+       switch (tuplehash->tuple.xmit_type) {
+       case FLOW_OFFLOAD_XMIT_NEIGH:
+-              rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
++              rt = dst_rt6_info(tuplehash->tuple.dst_cache);
+               outdev = rt->dst.dev;
+               skb->dev = outdev;
+               nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
+diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c
+index 24d9771385729..2434c624aafde 100644
+--- a/net/netfilter/nft_rt.c
++++ b/net/netfilter/nft_rt.c
+@@ -80,7 +80,7 @@ void nft_rt_get_eval(const struct nft_expr *expr,
+               if (nft_pf(pkt) != NFPROTO_IPV6)
+                       goto err;
+-              memcpy(dest, rt6_nexthop((struct rt6_info *)dst,
++              memcpy(dest, rt6_nexthop(dst_rt6_info(dst),
+                                        &ipv6_hdr(skb)->daddr),
+                      sizeof(struct in6_addr));
+               break;
+diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
+index 08acda9ecdf56..717828e531621 100644
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -416,7 +416,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+       if (!IS_ERR_OR_NULL(dst)) {
+               struct rt6_info *rt;
+-              rt = (struct rt6_info *)dst;
++              rt = dst_rt6_info(dst);
+               t->dst_cookie = rt6_get_cookie(rt);
+               pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n",
+                        &rt->rt6i_dst.addr, rt->rt6i_dst.plen,
+diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
+index d788baffbf104..68b3f9e7edffd 100644
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -2607,8 +2607,7 @@ static void xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst,
+                          int nfheader_len)
+ {
+       if (dst->ops->family == AF_INET6) {
+-              struct rt6_info *rt = (struct rt6_info *)dst;
+-              path->path_cookie = rt6_get_cookie(rt);
++              path->path_cookie = rt6_get_cookie(dst_rt6_info(dst));
+               path->u.rt6.rt6i_nfheader_len = nfheader_len;
+       }
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch b/queue-6.6/ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch
new file mode 100644 (file)
index 0000000..9b6c886
--- /dev/null
@@ -0,0 +1,117 @@
+From 35d591d95d07e560d6dad89a64c2eaee6af8f0d1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 23 Nov 2024 03:42:56 -0600
+Subject: ipvs: fix UB due to uninitialized stack access in
+ ip_vs_protocol_init()
+
+From: Jinghao Jia <jinghao7@illinois.edu>
+
+[ Upstream commit 146b6f1112eb30a19776d6c323c994e9d67790db ]
+
+Under certain kernel configurations when building with Clang/LLVM, the
+compiler does not generate a return or jump as the terminator
+instruction for ip_vs_protocol_init(), triggering the following objtool
+warning during build time:
+
+  vmlinux.o: warning: objtool: ip_vs_protocol_init() falls through to next function __initstub__kmod_ip_vs_rr__935_123_ip_vs_rr_init6()
+
+At runtime, this either causes an oops when trying to load the ipvs
+module or a boot-time panic if ipvs is built-in. This same issue has
+been reported by the Intel kernel test robot previously.
+
+Digging deeper into both LLVM and the kernel code reveals this to be a
+undefined behavior problem. ip_vs_protocol_init() uses a on-stack buffer
+of 64 chars to store the registered protocol names and leaves it
+uninitialized after definition. The function calls strnlen() when
+concatenating protocol names into the buffer. With CONFIG_FORTIFY_SOURCE
+strnlen() performs an extra step to check whether the last byte of the
+input char buffer is a null character (commit 3009f891bb9f ("fortify:
+Allow strlen() and strnlen() to pass compile-time known lengths")).
+This, together with possibly other configurations, cause the following
+IR to be generated:
+
+  define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #5 section ".init.text" align 16 !kcfi_type !29 {
+    %1 = alloca [64 x i8], align 16
+    ...
+
+  14:                                               ; preds = %11
+    %15 = getelementptr inbounds i8, ptr %1, i64 63
+    %16 = load i8, ptr %15, align 1
+    %17 = tail call i1 @llvm.is.constant.i8(i8 %16)
+    %18 = icmp eq i8 %16, 0
+    %19 = select i1 %17, i1 %18, i1 false
+    br i1 %19, label %20, label %23
+
+  20:                                               ; preds = %14
+    %21 = call i64 @strlen(ptr noundef nonnull dereferenceable(1) %1) #23
+    ...
+
+  23:                                               ; preds = %14, %11, %20
+    %24 = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) %1, i64 noundef 64) #24
+    ...
+  }
+
+The above code calculates the address of the last char in the buffer
+(value %15) and then loads from it (value %16). Because the buffer is
+never initialized, the LLVM GVN pass marks value %16 as undefined:
+
+  %13 = getelementptr inbounds i8, ptr %1, i64 63
+  br i1 undef, label %14, label %17
+
+This gives later passes (SCCP, in particular) more DCE opportunities by
+propagating the undef value further, and eventually removes everything
+after the load on the uninitialized stack location:
+
+  define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #0 section ".init.text" align 16 !kcfi_type !11 {
+    %1 = alloca [64 x i8], align 16
+    ...
+
+  12:                                               ; preds = %11
+    %13 = getelementptr inbounds i8, ptr %1, i64 63
+    unreachable
+  }
+
+In this way, the generated native code will just fall through to the
+next function, as LLVM does not generate any code for the unreachable IR
+instruction and leaves the function without a terminator.
+
+Zero the on-stack buffer to avoid this possible UB.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202402100205.PWXIz1ZK-lkp@intel.com/
+Co-developed-by: Ruowen Qin <ruqin@redhat.com>
+Signed-off-by: Ruowen Qin <ruqin@redhat.com>
+Signed-off-by: Jinghao Jia <jinghao7@illinois.edu>
+Acked-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/ipvs/ip_vs_proto.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
+index f100da4ba3bc3..a9fd1d3fc2cbf 100644
+--- a/net/netfilter/ipvs/ip_vs_proto.c
++++ b/net/netfilter/ipvs/ip_vs_proto.c
+@@ -340,7 +340,7 @@ void __net_exit ip_vs_protocol_net_cleanup(struct netns_ipvs *ipvs)
+ int __init ip_vs_protocol_init(void)
+ {
+-      char protocols[64];
++      char protocols[64] = { 0 };
+ #define REGISTER_PROTOCOL(p)                  \
+       do {                                    \
+               register_ip_vs_protocol(p);     \
+@@ -348,8 +348,6 @@ int __init ip_vs_protocol_init(void)
+               strcat(protocols, (p)->name);   \
+       } while (0)
+-      protocols[0] = '\0';
+-      protocols[2] = '\0';
+ #ifdef CONFIG_IP_VS_PROTO_TCP
+       REGISTER_PROTOCOL(&ip_vs_protocol_tcp);
+ #endif
+-- 
+2.43.0
+
diff --git a/queue-6.6/itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch b/queue-6.6/itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch
new file mode 100644 (file)
index 0000000..493cd8b
--- /dev/null
@@ -0,0 +1,85 @@
+From 603e805f2b7d442fbe463e84b3683a9765d87cd1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Sep 2024 12:14:03 -0700
+Subject: iTCO_wdt: mask NMI_NOW bit for update_no_reboot_bit() call
+
+From: Oleksandr Ocheretnyi <oocheret@cisco.com>
+
+[ Upstream commit daa814d784ac034c62ab3fb0ef83daeafef527e2 ]
+
+Commit da23b6faa8bf ("watchdog: iTCO: Add support for Cannon Lake
+PCH iTCO") does not mask NMI_NOW bit during TCO1_CNT register's
+value comparison for update_no_reboot_bit() call causing following
+failure:
+
+   ...
+   iTCO_vendor_support: vendor-support=0
+   iTCO_wdt iTCO_wdt: unable to reset NO_REBOOT flag, device
+                                    disabled by hardware/BIOS
+   ...
+
+and this can lead to unexpected NMIs later during regular
+crashkernel's workflow because of watchdog probe call failures.
+
+This change masks NMI_NOW bit for TCO1_CNT register values to
+avoid unexpected NMI_NOW bit inversions.
+
+Fixes: da23b6faa8bf ("watchdog: iTCO: Add support for Cannon Lake PCH iTCO")
+Signed-off-by: Oleksandr Ocheretnyi <oocheret@cisco.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Link: https://lore.kernel.org/r/20240913191403.2560805-1-oocheret@cisco.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/iTCO_wdt.c | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
+index 264857d314da8..dd297dcd524c9 100644
+--- a/drivers/watchdog/iTCO_wdt.c
++++ b/drivers/watchdog/iTCO_wdt.c
+@@ -82,6 +82,13 @@
+ #define TCO2_CNT(p)   (TCOBASE(p) + 0x0a) /* TCO2 Control Register    */
+ #define TCOv2_TMR(p)  (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/
++/*
++ * NMI_NOW is bit 8 of TCO1_CNT register
++ * Read/Write
++ * This bit is implemented as RW but has no effect on HW.
++ */
++#define NMI_NOW               BIT(8)
++
+ /* internal variables */
+ struct iTCO_wdt_private {
+       struct watchdog_device wddev;
+@@ -219,13 +226,23 @@ static int update_no_reboot_bit_cnt(void *priv, bool set)
+       struct iTCO_wdt_private *p = priv;
+       u16 val, newval;
+-      val = inw(TCO1_CNT(p));
++      /*
++       * writing back 1b1 to NMI_NOW of TCO1_CNT register
++       * causes NMI_NOW bit inversion what consequently does
++       * not allow to perform the register's value comparison
++       * properly.
++       *
++       * NMI_NOW bit masking for TCO1_CNT register values
++       * helps to avoid possible NMI_NOW bit inversions on
++       * following write operation.
++       */
++      val = inw(TCO1_CNT(p)) & ~NMI_NOW;
+       if (set)
+               val |= BIT(0);
+       else
+               val &= ~BIT(0);
+       outw(val, TCO1_CNT(p));
+-      newval = inw(TCO1_CNT(p));
++      newval = inw(TCO1_CNT(p)) & ~NMI_NOW;
+       /* make sure the update is successful */
+       return val != newval ? -EIO : 0;
+-- 
+2.43.0
+
diff --git a/queue-6.6/ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch b/queue-6.6/ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch
new file mode 100644 (file)
index 0000000..1ffc3ea
--- /dev/null
@@ -0,0 +1,73 @@
+From 6e992882c7323b610206f7d2027de1d8e91de68a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Nov 2024 16:05:43 -0700
+Subject: ixgbe: downgrade logging of unsupported VF API version to debug
+
+From: Jacob Keller <jacob.e.keller@intel.com>
+
+[ Upstream commit 15915b43a7fb938934bb7fc4290127218859d795 ]
+
+The ixgbe PF driver logs an info message when a VF attempts to negotiate an
+API version which it does not support:
+
+  VF 0 requested invalid api version 6
+
+The ixgbevf driver attempts to load with mailbox API v1.5, which is
+required for best compatibility with other hosts such as the ESX VMWare PF.
+
+The Linux PF only supports API v1.4, and does not currently have support
+for the v1.5 API.
+
+The logged message can confuse users, as the v1.5 API is valid, but just
+happens to not currently be supported by the Linux PF.
+
+Downgrade the info message to a debug message, and fix the language to
+use 'unsupported' instead of 'invalid' to improve message clarity.
+
+Long term, we should investigate whether the improvements in the v1.5 API
+make sense for the Linux PF, and if so implement them properly. This may
+require yet another API version to resolve issues with negotiating IPSEC
+offload support.
+
+Fixes: 339f28964147 ("ixgbevf: Add support for new mailbox communication between PF and VF")
+Reported-by: Yifei Liu <yifei.l.liu@oracle.com>
+Link: https://lore.kernel.org/intel-wired-lan/20240301235837.3741422-1-yifei.l.liu@oracle.com/
+Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ixgbe/ixgbe_common.h | 2 ++
+ drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c  | 2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+index 34761e691d52d..efdc222e183d1 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+@@ -194,6 +194,8 @@ u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg);
+       dev_err(&adapter->pdev->dev, format, ## arg)
+ #define e_dev_notice(format, arg...) \
+       dev_notice(&adapter->pdev->dev, format, ## arg)
++#define e_dbg(msglvl, format, arg...) \
++      netif_dbg(adapter, msglvl, adapter->netdev, format, ## arg)
+ #define e_info(msglvl, format, arg...) \
+       netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
+ #define e_err(msglvl, format, arg...) \
+diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+index d0a6c220a12ac..9c89a87e35e01 100644
+--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+@@ -1049,7 +1049,7 @@ static int ixgbe_negotiate_vf_api(struct ixgbe_adapter *adapter,
+               break;
+       }
+-      e_info(drv, "VF %d requested invalid api version %u\n", vf, api);
++      e_dbg(drv, "VF %d requested unsupported api version %u\n", vf, api);
+       return -1;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch b/queue-6.6/ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch
new file mode 100644 (file)
index 0000000..bfb5711
--- /dev/null
@@ -0,0 +1,58 @@
+From 2aadf25fb599476a45e709672afc4e8875a9d448 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Nov 2024 16:05:42 -0700
+Subject: ixgbevf: stop attempting IPSEC offload on Mailbox API 1.5
+
+From: Jacob Keller <jacob.e.keller@intel.com>
+
+[ Upstream commit d0725312adf5a803de8f621bd1b12ba7a6464a29 ]
+
+Commit 339f28964147 ("ixgbevf: Add support for new mailbox communication
+between PF and VF") added support for v1.5 of the PF to VF mailbox
+communication API. This commit mistakenly enabled IPSEC offload for API
+v1.5.
+
+No implementation of the v1.5 API has support for IPSEC offload. This
+offload is only supported by the Linux PF as mailbox API v1.4. In fact, the
+v1.5 API is not implemented in any Linux PF.
+
+Attempting to enable IPSEC offload on a PF which supports v1.5 API will not
+work. Only the Linux upstream ixgbe and ixgbevf support IPSEC offload, and
+only as part of the v1.4 API.
+
+Fix the ixgbevf Linux driver to stop attempting IPSEC offload when
+the mailbox API does not support it.
+
+The existing API design choice makes it difficult to support future API
+versions, as other non-Linux hosts do not implement IPSEC offload. If we
+add support for v1.5 to the Linux PF, then we lose support for IPSEC
+offload.
+
+A full solution likely requires a new mailbox API with a proper negotiation
+to check that IPSEC is actually supported by the host.
+
+Fixes: 339f28964147 ("ixgbevf: Add support for new mailbox communication between PF and VF")
+Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ixgbevf/ipsec.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
+index 66cf17f194082..f804b35d79c72 100644
+--- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c
++++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
+@@ -629,7 +629,6 @@ void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter)
+       switch (adapter->hw.api_version) {
+       case ixgbe_mbox_api_14:
+-      case ixgbe_mbox_api_15:
+               break;
+       default:
+               return;
+-- 
+2.43.0
+
diff --git a/queue-6.6/kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch b/queue-6.6/kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch
new file mode 100644 (file)
index 0000000..e71e77d
--- /dev/null
@@ -0,0 +1,66 @@
+From ce0990dfeedc1119319c45710975ce08a745f787 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Apr 2024 16:05:22 +0100
+Subject: KVM: arm64: Change kvm_handle_mmio_return() return polarity
+
+From: Fuad Tabba <tabba@google.com>
+
+[ Upstream commit cc81b6dfc3bc82c3a2600eefbd3823bdb2190197 ]
+
+Most exit handlers return <= 0 to indicate that the host needs to
+handle the exit. Make kvm_handle_mmio_return() consistent with
+the exit handlers in handle_exit(). This makes the code easier to
+reason about, and makes it easier to add other handlers in future
+patches.
+
+No functional change intended.
+
+Signed-off-by: Fuad Tabba <tabba@google.com>
+Acked-by: Oliver Upton <oliver.upton@linux.dev>
+Link: https://lore.kernel.org/r/20240423150538.2103045-15-tabba@google.com
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Stable-dep-of: e735a5da6442 ("KVM: arm64: Don't retire aborted MMIO instruction")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kvm/arm.c  | 2 +-
+ arch/arm64/kvm/mmio.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
+index 4742e6c5ea7a0..ffdc2c4d07ee8 100644
+--- a/arch/arm64/kvm/arm.c
++++ b/arch/arm64/kvm/arm.c
+@@ -900,7 +900,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+       if (run->exit_reason == KVM_EXIT_MMIO) {
+               ret = kvm_handle_mmio_return(vcpu);
+-              if (ret)
++              if (ret <= 0)
+                       return ret;
+       }
+diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c
+index 3dd38a151d2a6..886ef30e12196 100644
+--- a/arch/arm64/kvm/mmio.c
++++ b/arch/arm64/kvm/mmio.c
+@@ -86,7 +86,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
+       /* Detect an already handled MMIO return */
+       if (unlikely(!vcpu->mmio_needed))
+-              return 0;
++              return 1;
+       vcpu->mmio_needed = 0;
+@@ -117,7 +117,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
+        */
+       kvm_incr_pc(vcpu);
+-      return 0;
++      return 1;
+ }
+ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
+-- 
+2.43.0
+
diff --git a/queue-6.6/kvm-arm64-don-t-retire-aborted-mmio-instruction.patch b/queue-6.6/kvm-arm64-don-t-retire-aborted-mmio-instruction.patch
new file mode 100644 (file)
index 0000000..39f88c6
--- /dev/null
@@ -0,0 +1,106 @@
+From e47b4a47b2f51b393a4cbd8b55210a915a74f5a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Oct 2024 20:31:03 +0000
+Subject: KVM: arm64: Don't retire aborted MMIO instruction
+
+From: Oliver Upton <oliver.upton@linux.dev>
+
+[ Upstream commit e735a5da64420a86be370b216c269b5dd8e830e2 ]
+
+Returning an abort to the guest for an unsupported MMIO access is a
+documented feature of the KVM UAPI. Nevertheless, it's clear that this
+plumbing has seen limited testing, since userspace can trivially cause a
+WARN in the MMIO return:
+
+  WARNING: CPU: 0 PID: 30558 at arch/arm64/include/asm/kvm_emulate.h:536 kvm_handle_mmio_return+0x46c/0x5c4 arch/arm64/include/asm/kvm_emulate.h:536
+  Call trace:
+   kvm_handle_mmio_return+0x46c/0x5c4 arch/arm64/include/asm/kvm_emulate.h:536
+   kvm_arch_vcpu_ioctl_run+0x98/0x15b4 arch/arm64/kvm/arm.c:1133
+   kvm_vcpu_ioctl+0x75c/0xa78 virt/kvm/kvm_main.c:4487
+   __do_sys_ioctl fs/ioctl.c:51 [inline]
+   __se_sys_ioctl fs/ioctl.c:893 [inline]
+   __arm64_sys_ioctl+0x14c/0x1c8 fs/ioctl.c:893
+   __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
+   invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:49
+   el0_svc_common+0x1e0/0x23c arch/arm64/kernel/syscall.c:132
+   do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:151
+   el0_svc+0x38/0x68 arch/arm64/kernel/entry-common.c:712
+   el0t_64_sync_handler+0x90/0xfc arch/arm64/kernel/entry-common.c:730
+   el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:598
+
+The splat is complaining that KVM is advancing PC while an exception is
+pending, i.e. that KVM is retiring the MMIO instruction despite a
+pending synchronous external abort. Womp womp.
+
+Fix the glaring UAPI bug by skipping over all the MMIO emulation in
+case there is a pending synchronous exception. Note that while userspace
+is capable of pending an asynchronous exception (SError, IRQ, or FIQ),
+it is still safe to retire the MMIO instruction in this case as (1) they
+are by definition asynchronous, and (2) KVM relies on hardware support
+for pending/delivering these exceptions instead of the software state
+machine for advancing PC.
+
+Cc: stable@vger.kernel.org
+Fixes: da345174ceca ("KVM: arm/arm64: Allow user injection of external data aborts")
+Reported-by: Alexander Potapenko <glider@google.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20241025203106.3529261-2-oliver.upton@linux.dev
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kvm/mmio.c | 32 ++++++++++++++++++++++++++++++--
+ 1 file changed, 30 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c
+index 886ef30e12196..2aa503ff742ee 100644
+--- a/arch/arm64/kvm/mmio.c
++++ b/arch/arm64/kvm/mmio.c
+@@ -72,6 +72,31 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
+       return data;
+ }
++static bool kvm_pending_sync_exception(struct kvm_vcpu *vcpu)
++{
++      if (!vcpu_get_flag(vcpu, PENDING_EXCEPTION))
++              return false;
++
++      if (vcpu_el1_is_32bit(vcpu)) {
++              switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
++              case unpack_vcpu_flag(EXCEPT_AA32_UND):
++              case unpack_vcpu_flag(EXCEPT_AA32_IABT):
++              case unpack_vcpu_flag(EXCEPT_AA32_DABT):
++                      return true;
++              default:
++                      return false;
++              }
++      } else {
++              switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
++              case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC):
++              case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC):
++                      return true;
++              default:
++                      return false;
++              }
++      }
++}
++
+ /**
+  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+  *                         or in-kernel IO emulation
+@@ -84,8 +109,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
+       unsigned int len;
+       int mask;
+-      /* Detect an already handled MMIO return */
+-      if (unlikely(!vcpu->mmio_needed))
++      /*
++       * Detect if the MMIO return was already handled or if userspace aborted
++       * the MMIO access.
++       */
++      if (unlikely(!vcpu->mmio_needed || kvm_pending_sync_exception(vcpu)))
+               return 1;
+       vcpu->mmio_needed = 0;
+-- 
+2.43.0
+
diff --git a/queue-6.6/mlxsw-add-ipv4_5-flex-key.patch b/queue-6.6/mlxsw-add-ipv4_5-flex-key.patch
new file mode 100644 (file)
index 0000000..e554ab0
--- /dev/null
@@ -0,0 +1,142 @@
+From 10a5b6500a678710c1540ca568ae242f3c89786f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Sep 2023 17:42:54 +0200
+Subject: mlxsw: Add 'ipv4_5' flex key
+
+From: Amit Cohen <amcohen@nvidia.com>
+
+[ Upstream commit c2f3e10ac4ebf23e177226b9b4d297bfe2fb6b20 ]
+
+Currently virtual router ID element is broken to two sub-elements -
+'VIRT_ROUTER_LSB' and 'VIRT_ROUTER_MSB'. It was broken as this field is
+broken in 'ipv4_4' flex key which is used for IPv4 in Spectrum < 4.
+For Spectrum-4, we use 'ipv4_4b' flex key which contains one field for
+virtual router, this key is not supported in older ASICs.
+
+Add 'ipv4_5' flex key which is supported in all ASICs and contains one
+field for virtual router. Then there is no reason to use 'VIRT_ROUTER_LSB'
+and 'VIRT_ROUTER_MSB', remove them and add one element 'VIRT_ROUTER' for
+this field.
+
+The motivation is to get rid of 'ipv4_4' flex key, as it might be chosen
+for IPv6 multicast forwarding region. This will not allow the improvement
+in a following patch. See more details in the cover letter and in a
+following patch.
+
+Signed-off-by: Amit Cohen <amcohen@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlxsw/core_acl_flex_keys.c    |  3 +--
+ .../ethernet/mellanox/mlxsw/core_acl_flex_keys.h    |  3 +--
+ .../net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c | 13 ++++---------
+ .../mellanox/mlxsw/spectrum_acl_flex_keys.c         | 10 ++++------
+ 4 files changed, 10 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+index bf140e7416e19..5fa3800940c89 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+@@ -33,8 +33,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
+       MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8),
+       MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2),
+       MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6),
+-      MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x18, 17, 4),
+-      MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_LSB, 0x18, 21, 8),
++      MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER, 0x18, 17, 12),
+       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_96_127, 0x20, 4),
+       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_64_95, 0x24, 4),
+       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_32_63, 0x28, 4),
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+index 2eac7582c31a8..75e9bbc361701 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+@@ -33,8 +33,7 @@ enum mlxsw_afk_element {
+       MLXSW_AFK_ELEMENT_IP_TTL_,
+       MLXSW_AFK_ELEMENT_IP_ECN,
+       MLXSW_AFK_ELEMENT_IP_DSCP,
+-      MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
+-      MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
++      MLXSW_AFK_ELEMENT_VIRT_ROUTER,
+       MLXSW_AFK_ELEMENT_FDB_MISS,
+       MLXSW_AFK_ELEMENT_L4_PORT_RANGE,
+       MLXSW_AFK_ELEMENT_MAX,
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
+index b1178b7a7f51a..2efcc9372d4e6 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
+@@ -45,8 +45,7 @@ static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
+ }
+ static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
+-              MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
+-              MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
++              MLXSW_AFK_ELEMENT_VIRT_ROUTER,
+               MLXSW_AFK_ELEMENT_SRC_IP_0_31,
+               MLXSW_AFK_ELEMENT_DST_IP_0_31,
+ };
+@@ -89,8 +88,7 @@ static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
+ }
+ static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
+-              MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
+-              MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
++              MLXSW_AFK_ELEMENT_VIRT_ROUTER,
+               MLXSW_AFK_ELEMENT_SRC_IP_96_127,
+               MLXSW_AFK_ELEMENT_SRC_IP_64_95,
+               MLXSW_AFK_ELEMENT_SRC_IP_32_63,
+@@ -189,11 +187,8 @@ mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
+       rulei = mlxsw_sp_acl_rule_rulei(rule);
+       rulei->priority = priority;
+-      mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
+-                                     key->vrid, GENMASK(7, 0));
+-      mlxsw_sp_acl_rulei_keymask_u32(rulei,
+-                                     MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
+-                                     key->vrid >> 8, GENMASK(3, 0));
++      mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER,
++                                     key->vrid, GENMASK(11, 0));
+       switch (key->proto) {
+       case MLXSW_SP_L3_PROTO_IPV4:
+               return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+index cb746a43b24b3..cc00c8d69eb77 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+@@ -171,9 +171,8 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x04, 16, 8),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4[] = {
+-      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_LSB, 0x04, 24, 8),
+-      MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true),
++static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = {
++      MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER, 0x04, 20, 11, 0, true),
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = {
+@@ -220,7 +219,7 @@ static const struct mlxsw_afk_block mlxsw_sp2_afk_blocks[] = {
+       MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0),
+       MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1),
+       MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2),
+-      MLXSW_AFK_BLOCK(0x3C, mlxsw_sp_afk_element_info_ipv4_4),
++      MLXSW_AFK_BLOCK(0x3D, mlxsw_sp_afk_element_info_ipv4_5),
+       MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0),
+       MLXSW_AFK_BLOCK(0x41, mlxsw_sp_afk_element_info_ipv6_1),
+       MLXSW_AFK_BLOCK(0x42, mlxsw_sp_afk_element_info_ipv6_2),
+@@ -323,8 +322,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = {
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4b[] = {
+-      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_LSB, 0x04, 13, 8),
+-      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x04, 21, 4),
++      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 13, 12),
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
+-- 
+2.43.0
+
diff --git a/queue-6.6/mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch b/queue-6.6/mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch
new file mode 100644 (file)
index 0000000..de47e5d
--- /dev/null
@@ -0,0 +1,172 @@
+From a288b3d342fe307ffd9140160e95249b86d03744 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Sep 2023 17:42:56 +0200
+Subject: mlxsw: Edit IPv6 key blocks to use one less block for multicast
+ forwarding
+
+From: Amit Cohen <amcohen@nvidia.com>
+
+[ Upstream commit 92953e7aab013719aa8974805614c0bc11361026 ]
+
+Two ACL regions that are configured by the driver during initialization are
+the ones used for IPv4 and IPv6 multicast forwarding. Entries residing
+in these two regions match on the {SIP, DIP, VRID} key elements.
+
+Currently for IPv6 region, 9 key blocks are used:
+* 4 for SIP - 'ipv4_1', 'ipv6_{3,4,5}'
+* 4 for DIP - 'ipv4_0', 'ipv6_{0,1,2/2b}'
+* 1 for VRID - 'ipv4_4b'
+
+This can be improved by reducing the amount key blocks needed for
+the IPv6 region to 8. It is possible to use key blocks that mix subsets of
+the VRID element with subsets of the DIP element.
+The following key blocks can be used:
+* 4 for SIP - 'ipv4_1', 'ipv6_{3,4,5}'
+* 1 for subset of DIP - 'ipv4_0'
+* 3 for the rest of DIP and subsets of VRID - 'ipv6_{0,1,2/2b}'
+
+To make this happen, add VRID sub-elements as part of existing keys -
+'ipv6_{0,1,2/2b}'. Note that one of the sub-elements is called
+VRID_ROUTER_MSB and does not contain bit numbers like the rest, as for
+Spectrum < 4 this element represents bits 8-10 and for Spectrum-4 it
+represents bits 8-11.
+
+Breaking VRID into 3 sub-elements makes the driver use one less block in
+IPv6 region for multicast forwarding. The sub-elements can be filled in
+blocks that are used for destination IP.
+
+The algorithm in the driver that chooses which key blocks will be used is
+lazy and not the optimal one. It searches the block that contains the most
+elements that are required, chooses it, removes the elements that appear
+in the chosen block and starts again searching the block that contains the
+most elements.
+
+When key block 'ipv4_4' is defined, the algorithm might choose it, as it
+contains 2 sub-elements of VRID, then 8 blocks must be chosen for SIP and
+DIP and we get 9 blocks to match on {SIP, DIP, VRID}. That is why we had to
+remove key block 'ipv4_4' in a previous patch and use key block that
+contains one field for VRID.
+
+This improvement was tested and indeed 8 blocks are used instead of 9.
+
+Signed-off-by: Amit Cohen <amcohen@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlxsw/core_acl_flex_keys.c  |  3 +++
+ .../ethernet/mellanox/mlxsw/core_acl_flex_keys.h  |  3 +++
+ .../ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c   | 15 ++++++++++++---
+ .../mellanox/mlxsw/spectrum_acl_flex_keys.c       |  4 ++++
+ 4 files changed, 22 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+index 5fa3800940c89..654dafc9b54d3 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+@@ -44,6 +44,9 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
+       MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_0_31, 0x3C, 4),
+       MLXSW_AFK_ELEMENT_INFO_U32(FDB_MISS, 0x40, 0, 1),
+       MLXSW_AFK_ELEMENT_INFO_U32(L4_PORT_RANGE, 0x40, 1, 16),
++      MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_0_3, 0x40, 17, 4),
++      MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_4_7, 0x40, 21, 4),
++      MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x40, 25, 4),
+ };
+ struct mlxsw_afk {
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+index 75e9bbc361701..1c76aa3ffab72 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+@@ -36,6 +36,9 @@ enum mlxsw_afk_element {
+       MLXSW_AFK_ELEMENT_VIRT_ROUTER,
+       MLXSW_AFK_ELEMENT_FDB_MISS,
+       MLXSW_AFK_ELEMENT_L4_PORT_RANGE,
++      MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
++      MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
++      MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
+       MLXSW_AFK_ELEMENT_MAX,
+ };
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
+index 2efcc9372d4e6..99eeafdc8d1e4 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
+@@ -88,7 +88,9 @@ static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
+ }
+ static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
+-              MLXSW_AFK_ELEMENT_VIRT_ROUTER,
++              MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
++              MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
++              MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
+               MLXSW_AFK_ELEMENT_SRC_IP_96_127,
+               MLXSW_AFK_ELEMENT_SRC_IP_64_95,
+               MLXSW_AFK_ELEMENT_SRC_IP_32_63,
+@@ -140,6 +142,8 @@ static void
+ mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
+                             struct mlxsw_sp_mr_route_key *key)
+ {
++      mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER,
++                                     key->vrid, GENMASK(11, 0));
+       mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
+                                      (char *) &key->source.addr4,
+                                      (char *) &key->source_mask.addr4, 4);
+@@ -152,6 +156,13 @@ static void
+ mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
+                             struct mlxsw_sp_mr_route_key *key)
+ {
++      mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
++                                     key->vrid, GENMASK(3, 0));
++      mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
++                                     key->vrid >> 4, GENMASK(3, 0));
++      mlxsw_sp_acl_rulei_keymask_u32(rulei,
++                                     MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
++                                     key->vrid >> 8, GENMASK(3, 0));
+       mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
+                                      &key->source.addr6.s6_addr[0x0],
+                                      &key->source_mask.addr6.s6_addr[0x0], 4);
+@@ -187,8 +198,6 @@ mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
+       rulei = mlxsw_sp_acl_rule_rulei(rule);
+       rulei->priority = priority;
+-      mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER,
+-                                     key->vrid, GENMASK(11, 0));
+       switch (key->proto) {
+       case MLXSW_SP_L3_PROTO_IPV4:
+               return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+index 7d66c4f2deeaa..4b3564f5fd652 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+@@ -176,14 +176,17 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = {
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = {
++      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_0_3, 0x00, 0, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x04, 4),
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = {
++      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_4_7, 0x00, 0, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4),
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = {
++      MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4),
+ };
+@@ -326,6 +329,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = {
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
++      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x00, 0, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4),
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.6/mlxsw-mark-high-entropy-key-blocks.patch b/queue-6.6/mlxsw-mark-high-entropy-key-blocks.patch
new file mode 100644 (file)
index 0000000..cd31b2e
--- /dev/null
@@ -0,0 +1,100 @@
+From 654d26c2edfba386e4aac9a80e8da447cd36318b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Oct 2023 13:25:26 +0200
+Subject: mlxsw: Mark high entropy key blocks
+
+From: Amit Cohen <amcohen@nvidia.com>
+
+[ Upstream commit cad6431b867507779c41b00baaf18382467ef0a0 ]
+
+For 12 key blocks in the A-TCAM, rules are split into two records, which
+constitute two lookups. The two records are linked using a
+"large entry key ID".
+
+Due to a Spectrum-4 hardware issue, KVD entries that correspond to key
+blocks 0 to 5 of 12 key blocks A-TCAM entries will be placed in the same
+KVD pipe if they only differ in their "large entry key ID", as it is
+ignored. This results in a reduced scale. To reduce the probability of this
+issue, we can place key blocks with high entropy in blocks 0 to 5. The idea
+is to place blocks that are changed often in blocks 0 to 5, for
+example, key blocks that match on IPv4 addresses or the LSBs of IPv6
+addresses. Such placement will reduce the probability of these blocks to be
+same.
+
+Mark several blocks with 'high_entropy' flag, so later we will take into
+account this flag and place them in blocks 0 to 5.
+
+Signed-off-by: Amit Cohen <amcohen@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h |  9 +++++++++
+ .../ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c | 12 ++++++------
+ 2 files changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+index 1c76aa3ffab72..98a05598178b3 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+@@ -119,6 +119,7 @@ struct mlxsw_afk_block {
+       u16 encoding; /* block ID */
+       struct mlxsw_afk_element_inst *instances;
+       unsigned int instances_count;
++      bool high_entropy;
+ };
+ #define MLXSW_AFK_BLOCK(_encoding, _instances)                                        \
+@@ -128,6 +129,14 @@ struct mlxsw_afk_block {
+               .instances_count = ARRAY_SIZE(_instances),                      \
+       }
++#define MLXSW_AFK_BLOCK_HIGH_ENTROPY(_encoding, _instances)                   \
++      {                                                                       \
++              .encoding = _encoding,                                          \
++              .instances = _instances,                                        \
++              .instances_count = ARRAY_SIZE(_instances),                      \
++              .high_entropy = true,                                           \
++      }
++
+ struct mlxsw_afk_element_usage {
+       DECLARE_BITMAP(usage, MLXSW_AFK_ELEMENT_MAX);
+ };
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+index 4b3564f5fd652..eaad786056027 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+@@ -334,14 +334,14 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
+ };
+ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = {
+-      MLXSW_AFK_BLOCK(0x10, mlxsw_sp_afk_element_info_mac_0),
+-      MLXSW_AFK_BLOCK(0x11, mlxsw_sp_afk_element_info_mac_1),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x10, mlxsw_sp_afk_element_info_mac_0),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x11, mlxsw_sp_afk_element_info_mac_1),
+       MLXSW_AFK_BLOCK(0x12, mlxsw_sp_afk_element_info_mac_2),
+       MLXSW_AFK_BLOCK(0x13, mlxsw_sp_afk_element_info_mac_3),
+       MLXSW_AFK_BLOCK(0x14, mlxsw_sp_afk_element_info_mac_4),
+-      MLXSW_AFK_BLOCK(0x1A, mlxsw_sp_afk_element_info_mac_5b),
+-      MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0),
+-      MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x1A, mlxsw_sp_afk_element_info_mac_5b),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x38, mlxsw_sp_afk_element_info_ipv4_0),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x39, mlxsw_sp_afk_element_info_ipv4_1),
+       MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2),
+       MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b),
+       MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0),
+@@ -350,7 +350,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = {
+       MLXSW_AFK_BLOCK(0x43, mlxsw_sp_afk_element_info_ipv6_3),
+       MLXSW_AFK_BLOCK(0x44, mlxsw_sp_afk_element_info_ipv6_4),
+       MLXSW_AFK_BLOCK(0x45, mlxsw_sp_afk_element_info_ipv6_5),
+-      MLXSW_AFK_BLOCK(0x90, mlxsw_sp_afk_element_info_l4_0),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x90, mlxsw_sp_afk_element_info_l4_0),
+       MLXSW_AFK_BLOCK(0x92, mlxsw_sp_afk_element_info_l4_2),
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.6/mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch b/queue-6.6/mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch
new file mode 100644 (file)
index 0000000..607094b
--- /dev/null
@@ -0,0 +1,50 @@
+From f70f6d644ac9cbc987903d09817dc596eeb16ea7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Sep 2023 17:42:55 +0200
+Subject: mlxsw: spectrum_acl_flex_keys: Add 'ipv4_5b' flex key
+
+From: Amit Cohen <amcohen@nvidia.com>
+
+[ Upstream commit c6caabdf3e0cc50ba4a44bebc82cda5551d81d4f ]
+
+The previous patch replaced the key block 'ipv4_4' with 'ipv4_5'. The
+corresponding block for Spectrum-4 is 'ipv4_4b'. To be consistent, replace
+key block 'ipv4_4b' with 'ipv4_5b'.
+
+Signed-off-by: Amit Cohen <amcohen@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c    | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+index cc00c8d69eb77..7d66c4f2deeaa 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+@@ -321,8 +321,8 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = {
+       MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4b[] = {
+-      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 13, 12),
++static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = {
++      MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12),
+ };
+ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
+@@ -339,7 +339,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = {
+       MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0),
+       MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1),
+       MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2),
+-      MLXSW_AFK_BLOCK(0x35, mlxsw_sp_afk_element_info_ipv4_4b),
++      MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b),
+       MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0),
+       MLXSW_AFK_BLOCK(0x41, mlxsw_sp_afk_element_info_ipv6_1),
+       MLXSW_AFK_BLOCK(0x47, mlxsw_sp_afk_element_info_ipv6_2b),
+-- 
+2.43.0
+
diff --git a/queue-6.6/mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch b/queue-6.6/mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch
new file mode 100644 (file)
index 0000000..c0dc341
--- /dev/null
@@ -0,0 +1,312 @@
+From 181ff20aab66e26df125138b1f4ff3e7cabd1ac2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Oct 2024 07:26:05 +0200
+Subject: mlxsw: spectrum_acl_flex_keys: Constify struct mlxsw_afk_element_inst
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit bec2a32145d5cc066df29182fa0e5b0d4329b1a1 ]
+
+'struct mlxsw_afk_element_inst' are not modified in these drivers.
+
+Constifying these structures moves some data to a read-only section, so
+increases overall security.
+
+Update a few functions and struct mlxsw_afk_block accordingly.
+
+On a x86_64, with allmodconfig, as an example:
+Before:
+======
+   text           data     bss     dec     hex filename
+   4278           4032       0    8310    2076 drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.o
+
+After:
+=====
+   text           data     bss     dec     hex filename
+   7934            352       0    8286    205e drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.o
+
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/8ccfc7bfb2365dcee5b03c81ebe061a927d6da2e.1727541677.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../mellanox/mlxsw/core_acl_flex_keys.c       |  6 +-
+ .../mellanox/mlxsw/core_acl_flex_keys.h       |  2 +-
+ .../mellanox/mlxsw/spectrum_acl_flex_keys.c   | 66 +++++++++----------
+ 3 files changed, 37 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+index 654dafc9b54d3..57a1a55856a51 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+@@ -67,7 +67,7 @@ static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk)
+               for (j = 0; j < block->instances_count; j++) {
+                       const struct mlxsw_afk_element_info *elinfo;
+-                      struct mlxsw_afk_element_inst *elinst;
++                      const struct mlxsw_afk_element_inst *elinst;
+                       elinst = &block->instances[j];
+                       elinfo = &mlxsw_afk_element_infos[elinst->element];
+@@ -153,7 +153,7 @@ static void mlxsw_afk_picker_count_hits(struct mlxsw_afk *mlxsw_afk,
+               const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i];
+               for (j = 0; j < block->instances_count; j++) {
+-                      struct mlxsw_afk_element_inst *elinst;
++                      const struct mlxsw_afk_element_inst *elinst;
+                       elinst = &block->instances[j];
+                       if (elinst->element == element) {
+@@ -336,7 +336,7 @@ mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block,
+       int i;
+       for (i = 0; i < block->instances_count; i++) {
+-              struct mlxsw_afk_element_inst *elinst;
++              const struct mlxsw_afk_element_inst *elinst;
+               elinst = &block->instances[i];
+               if (elinst->element == element)
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+index 98a05598178b3..5aa1afb3f2ca8 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+@@ -117,7 +117,7 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */
+ struct mlxsw_afk_block {
+       u16 encoding; /* block ID */
+-      struct mlxsw_afk_element_inst *instances;
++      const struct mlxsw_afk_element_inst *instances;
+       unsigned int instances_count;
+       bool high_entropy;
+ };
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+index eaad786056027..6fe185ea6732c 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+@@ -7,7 +7,7 @@
+ #include "item.h"
+ #include "core_acl_flex_keys.h"
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x00, 2),
+       MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x02, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3),
+@@ -15,7 +15,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x00, 2),
+       MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x02, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3),
+@@ -23,27 +23,27 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x02, 2),
+       MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x0C, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
+       MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
+       MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_ECN, 0x04, 4, 2),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_TTL_, 0x04, 24, 8),
+@@ -51,35 +51,35 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x08, 8, 9), /* TCP_CONTROL+TCP_ECN */
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VID, 0x00, 0, 12),
+       MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 29, 3),
+       MLXSW_AFK_ELEMENT_INST_U32(SRC_L4_PORT, 0x08, 0, 16),
+       MLXSW_AFK_ELEMENT_INST_U32(DST_L4_PORT, 0x0C, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_dip[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_dip[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_ex1[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_ex1[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_32_63, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip_ex[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip_ex[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_96_127, 0x00, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_64_95, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_packet_type[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_packet_type[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x00, 0, 16),
+ };
+@@ -124,90 +124,90 @@ const struct mlxsw_afk_ops mlxsw_sp1_afk_ops = {
+       .clear_block    = mlxsw_sp1_afk_clear_block,
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1),
+       MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_1[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_1[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1),
+       MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_2[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_2[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x04, 2),
+       MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x06, 2),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_3[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_3[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x00, 0, 3),
+       MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12),
+       MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x06, 2),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x00, 0, 3),
+       MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12),
+       MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x04, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12),
+       MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 8, -1, true), /* RX_ACL_SYSTEM_PORT */
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(IP_DSCP, 0x04, 0, 6),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_ECN, 0x04, 6, 2),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_TTL_, 0x04, 8, 8),
+       MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x04, 16, 8),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = {
+       MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER, 0x04, 20, 11, 0, true),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_0_3, 0x00, 0, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_4_7, 0x00, 0, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = {
+       MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_3[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_3[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_32_63, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_4[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_4[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_64_95, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_5[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_5[] = {
+       MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_96_127, 0x04, 4),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(SRC_L4_PORT, 0x04, 16, 16),
+       MLXSW_AFK_ELEMENT_INST_U32(DST_L4_PORT, 0x04, 0, 16),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x04, 16, 9), /* TCP_CONTROL + TCP_ECN */
+       MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 0, 16),
+ };
+@@ -319,16 +319,16 @@ const struct mlxsw_afk_ops mlxsw_sp2_afk_ops = {
+       .clear_block    = mlxsw_sp2_afk_clear_block,
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 18, 12),
+       MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12),
+ };
+-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x00, 0, 4),
+       MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4),
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.6/mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch b/queue-6.6/mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch
new file mode 100644 (file)
index 0000000..2d84e1f
--- /dev/null
@@ -0,0 +1,58 @@
+From 15c1e15da8ca17eb7e5af14c90cddfd968cf4061 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 16:16:05 +0100
+Subject: mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4
+
+From: Ido Schimmel <idosch@nvidia.com>
+
+[ Upstream commit 217bbf156f93ada86b91617489e7ba8a0904233c ]
+
+The driver is currently using an ACL key block that is not supported by
+Spectrum-4. This works because the driver is only using a single field
+from this key block which is located in the same offset in the
+equivalent Spectrum-4 key block.
+
+The issue was discovered when the firmware started rejecting the use of
+the unsupported key block. The change has been reverted to avoid
+breaking users that only update their firmware.
+
+Nonetheless, fix the issue by using the correct key block.
+
+Fixes: 07ff135958dd ("mlxsw: Introduce flex key elements for Spectrum-4")
+Signed-off-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: Petr Machata <petrm@nvidia.com>
+Link: https://patch.msgid.link/35e72c97bdd3bc414fb8e4d747e5fb5d26c29658.1733237440.git.petrm@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c    | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+index 6fe185ea6732c..1850a975b3804 100644
+--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+@@ -324,6 +324,10 @@ static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] =
+       MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */
+ };
++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1b[] = {
++      MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4),
++};
++
+ static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = {
+       MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12),
+ };
+@@ -341,7 +345,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = {
+       MLXSW_AFK_BLOCK(0x14, mlxsw_sp_afk_element_info_mac_4),
+       MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x1A, mlxsw_sp_afk_element_info_mac_5b),
+       MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x38, mlxsw_sp_afk_element_info_ipv4_0),
+-      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x39, mlxsw_sp_afk_element_info_ipv4_1),
++      MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x3F, mlxsw_sp_afk_element_info_ipv4_1b),
+       MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2),
+       MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b),
+       MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0),
+-- 
+2.43.0
+
diff --git a/queue-6.6/mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch b/queue-6.6/mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch
new file mode 100644 (file)
index 0000000..d555a3f
--- /dev/null
@@ -0,0 +1,40 @@
+From 5303e9ecc70c27ade30475bab0be414db2576057 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Sep 2024 15:49:19 -0700
+Subject: mmc: mtk-sd: fix devm_clk_get_optional usage
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit ed299eda8fbb37cb0e05c7001ab6a6b2627ec087 ]
+
+This already returns NULL when not found. However, it can return
+EPROBE_DEFER and should thus return here.
+
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Link: https://lore.kernel.org/r/20240930224919.355359-4-rosenp@gmail.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Stable-dep-of: 2508925fb346 ("mmc: mtk-sd: Fix MMC_CAP2_CRYPTO flag setting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/mtk-sd.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
+index a97034388cdff..c5e96a2c079e5 100644
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -2711,9 +2711,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
+       if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
+               host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
+               if (IS_ERR(host->crypto_clk))
+-                      host->crypto_clk = NULL;
+-              else
+-                      mmc->caps2 |= MMC_CAP2_CRYPTO;
++                      return PTR_ERR(host->crypto_clk);
++              mmc->caps2 |= MMC_CAP2_CRYPTO;
+       }
+       host->irq = platform_get_irq(pdev, 0);
+-- 
+2.43.0
+
diff --git a/queue-6.6/mmc-mtk-sd-fix-error-handle-of-probe-function.patch b/queue-6.6/mmc-mtk-sd-fix-error-handle-of-probe-function.patch
new file mode 100644 (file)
index 0000000..9b326bb
--- /dev/null
@@ -0,0 +1,86 @@
+From 61788dcf2b34924a0af024bf09b4d506d3d16e7b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 7 Nov 2024 20:11:21 +0800
+Subject: mmc: mtk-sd: Fix error handle of probe function
+
+From: Andy-ld Lu <andy-ld.lu@mediatek.com>
+
+[ Upstream commit 291220451c775a054cedc4fab4578a1419eb6256 ]
+
+In the probe function, it goes to 'release_mem' label and returns after
+some procedure failure. But if the clocks (partial or all) have been
+enabled previously, they would not be disabled in msdc_runtime_suspend,
+since runtime PM is not yet enabled for this case.
+
+That cause mmc related clocks always on during system suspend and block
+suspend flow. Below log is from a SDCard issue of MT8196 chromebook, it
+returns -ETIMEOUT while polling clock stable in the msdc_ungate_clock()
+and probe failed, but the enabled clocks could not be disabled anyway.
+
+[  129.059253] clk_chk_dev_pm_suspend()
+[  129.350119] suspend warning: msdcpll is on
+[  129.354494] [ck_msdc30_1_sel : enabled, 1, 1, 191999939,   ck_msdcpll_d2]
+[  129.362787] [ck_msdcpll_d2   : enabled, 1, 1, 191999939,         msdcpll]
+[  129.371041] [ck_msdc30_1_ck  : enabled, 1, 1, 191999939, ck_msdc30_1_sel]
+[  129.379295] [msdcpll         : enabled, 1, 1, 383999878,          clk26m]
+
+Add a new 'release_clk' label and reorder the error handle functions to
+make sure the clocks be disabled after probe failure.
+
+Fixes: ffaea6ebfe9c ("mmc: mtk-sd: Use readl_poll_timeout instead of open-coded polling")
+Fixes: 7a2fa8eed936 ("mmc: mtk-sd: use devm_mmc_alloc_host")
+Signed-off-by: Andy-ld Lu <andy-ld.lu@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Cc: stable@vger.kernel.org
+Message-ID: <20241107121215.5201-1-andy-ld.lu@mediatek.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/mtk-sd.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
+index 9ebf5aa5d9b18..a97034388cdff 100644
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -2813,7 +2813,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
+       ret = msdc_ungate_clock(host);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot ungate clocks!\n");
+-              goto release_mem;
++              goto release_clk;
+       }
+       msdc_init_hw(host);
+@@ -2823,14 +2823,14 @@ static int msdc_drv_probe(struct platform_device *pdev)
+                                            GFP_KERNEL);
+               if (!host->cq_host) {
+                       ret = -ENOMEM;
+-                      goto release_mem;
++                      goto release;
+               }
+               host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
+               host->cq_host->mmio = host->base + 0x800;
+               host->cq_host->ops = &msdc_cmdq_ops;
+               ret = cqhci_init(host->cq_host, mmc, true);
+               if (ret)
+-                      goto release_mem;
++                      goto release;
+               mmc->max_segs = 128;
+               /* cqhci 16bit length */
+               /* 0 size, means 65536 so we don't have to -1 here */
+@@ -2857,9 +2857,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
+ end:
+       pm_runtime_disable(host->dev);
+ release:
+-      platform_set_drvdata(pdev, NULL);
+       msdc_deinit_hw(host);
++release_clk:
+       msdc_gate_clock(host);
++      platform_set_drvdata(pdev, NULL);
+ release_mem:
+       if (host->dma.gpd)
+               dma_free_coherent(&pdev->dev,
+-- 
+2.43.0
+
diff --git a/queue-6.6/mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch b/queue-6.6/mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch
new file mode 100644 (file)
index 0000000..8b33204
--- /dev/null
@@ -0,0 +1,45 @@
+From dafce777b6fcd2cd94772bff5136d37b26006622 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 11 Nov 2024 16:49:31 +0800
+Subject: mmc: mtk-sd: Fix MMC_CAP2_CRYPTO flag setting
+
+From: Andy-ld Lu <andy-ld.lu@mediatek.com>
+
+[ Upstream commit 2508925fb346661bad9f50b497d7ac7d0b6085d0 ]
+
+Currently, the MMC_CAP2_CRYPTO flag is set by default for eMMC hosts.
+However, this flag should not be set for hosts that do not support inline
+encryption.
+
+The 'crypto' clock, as described in the documentation, is used for data
+encryption and decryption. Therefore, only hosts that are configured with
+this 'crypto' clock should have the MMC_CAP2_CRYPTO flag set.
+
+Fixes: 7b438d0377fb ("mmc: mtk-sd: add Inline Crypto Engine clock control")
+Fixes: ed299eda8fbb ("mmc: mtk-sd: fix devm_clk_get_optional usage")
+Signed-off-by: Andy-ld Lu <andy-ld.lu@mediatek.com>
+Cc: stable@vger.kernel.org
+Message-ID: <20241111085039.26527-1-andy-ld.lu@mediatek.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/mtk-sd.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
+index c5e96a2c079e5..1896bf6746071 100644
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -2712,7 +2712,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
+               host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
+               if (IS_ERR(host->crypto_clk))
+                       return PTR_ERR(host->crypto_clk);
+-              mmc->caps2 |= MMC_CAP2_CRYPTO;
++              else if (host->crypto_clk)
++                      mmc->caps2 |= MMC_CAP2_CRYPTO;
+       }
+       host->irq = platform_get_irq(pdev, 0);
+-- 
+2.43.0
+
diff --git a/queue-6.6/mmc-mtk-sd-use-devm_mmc_alloc_host.patch b/queue-6.6/mmc-mtk-sd-use-devm_mmc_alloc_host.patch
new file mode 100644 (file)
index 0000000..030dd45
--- /dev/null
@@ -0,0 +1,159 @@
+From 28cc86983c09769725400af9458287a9c121acf8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 30 Sep 2024 15:49:17 -0700
+Subject: mmc: mtk-sd: use devm_mmc_alloc_host
+
+From: Rosen Penev <rosenp@gmail.com>
+
+[ Upstream commit 7a2fa8eed936b33b22e49b1d2349cd7d02f22710 ]
+
+Allows removing several gotos.
+
+Also fixed some wrong ones.
+
+Added dev_err_probe where EPROBE_DEFER is possible.
+
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+Link: https://lore.kernel.org/r/20240930224919.355359-2-rosenp@gmail.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Stable-dep-of: 291220451c77 ("mmc: mtk-sd: Fix error handle of probe function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/mtk-sd.c | 55 ++++++++++++++-------------------------
+ 1 file changed, 20 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
+index 8b755f1627325..9ebf5aa5d9b18 100644
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -2674,20 +2674,18 @@ static int msdc_drv_probe(struct platform_device *pdev)
+       }
+       /* Allocate MMC host for this device */
+-      mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
++      mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct msdc_host));
+       if (!mmc)
+               return -ENOMEM;
+       host = mmc_priv(mmc);
+       ret = mmc_of_parse(mmc);
+       if (ret)
+-              goto host_free;
++              return ret;
+       host->base = devm_platform_ioremap_resource(pdev, 0);
+-      if (IS_ERR(host->base)) {
+-              ret = PTR_ERR(host->base);
+-              goto host_free;
+-      }
++      if (IS_ERR(host->base))
++              return PTR_ERR(host->base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res) {
+@@ -2698,18 +2696,16 @@ static int msdc_drv_probe(struct platform_device *pdev)
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret)
+-              goto host_free;
++              return ret;
+       ret = msdc_of_clock_parse(pdev, host);
+       if (ret)
+-              goto host_free;
++              return ret;
+       host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                               "hrst");
+-      if (IS_ERR(host->reset)) {
+-              ret = PTR_ERR(host->reset);
+-              goto host_free;
+-      }
++      if (IS_ERR(host->reset))
++              return PTR_ERR(host->reset);
+       /* only eMMC has crypto property */
+       if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
+@@ -2721,30 +2717,24 @@ static int msdc_drv_probe(struct platform_device *pdev)
+       }
+       host->irq = platform_get_irq(pdev, 0);
+-      if (host->irq < 0) {
+-              ret = host->irq;
+-              goto host_free;
+-      }
++      if (host->irq < 0)
++              return host->irq;
+       host->pinctrl = devm_pinctrl_get(&pdev->dev);
+-      if (IS_ERR(host->pinctrl)) {
+-              ret = PTR_ERR(host->pinctrl);
+-              dev_err(&pdev->dev, "Cannot find pinctrl!\n");
+-              goto host_free;
+-      }
++      if (IS_ERR(host->pinctrl))
++              return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl),
++                                   "Cannot find pinctrl");
+       host->pins_default = pinctrl_lookup_state(host->pinctrl, "default");
+       if (IS_ERR(host->pins_default)) {
+-              ret = PTR_ERR(host->pins_default);
+               dev_err(&pdev->dev, "Cannot find pinctrl default!\n");
+-              goto host_free;
++              return PTR_ERR(host->pins_default);
+       }
+       host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
+       if (IS_ERR(host->pins_uhs)) {
+-              ret = PTR_ERR(host->pins_uhs);
+               dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n");
+-              goto host_free;
++              return PTR_ERR(host->pins_uhs);
+       }
+       /* Support for SDIO eint irq ? */
+@@ -2833,14 +2823,14 @@ static int msdc_drv_probe(struct platform_device *pdev)
+                                            GFP_KERNEL);
+               if (!host->cq_host) {
+                       ret = -ENOMEM;
+-                      goto host_free;
++                      goto release_mem;
+               }
+               host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
+               host->cq_host->mmio = host->base + 0x800;
+               host->cq_host->ops = &msdc_cmdq_ops;
+               ret = cqhci_init(host->cq_host, mmc, true);
+               if (ret)
+-                      goto host_free;
++                      goto release_mem;
+               mmc->max_segs = 128;
+               /* cqhci 16bit length */
+               /* 0 size, means 65536 so we don't have to -1 here */
+@@ -2877,11 +2867,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
+                       host->dma.gpd, host->dma.gpd_addr);
+       if (host->dma.bd)
+               dma_free_coherent(&pdev->dev,
+-                      MAX_BD_NUM * sizeof(struct mt_bdma_desc),
+-                      host->dma.bd, host->dma.bd_addr);
+-host_free:
+-      mmc_free_host(mmc);
+-
++                                MAX_BD_NUM * sizeof(struct mt_bdma_desc),
++                                host->dma.bd, host->dma.bd_addr);
+       return ret;
+ }
+@@ -2906,9 +2893,7 @@ static void msdc_drv_remove(struct platform_device *pdev)
+                       2 * sizeof(struct mt_gpdma_desc),
+                       host->dma.gpd, host->dma.gpd_addr);
+       dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
+-                      host->dma.bd, host->dma.bd_addr);
+-
+-      mmc_free_host(mmc);
++                        host->dma.bd, host->dma.bd_addr);
+ }
+ static void msdc_save_reg(struct msdc_host *host)
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-avoid-potential-uaf-in-default_operstate.patch b/queue-6.6/net-avoid-potential-uaf-in-default_operstate.patch
new file mode 100644 (file)
index 0000000..f0e7c19
--- /dev/null
@@ -0,0 +1,226 @@
+From 0b4530e8f42410c919b118b5510811a1e74311dd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 17:09:33 +0000
+Subject: net: avoid potential UAF in default_operstate()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 750e51603395e755537da08f745864c93e3ce741 ]
+
+syzbot reported an UAF in default_operstate() [1]
+
+Issue is a race between device and netns dismantles.
+
+After calling __rtnl_unlock() from netdev_run_todo(),
+we can not assume the netns of each device is still alive.
+
+Make sure the device is not in NETREG_UNREGISTERED state,
+and add an ASSERT_RTNL() before the call to
+__dev_get_by_index().
+
+We might move this ASSERT_RTNL() in __dev_get_by_index()
+in the future.
+
+[1]
+
+BUG: KASAN: slab-use-after-free in __dev_get_by_index+0x5d/0x110 net/core/dev.c:852
+Read of size 8 at addr ffff888043eba1b0 by task syz.0.0/5339
+
+CPU: 0 UID: 0 PID: 5339 Comm: syz.0.0 Not tainted 6.12.0-syzkaller-10296-gaaf20f870da0 #0
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
+Call Trace:
+ <TASK>
+  __dump_stack lib/dump_stack.c:94 [inline]
+  dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
+  print_address_description mm/kasan/report.c:378 [inline]
+  print_report+0x169/0x550 mm/kasan/report.c:489
+  kasan_report+0x143/0x180 mm/kasan/report.c:602
+  __dev_get_by_index+0x5d/0x110 net/core/dev.c:852
+  default_operstate net/core/link_watch.c:51 [inline]
+  rfc2863_policy+0x224/0x300 net/core/link_watch.c:67
+  linkwatch_do_dev+0x3e/0x170 net/core/link_watch.c:170
+  netdev_run_todo+0x461/0x1000 net/core/dev.c:10894
+  rtnl_unlock net/core/rtnetlink.c:152 [inline]
+  rtnl_net_unlock include/linux/rtnetlink.h:133 [inline]
+  rtnl_dellink+0x760/0x8d0 net/core/rtnetlink.c:3520
+  rtnetlink_rcv_msg+0x791/0xcf0 net/core/rtnetlink.c:6911
+  netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2541
+  netlink_unicast_kernel net/netlink/af_netlink.c:1321 [inline]
+  netlink_unicast+0x7f6/0x990 net/netlink/af_netlink.c:1347
+  netlink_sendmsg+0x8e4/0xcb0 net/netlink/af_netlink.c:1891
+  sock_sendmsg_nosec net/socket.c:711 [inline]
+  __sock_sendmsg+0x221/0x270 net/socket.c:726
+  ____sys_sendmsg+0x52a/0x7e0 net/socket.c:2583
+  ___sys_sendmsg net/socket.c:2637 [inline]
+  __sys_sendmsg+0x269/0x350 net/socket.c:2669
+  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+  do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7f2a3cb80809
+Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007f2a3d9cd058 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007f2a3cd45fa0 RCX: 00007f2a3cb80809
+RDX: 0000000000000000 RSI: 0000000020000000 RDI: 0000000000000008
+RBP: 00007f2a3cbf393e R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 0000000000000000 R14: 00007f2a3cd45fa0 R15: 00007ffd03bc65c8
+ </TASK>
+
+Allocated by task 5339:
+  kasan_save_stack mm/kasan/common.c:47 [inline]
+  kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
+  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
+  __kasan_kmalloc+0x98/0xb0 mm/kasan/common.c:394
+  kasan_kmalloc include/linux/kasan.h:260 [inline]
+  __kmalloc_cache_noprof+0x243/0x390 mm/slub.c:4314
+  kmalloc_noprof include/linux/slab.h:901 [inline]
+  kmalloc_array_noprof include/linux/slab.h:945 [inline]
+  netdev_create_hash net/core/dev.c:11870 [inline]
+  netdev_init+0x10c/0x250 net/core/dev.c:11890
+  ops_init+0x31e/0x590 net/core/net_namespace.c:138
+  setup_net+0x287/0x9e0 net/core/net_namespace.c:362
+  copy_net_ns+0x33f/0x570 net/core/net_namespace.c:500
+  create_new_namespaces+0x425/0x7b0 kernel/nsproxy.c:110
+  unshare_nsproxy_namespaces+0x124/0x180 kernel/nsproxy.c:228
+  ksys_unshare+0x57d/0xa70 kernel/fork.c:3314
+  __do_sys_unshare kernel/fork.c:3385 [inline]
+  __se_sys_unshare kernel/fork.c:3383 [inline]
+  __x64_sys_unshare+0x38/0x40 kernel/fork.c:3383
+  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+  do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 12:
+  kasan_save_stack mm/kasan/common.c:47 [inline]
+  kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
+  kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:582
+  poison_slab_object mm/kasan/common.c:247 [inline]
+  __kasan_slab_free+0x59/0x70 mm/kasan/common.c:264
+  kasan_slab_free include/linux/kasan.h:233 [inline]
+  slab_free_hook mm/slub.c:2338 [inline]
+  slab_free mm/slub.c:4598 [inline]
+  kfree+0x196/0x420 mm/slub.c:4746
+  netdev_exit+0x65/0xd0 net/core/dev.c:11992
+  ops_exit_list net/core/net_namespace.c:172 [inline]
+  cleanup_net+0x802/0xcc0 net/core/net_namespace.c:632
+  process_one_work kernel/workqueue.c:3229 [inline]
+  process_scheduled_works+0xa63/0x1850 kernel/workqueue.c:3310
+  worker_thread+0x870/0xd30 kernel/workqueue.c:3391
+  kthread+0x2f0/0x390 kernel/kthread.c:389
+  ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:147
+  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
+
+The buggy address belongs to the object at ffff888043eba000
+ which belongs to the cache kmalloc-2k of size 2048
+The buggy address is located 432 bytes inside of
+ freed 2048-byte region [ffff888043eba000, ffff888043eba800)
+
+The buggy address belongs to the physical page:
+page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x43eb8
+head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
+flags: 0x4fff00000000040(head|node=1|zone=1|lastcpupid=0x7ff)
+page_type: f5(slab)
+raw: 04fff00000000040 ffff88801ac42000 dead000000000122 0000000000000000
+raw: 0000000000000000 0000000000080008 00000001f5000000 0000000000000000
+head: 04fff00000000040 ffff88801ac42000 dead000000000122 0000000000000000
+head: 0000000000000000 0000000000080008 00000001f5000000 0000000000000000
+head: 04fff00000000003 ffffea00010fae01 ffffffffffffffff 0000000000000000
+head: 0000000000000008 0000000000000000 00000000ffffffff 0000000000000000
+page dumped because: kasan: bad access detected
+page_owner tracks the page as allocated
+page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5339, tgid 5338 (syz.0.0), ts 69674195892, free_ts 69663220888
+  set_page_owner include/linux/page_owner.h:32 [inline]
+  post_alloc_hook+0x1f3/0x230 mm/page_alloc.c:1556
+  prep_new_page mm/page_alloc.c:1564 [inline]
+  get_page_from_freelist+0x3649/0x3790 mm/page_alloc.c:3474
+  __alloc_pages_noprof+0x292/0x710 mm/page_alloc.c:4751
+  alloc_pages_mpol_noprof+0x3e8/0x680 mm/mempolicy.c:2265
+  alloc_slab_page+0x6a/0x140 mm/slub.c:2408
+  allocate_slab+0x5a/0x2f0 mm/slub.c:2574
+  new_slab mm/slub.c:2627 [inline]
+  ___slab_alloc+0xcd1/0x14b0 mm/slub.c:3815
+  __slab_alloc+0x58/0xa0 mm/slub.c:3905
+  __slab_alloc_node mm/slub.c:3980 [inline]
+  slab_alloc_node mm/slub.c:4141 [inline]
+  __do_kmalloc_node mm/slub.c:4282 [inline]
+  __kmalloc_noprof+0x2e6/0x4c0 mm/slub.c:4295
+  kmalloc_noprof include/linux/slab.h:905 [inline]
+  sk_prot_alloc+0xe0/0x210 net/core/sock.c:2165
+  sk_alloc+0x38/0x370 net/core/sock.c:2218
+  __netlink_create+0x65/0x260 net/netlink/af_netlink.c:629
+  __netlink_kernel_create+0x174/0x6f0 net/netlink/af_netlink.c:2015
+  netlink_kernel_create include/linux/netlink.h:62 [inline]
+  uevent_net_init+0xed/0x2d0 lib/kobject_uevent.c:783
+  ops_init+0x31e/0x590 net/core/net_namespace.c:138
+  setup_net+0x287/0x9e0 net/core/net_namespace.c:362
+page last free pid 1032 tgid 1032 stack trace:
+  reset_page_owner include/linux/page_owner.h:25 [inline]
+  free_pages_prepare mm/page_alloc.c:1127 [inline]
+  free_unref_page+0xdf9/0x1140 mm/page_alloc.c:2657
+  __slab_free+0x31b/0x3d0 mm/slub.c:4509
+  qlink_free mm/kasan/quarantine.c:163 [inline]
+  qlist_free_all+0x9a/0x140 mm/kasan/quarantine.c:179
+  kasan_quarantine_reduce+0x14f/0x170 mm/kasan/quarantine.c:286
+  __kasan_slab_alloc+0x23/0x80 mm/kasan/common.c:329
+  kasan_slab_alloc include/linux/kasan.h:250 [inline]
+  slab_post_alloc_hook mm/slub.c:4104 [inline]
+  slab_alloc_node mm/slub.c:4153 [inline]
+  kmem_cache_alloc_node_noprof+0x1d9/0x380 mm/slub.c:4205
+  __alloc_skb+0x1c3/0x440 net/core/skbuff.c:668
+  alloc_skb include/linux/skbuff.h:1323 [inline]
+  alloc_skb_with_frags+0xc3/0x820 net/core/skbuff.c:6612
+  sock_alloc_send_pskb+0x91a/0xa60 net/core/sock.c:2881
+  sock_alloc_send_skb include/net/sock.h:1797 [inline]
+  mld_newpack+0x1c3/0xaf0 net/ipv6/mcast.c:1747
+  add_grhead net/ipv6/mcast.c:1850 [inline]
+  add_grec+0x1492/0x19a0 net/ipv6/mcast.c:1988
+  mld_send_initial_cr+0x228/0x4b0 net/ipv6/mcast.c:2234
+  ipv6_mc_dad_complete+0x88/0x490 net/ipv6/mcast.c:2245
+  addrconf_dad_completed+0x712/0xcd0 net/ipv6/addrconf.c:4342
+ addrconf_dad_work+0xdc2/0x16f0
+  process_one_work kernel/workqueue.c:3229 [inline]
+  process_scheduled_works+0xa63/0x1850 kernel/workqueue.c:3310
+
+Memory state around the buggy address:
+ ffff888043eba080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+ ffff888043eba100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+>ffff888043eba180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+                                     ^
+ ffff888043eba200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+ ffff888043eba280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+
+Fixes: 8c55facecd7a ("net: linkwatch: only report IF_OPER_LOWERLAYERDOWN if iflink is actually down")
+Reported-by: syzbot+1939f24bdb783e9e43d9@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/674f3a18.050a0220.48a03.0041.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Link: https://patch.msgid.link/20241203170933.2449307-1-edumazet@google.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/link_watch.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/core/link_watch.c b/net/core/link_watch.c
+index cf867f6e38bf1..66422c95c83c7 100644
+--- a/net/core/link_watch.c
++++ b/net/core/link_watch.c
+@@ -45,9 +45,14 @@ static unsigned char default_operstate(const struct net_device *dev)
+               int iflink = dev_get_iflink(dev);
+               struct net_device *peer;
+-              if (iflink == dev->ifindex)
++              /* If called from netdev_run_todo()/linkwatch_sync_dev(),
++               * dev_net(dev) can be already freed, and RTNL is not held.
++               */
++              if (dev->reg_state == NETREG_UNREGISTERED ||
++                  iflink == dev->ifindex)
+                       return IF_OPER_DOWN;
++              ASSERT_RTNL();
+               peer = __dev_get_by_index(dev_net(dev), iflink);
+               if (!peer)
+                       return IF_OPER_DOWN;
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch b/queue-6.6/net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch
new file mode 100644 (file)
index 0000000..2e317c5
--- /dev/null
@@ -0,0 +1,69 @@
+From d5ecad4a6f4c6a54e1c388e0be84e9ae7b6fdf03 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Nov 2024 17:07:19 +0800
+Subject: net: enetc: Do not configure preemptible TCs if SIs do not support
+
+From: Wei Fang <wei.fang@nxp.com>
+
+[ Upstream commit b2420b8c81ec674552d00c55d46245e5c184b260 ]
+
+Both ENETC PF and VF drivers share enetc_setup_tc_mqprio() to configure
+MQPRIO. And enetc_setup_tc_mqprio() calls enetc_change_preemptible_tcs()
+to configure preemptible TCs. However, only PF is able to configure
+preemptible TCs. Because only PF has related registers, while VF does not
+have these registers. So for VF, its hw->port pointer is NULL. Therefore,
+VF will access an invalid pointer when accessing a non-existent register,
+which will cause a crash issue. The simplified log is as follows.
+
+root@ls1028ardb:~# tc qdisc add dev eno0vf0 parent root handle 100: \
+mqprio num_tc 4 map 0 0 1 1 2 2 3 3 queues 1@0 1@1 1@2 1@3 hw 1
+[  187.290775] Unable to handle kernel paging request at virtual address 0000000000001f00
+[  187.424831] pc : enetc_mm_commit_preemptible_tcs+0x1c4/0x400
+[  187.430518] lr : enetc_mm_commit_preemptible_tcs+0x30c/0x400
+[  187.511140] Call trace:
+[  187.513588]  enetc_mm_commit_preemptible_tcs+0x1c4/0x400
+[  187.518918]  enetc_setup_tc_mqprio+0x180/0x214
+[  187.523374]  enetc_vf_setup_tc+0x1c/0x30
+[  187.527306]  mqprio_enable_offload+0x144/0x178
+[  187.531766]  mqprio_init+0x3ec/0x668
+[  187.535351]  qdisc_create+0x15c/0x488
+[  187.539023]  tc_modify_qdisc+0x398/0x73c
+[  187.542958]  rtnetlink_rcv_msg+0x128/0x378
+[  187.547064]  netlink_rcv_skb+0x60/0x130
+[  187.550910]  rtnetlink_rcv+0x18/0x24
+[  187.554492]  netlink_unicast+0x300/0x36c
+[  187.558425]  netlink_sendmsg+0x1a8/0x420
+[  187.606759] ---[ end trace 0000000000000000 ]---
+
+In addition, some PFs also do not support configuring preemptible TCs,
+such as eno1 and eno3 on LS1028A. It won't crash like it does for VFs,
+but we should prevent these PFs from accessing these unimplemented
+registers.
+
+Fixes: 827145392a4a ("net: enetc: only commit preemptible TCs to hardware when MM TX is active")
+Signed-off-by: Wei Fang <wei.fang@nxp.com>
+Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/enetc/enetc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
+index c17b9e3385168..87b27bd7a13bb 100644
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -28,6 +28,9 @@ EXPORT_SYMBOL_GPL(enetc_port_mac_wr);
+ static void enetc_change_preemptible_tcs(struct enetc_ndev_priv *priv,
+                                        u8 preemptible_tcs)
+ {
++      if (!(priv->si->hw_features & ENETC_SI_F_QBU))
++              return;
++
+       priv->preemptible_tcs = preemptible_tcs;
+       enetc_mm_commit_preemptible_tcs(priv);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch b/queue-6.6/net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch
new file mode 100644 (file)
index 0000000..e92dfe5
--- /dev/null
@@ -0,0 +1,95 @@
+From ecbeee63d17470718c15e1f0f6c1e9357be4ffd8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 26 Nov 2024 14:43:44 +0000
+Subject: net: hsr: avoid potential out-of-bound access in fill_frame_info()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit b9653d19e556c6afd035602927a93d100a0d7644 ]
+
+syzbot is able to feed a packet with 14 bytes, pretending
+it is a vlan one.
+
+Since fill_frame_info() is relying on skb->mac_len already,
+extend the check to cover this case.
+
+BUG: KMSAN: uninit-value in fill_frame_info net/hsr/hsr_forward.c:709 [inline]
+ BUG: KMSAN: uninit-value in hsr_forward_skb+0x9ee/0x3b10 net/hsr/hsr_forward.c:724
+  fill_frame_info net/hsr/hsr_forward.c:709 [inline]
+  hsr_forward_skb+0x9ee/0x3b10 net/hsr/hsr_forward.c:724
+  hsr_dev_xmit+0x2f0/0x350 net/hsr/hsr_device.c:235
+  __netdev_start_xmit include/linux/netdevice.h:5002 [inline]
+  netdev_start_xmit include/linux/netdevice.h:5011 [inline]
+  xmit_one net/core/dev.c:3590 [inline]
+  dev_hard_start_xmit+0x247/0xa20 net/core/dev.c:3606
+  __dev_queue_xmit+0x366a/0x57d0 net/core/dev.c:4434
+  dev_queue_xmit include/linux/netdevice.h:3168 [inline]
+  packet_xmit+0x9c/0x6c0 net/packet/af_packet.c:276
+  packet_snd net/packet/af_packet.c:3146 [inline]
+  packet_sendmsg+0x91ae/0xa6f0 net/packet/af_packet.c:3178
+  sock_sendmsg_nosec net/socket.c:711 [inline]
+  __sock_sendmsg+0x30f/0x380 net/socket.c:726
+  __sys_sendto+0x594/0x750 net/socket.c:2197
+  __do_sys_sendto net/socket.c:2204 [inline]
+  __se_sys_sendto net/socket.c:2200 [inline]
+  __x64_sys_sendto+0x125/0x1d0 net/socket.c:2200
+  x64_sys_call+0x346a/0x3c30 arch/x86/include/generated/asm/syscalls_64.h:45
+  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+  do_syscall_64+0xcd/0x1e0 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Uninit was created at:
+  slab_post_alloc_hook mm/slub.c:4091 [inline]
+  slab_alloc_node mm/slub.c:4134 [inline]
+  kmem_cache_alloc_node_noprof+0x6bf/0xb80 mm/slub.c:4186
+  kmalloc_reserve+0x13d/0x4a0 net/core/skbuff.c:587
+  __alloc_skb+0x363/0x7b0 net/core/skbuff.c:678
+  alloc_skb include/linux/skbuff.h:1323 [inline]
+  alloc_skb_with_frags+0xc8/0xd00 net/core/skbuff.c:6612
+  sock_alloc_send_pskb+0xa81/0xbf0 net/core/sock.c:2881
+  packet_alloc_skb net/packet/af_packet.c:2995 [inline]
+  packet_snd net/packet/af_packet.c:3089 [inline]
+  packet_sendmsg+0x74c6/0xa6f0 net/packet/af_packet.c:3178
+  sock_sendmsg_nosec net/socket.c:711 [inline]
+  __sock_sendmsg+0x30f/0x380 net/socket.c:726
+  __sys_sendto+0x594/0x750 net/socket.c:2197
+  __do_sys_sendto net/socket.c:2204 [inline]
+  __se_sys_sendto net/socket.c:2200 [inline]
+  __x64_sys_sendto+0x125/0x1d0 net/socket.c:2200
+  x64_sys_call+0x346a/0x3c30 arch/x86/include/generated/asm/syscalls_64.h:45
+  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+  do_syscall_64+0xcd/0x1e0 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fixes: 48b491a5cc74 ("net: hsr: fix mac_len checks")
+Reported-by: syzbot+671e2853f9851d039551@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6745dc7f.050a0220.21d33d.0018.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: WingMan Kwok <w-kwok2@ti.com>
+Cc: Murali Karicheri <m-karicheri2@ti.com>
+Cc: MD Danish Anwar <danishanwar@ti.com>
+Cc: Jiri Pirko <jiri@nvidia.com>
+Cc: George McCollister <george.mccollister@gmail.com>
+Link: https://patch.msgid.link/20241126144344.4177332-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/hsr/hsr_forward.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
+index 0323ab5023c69..2790f3964d6bd 100644
+--- a/net/hsr/hsr_forward.c
++++ b/net/hsr/hsr_forward.c
+@@ -588,6 +588,8 @@ static int fill_frame_info(struct hsr_frame_info *frame,
+               frame->is_vlan = true;
+       if (frame->is_vlan) {
++              if (skb->mac_len < offsetofend(struct hsr_vlan_ethhdr, vlanhdr))
++                      return -EINVAL;
+               vlan_hdr = (struct hsr_vlan_ethhdr *)ethhdr;
+               proto = vlan_hdr->vlanhdr.h_vlan_encapsulated_proto;
+               /* FIXME: */
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-ipv6-release-expired-exception-dst-cached-in-soc.patch b/queue-6.6/net-ipv6-release-expired-exception-dst-cached-in-soc.patch
new file mode 100644 (file)
index 0000000..84382a1
--- /dev/null
@@ -0,0 +1,85 @@
+From 2710e56064b74f86c7d1938e5dc347b68604fdd3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Nov 2024 09:59:50 +0100
+Subject: net/ipv6: release expired exception dst cached in socket
+
+From: Jiri Wiesner <jwiesner@suse.de>
+
+[ Upstream commit 3301ab7d5aeb0fe270f73a3d4810c9d1b6a9f045 ]
+
+Dst objects get leaked in ip6_negative_advice() when this function is
+executed for an expired IPv6 route located in the exception table. There
+are several conditions that must be fulfilled for the leak to occur:
+* an ICMPv6 packet indicating a change of the MTU for the path is received,
+  resulting in an exception dst being created
+* a TCP connection that uses the exception dst for routing packets must
+  start timing out so that TCP begins retransmissions
+* after the exception dst expires, the FIB6 garbage collector must not run
+  before TCP executes ip6_negative_advice() for the expired exception dst
+
+When TCP executes ip6_negative_advice() for an exception dst that has
+expired and if no other socket holds a reference to the exception dst, the
+refcount of the exception dst is 2, which corresponds to the increment
+made by dst_init() and the increment made by the TCP socket for which the
+connection is timing out. The refcount made by the socket is never
+released. The refcount of the dst is decremented in sk_dst_reset() but
+that decrement is counteracted by a dst_hold() intentionally placed just
+before the sk_dst_reset() in ip6_negative_advice(). After
+ip6_negative_advice() has finished, there is no other object tied to the
+dst. The socket lost its reference stored in sk_dst_cache and the dst is
+no longer in the exception table. The exception dst becomes a leaked
+object.
+
+As a result of this dst leak, an unbalanced refcount is reported for the
+loopback device of a net namespace being destroyed under kernels that do
+not contain e5f80fcf869a ("ipv6: give an IPv6 dev to blackhole_netdev"):
+unregister_netdevice: waiting for lo to become free. Usage count = 2
+
+Fix the dst leak by removing the dst_hold() in ip6_negative_advice(). The
+patch that introduced the dst_hold() in ip6_negative_advice() was
+92f1655aa2b22 ("net: fix __dst_negative_advice() race"). But 92f1655aa2b22
+merely refactored the code with regards to the dst refcount so the issue
+was present even before 92f1655aa2b22. The bug was introduced in
+54c1a859efd9f ("ipv6: Don't drop cache route entry unless timer actually
+expired.") where the expired cached route is deleted and the sk_dst_cache
+member of the socket is set to NULL by calling dst_negative_advice() but
+the refcount belonging to the socket is left unbalanced.
+
+The IPv4 version - ipv4_negative_advice() - is not affected by this bug.
+When the TCP connection times out ipv4_negative_advice() merely resets the
+sk_dst_cache of the socket while decrementing the refcount of the
+exception dst.
+
+Fixes: 92f1655aa2b22 ("net: fix __dst_negative_advice() race")
+Fixes: 54c1a859efd9f ("ipv6: Don't drop cache route entry unless timer actually expired.")
+Link: https://lore.kernel.org/netdev/20241113105611.GA6723@incl/T/#u
+Signed-off-by: Jiri Wiesner <jwiesner@suse.de>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20241128085950.GA4505@incl
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/route.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 0fdd062d4b05b..fc5c534620253 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -2772,10 +2772,10 @@ static void ip6_negative_advice(struct sock *sk,
+       if (rt->rt6i_flags & RTF_CACHE) {
+               rcu_read_lock();
+               if (rt6_check_expired(rt)) {
+-                      /* counteract the dst_release() in sk_dst_reset() */
+-                      dst_hold(dst);
++                      /* rt/dst can not be destroyed yet,
++                       * because of rcu_read_lock()
++                       */
+                       sk_dst_reset(sk);
+-
+                       rt6_remove_exception_rt(rt);
+               }
+               rcu_read_unlock();
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch b/queue-6.6/net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch
new file mode 100644 (file)
index 0000000..6148696
--- /dev/null
@@ -0,0 +1,69 @@
+From 33e7f648f3cb6036aaa7fbd708fa8013d340ab03 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 22:49:20 +0200
+Subject: net/mlx5e: Remove workaround to avoid syndrome for internal port
+
+From: Jianbo Liu <jianbol@nvidia.com>
+
+[ Upstream commit 5085f861b414e4a51ce28a891dfa32a10a54b64e ]
+
+Previously a workaround was added to avoid syndrome 0xcdb051. It is
+triggered when offload a rule with tunnel encapsulation, and
+forwarding to another table, but not matching on the internal port in
+firmware steering mode. The original workaround skips internal tunnel
+port logic, which is not correct as not all cases are considered. As
+an example, if vlan is configured on the uplink port, traffic can't
+pass because vlan header is not added with this workaround. Besides,
+there is no such issue for software steering. So, this patch removes
+that, and returns error directly if trying to offload such rule for
+firmware steering.
+
+Fixes: 06b4eac9c4be ("net/mlx5e: Don't offload internal port if filter device is out device")
+Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
+Tested-by: Frode Nordahl <frode.nordahl@canonical.com>
+Reviewed-by: Chris Mi <cmi@nvidia.com>
+Reviewed-by: Ariel Levkovich <lariel@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20241203204920.232744-7-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/mellanox/mlx5/core/en/tc_tun_encap.c   | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+index f1d1e1542e81b..c11092da2e7d8 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+@@ -5,6 +5,7 @@
+ #include <net/nexthop.h>
+ #include <net/ip_tunnels.h>
+ #include "tc_tun_encap.h"
++#include "fs_core.h"
+ #include "en_tc.h"
+ #include "tc_tun.h"
+ #include "rep/tc.h"
+@@ -24,10 +25,18 @@ static int mlx5e_set_int_port_tunnel(struct mlx5e_priv *priv,
+       route_dev = dev_get_by_index(dev_net(e->out_dev), e->route_dev_ifindex);
+-      if (!route_dev || !netif_is_ovs_master(route_dev) ||
+-          attr->parse_attr->filter_dev == e->out_dev)
++      if (!route_dev || !netif_is_ovs_master(route_dev))
+               goto out;
++      if (priv->mdev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_DMFS &&
++          mlx5e_eswitch_uplink_rep(attr->parse_attr->filter_dev) &&
++          (attr->esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) {
++              mlx5_core_warn(priv->mdev,
++                             "Matching on external port with encap + fwd to table actions is not allowed for firmware steering\n");
++              err = -EINVAL;
++              goto out;
++      }
++
+       err = mlx5e_set_fwd_to_int_port_actions(priv, attr, e->route_dev_ifindex,
+                                               MLX5E_TC_INT_PORT_EGRESS,
+                                               &attr->action, out_index);
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-qed-allow-old-cards-not-supporting-num_images-to.patch b/queue-6.6/net-qed-allow-old-cards-not-supporting-num_images-to.patch
new file mode 100644 (file)
index 0000000..9ed26d9
--- /dev/null
@@ -0,0 +1,48 @@
+From b77deecd33968d1339d6e8d71080f08efd6e2cd1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Nov 2024 09:33:58 +0100
+Subject: net/qed: allow old cards not supporting "num_images" to work
+
+From: Louis Leseur <louis.leseur@gmail.com>
+
+[ Upstream commit 7a0ea70da56ee8c2716d0b79e9959d3c47efab62 ]
+
+Commit 43645ce03e00 ("qed: Populate nvm image attribute shadow.")
+added support for populating flash image attributes, notably
+"num_images". However, some cards were not able to return this
+information. In such cases, the driver would return EINVAL, causing the
+driver to exit.
+
+Add check to return EOPNOTSUPP instead of EINVAL when the card is not
+able to return these information. The caller function already handles
+EOPNOTSUPP without error.
+
+Fixes: 43645ce03e00 ("qed: Populate nvm image attribute shadow.")
+Co-developed-by: Florian Forestier <florian@forestier.re>
+Signed-off-by: Florian Forestier <florian@forestier.re>
+Signed-off-by: Louis Leseur <louis.leseur@gmail.com>
+Link: https://patch.msgid.link/20241128083633.26431-1-louis.leseur@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/qlogic/qed/qed_mcp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+index 16e6bd4661433..6218d9c268554 100644
+--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+@@ -3314,7 +3314,9 @@ int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn,
+       if (rc)
+               return rc;
+-      if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK))
++      if (((rsp & FW_MSG_CODE_MASK) == FW_MSG_CODE_UNSUPPORTED))
++              rc = -EOPNOTSUPP;
++      else if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK))
+               rc = -EINVAL;
+       return rc;
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-sched-fix-erspan_opt-settings-in-cls_flower.patch b/queue-6.6/net-sched-fix-erspan_opt-settings-in-cls_flower.patch
new file mode 100644 (file)
index 0000000..ded754b
--- /dev/null
@@ -0,0 +1,68 @@
+From 4b84c2e3d8239a302c6192da071d78a1fcd9c556 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Dec 2024 10:21:38 -0500
+Subject: net: sched: fix erspan_opt settings in cls_flower
+
+From: Xin Long <lucien.xin@gmail.com>
+
+[ Upstream commit 292207809486d99c78068d3f459cbbbffde88415 ]
+
+When matching erspan_opt in cls_flower, only the (version, dir, hwid)
+fields are relevant. However, in fl_set_erspan_opt() it initializes
+all bits of erspan_opt and its mask to 1. This inadvertently requires
+packets to match not only the (version, dir, hwid) fields but also the
+other fields that are unexpectedly set to 1.
+
+This patch resolves the issue by ensuring that only the (version, dir,
+hwid) fields are configured in fl_set_erspan_opt(), leaving the other
+fields to 0 in erspan_opt.
+
+Fixes: 79b1011cb33d ("net: sched: allow flower to match erspan options")
+Reported-by: Shuang Li <shuali@redhat.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Reviewed-by: Cong Wang <cong.wang@bytedance.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/cls_flower.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
+index 6ee7064c82fcc..bcf1b8012b2c3 100644
+--- a/net/sched/cls_flower.c
++++ b/net/sched/cls_flower.c
+@@ -1320,7 +1320,6 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key,
+       int err;
+       md = (struct erspan_metadata *)&key->enc_opts.data[key->enc_opts.len];
+-      memset(md, 0xff, sizeof(*md));
+       md->version = 1;
+       if (!depth)
+@@ -1349,9 +1348,9 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key,
+                       NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index");
+                       return -EINVAL;
+               }
++              memset(&md->u.index, 0xff, sizeof(md->u.index));
+               if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) {
+                       nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX];
+-                      memset(&md->u, 0x00, sizeof(md->u));
+                       md->u.index = nla_get_be32(nla);
+               }
+       } else if (md->version == 2) {
+@@ -1360,10 +1359,12 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key,
+                       NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid");
+                       return -EINVAL;
+               }
++              md->u.md2.dir = 1;
+               if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]) {
+                       nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR];
+                       md->u.md2.dir = nla_get_u8(nla);
+               }
++              set_hwid(&md->u.md2, 0xff);
+               if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]) {
+                       nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID];
+                       set_hwid(&md->u.md2, nla_get_u8(nla));
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch b/queue-6.6/net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch
new file mode 100644 (file)
index 0000000..b01d046
--- /dev/null
@@ -0,0 +1,90 @@
+From 600e24f040c747fb6aef575cf571ce86943df3f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Nov 2024 18:46:07 +0100
+Subject: net/sched: tbf: correct backlog statistic for GSO packets
+
+From: Martin Ottens <martin.ottens@fau.de>
+
+[ Upstream commit 1596a135e3180c92e42dd1fbcad321f4fb3e3b17 ]
+
+When the length of a GSO packet in the tbf qdisc is larger than the burst
+size configured the packet will be segmented by the tbf_segment function.
+Whenever this function is used to enqueue SKBs, the backlog statistic of
+the tbf is not increased correctly. This can lead to underflows of the
+'backlog' byte-statistic value when these packets are dequeued from tbf.
+
+Reproduce the bug:
+Ensure that the sender machine has GSO enabled. Configured the tbf on
+the outgoing interface of the machine as follows (burstsize = 1 MTU):
+$ tc qdisc add dev <oif> root handle 1: tbf rate 50Mbit burst 1514 latency 50ms
+
+Send bulk TCP traffic out via this interface, e.g., by running an iPerf3
+client on this machine. Check the qdisc statistics:
+$ tc -s qdisc show dev <oif>
+
+The 'backlog' byte-statistic has incorrect values while traffic is
+transferred, e.g., high values due to u32 underflows. When the transfer
+is stopped, the value is != 0, which should never happen.
+
+This patch fixes this bug by updating the statistics correctly, even if
+single SKBs of a GSO SKB cannot be enqueued.
+
+Fixes: e43ac79a4bc6 ("sch_tbf: segment too big GSO packets")
+Signed-off-by: Martin Ottens <martin.ottens@fau.de>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20241125174608.1484356-1-martin.ottens@fau.de
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_tbf.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
+index 17d2d00ddb182..f92174008499b 100644
+--- a/net/sched/sch_tbf.c
++++ b/net/sched/sch_tbf.c
+@@ -208,7 +208,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
+       struct tbf_sched_data *q = qdisc_priv(sch);
+       struct sk_buff *segs, *nskb;
+       netdev_features_t features = netif_skb_features(skb);
+-      unsigned int len = 0, prev_len = qdisc_pkt_len(skb);
++      unsigned int len = 0, prev_len = qdisc_pkt_len(skb), seg_len;
+       int ret, nb;
+       segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
+@@ -219,21 +219,27 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
+       nb = 0;
+       skb_list_walk_safe(segs, segs, nskb) {
+               skb_mark_not_on_list(segs);
+-              qdisc_skb_cb(segs)->pkt_len = segs->len;
+-              len += segs->len;
++              seg_len = segs->len;
++              qdisc_skb_cb(segs)->pkt_len = seg_len;
+               ret = qdisc_enqueue(segs, q->qdisc, to_free);
+               if (ret != NET_XMIT_SUCCESS) {
+                       if (net_xmit_drop_count(ret))
+                               qdisc_qstats_drop(sch);
+               } else {
+                       nb++;
++                      len += seg_len;
+               }
+       }
+       sch->q.qlen += nb;
+-      if (nb > 1)
++      sch->qstats.backlog += len;
++      if (nb > 0) {
+               qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len);
+-      consume_skb(skb);
+-      return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
++              consume_skb(skb);
++              return NET_XMIT_SUCCESS;
++      }
++
++      kfree_skb(skb);
++      return NET_XMIT_DROP;
+ }
+ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch b/queue-6.6/net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch
new file mode 100644 (file)
index 0000000..02da0d3
--- /dev/null
@@ -0,0 +1,127 @@
+From 691098ba12faec4ee6d6d83b2d1ed0ea30ccf267 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Apr 2024 14:07:35 +0800
+Subject: net/smc: add operations to merge sndbuf with peer DMB
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit 4398888268582cb51b69c6ee94f551bb8d37d12f ]
+
+In some scenarios using Emulated-ISM device, sndbuf can share the same
+physical memory region with peer DMB to avoid data copy from one side
+to the other. In such case the sndbuf is only a descriptor that
+describes the shared memory and does not actually occupy memory, it's
+more like a ghost buffer.
+
+      +----------+                     +----------+
+      | socket A |                     | socket B |
+      +----------+                     +----------+
+            |                               |
+       +--------+                       +--------+
+       | sndbuf |                       |  DMB   |
+       |  desc  |                       |  desc  |
+       +--------+                       +--------+
+            |                               |
+            |                          +----v-----+
+            +-------------------------->  memory  |
+                                       +----------+
+
+So here introduces three new SMC-D device operations to check if this
+feature is supported by device, and to {attach|detach} ghost sndbuf to
+peer DMB. For now only loopback-ism supports this.
+
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-and-tested-by: Jan Karcher <jaka@linux.ibm.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/smc.h |  3 +++
+ net/smc/smc_ism.c | 40 ++++++++++++++++++++++++++++++++++++++++
+ net/smc/smc_ism.h |  4 ++++
+ 3 files changed, 47 insertions(+)
+
+diff --git a/include/net/smc.h b/include/net/smc.h
+index 9dfe57f3e4f0b..6fef76087b9ed 100644
+--- a/include/net/smc.h
++++ b/include/net/smc.h
+@@ -79,6 +79,9 @@ struct smcd_ops {
+       int (*reset_vlan_required)(struct smcd_dev *dev);
+       int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
+                           u32 trigger_irq, u32 event_code, u64 info);
++      int (*support_dmb_nocopy)(struct smcd_dev *dev);
++      int (*attach_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
++      int (*detach_dmb)(struct smcd_dev *dev, u64 token);
+ };
+ struct smcd_dev {
+diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
+index 3623df320de55..61ffc72014013 100644
+--- a/net/smc/smc_ism.c
++++ b/net/smc/smc_ism.c
+@@ -228,6 +228,46 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
+ #endif
+ }
++bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd)
++{
++      /* for now only loopback-ism supports
++       * merging sndbuf with peer DMB to avoid
++       * data copies between them.
++       */
++      return (smcd->ops->support_dmb_nocopy &&
++              smcd->ops->support_dmb_nocopy(smcd));
++}
++
++int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token,
++                     struct smc_buf_desc *dmb_desc)
++{
++      struct smcd_dmb dmb;
++      int rc = 0;
++
++      if (!dev->ops->attach_dmb)
++              return -EINVAL;
++
++      memset(&dmb, 0, sizeof(dmb));
++      dmb.dmb_tok = token;
++      rc = dev->ops->attach_dmb(dev, &dmb);
++      if (!rc) {
++              dmb_desc->sba_idx = dmb.sba_idx;
++              dmb_desc->token = dmb.dmb_tok;
++              dmb_desc->cpu_addr = dmb.cpu_addr;
++              dmb_desc->dma_addr = dmb.dma_addr;
++              dmb_desc->len = dmb.dmb_len;
++      }
++      return rc;
++}
++
++int smc_ism_detach_dmb(struct smcd_dev *dev, u64 token)
++{
++      if (!dev->ops->detach_dmb)
++              return -EINVAL;
++
++      return dev->ops->detach_dmb(dev, token);
++}
++
+ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
+                                 struct sk_buff *skb,
+                                 struct netlink_callback *cb)
+diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
+index 0e5e563099ec3..8312c3586d2b3 100644
+--- a/net/smc/smc_ism.h
++++ b/net/smc/smc_ism.h
+@@ -41,6 +41,10 @@ int smc_ism_put_vlan(struct smcd_dev *dev, unsigned short vlan_id);
+ int smc_ism_register_dmb(struct smc_link_group *lgr, int buf_size,
+                        struct smc_buf_desc *dmb_desc);
+ int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc);
++bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd);
++int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token,
++                     struct smc_buf_desc *dmb_desc);
++int smc_ism_detach_dmb(struct smcd_dev *dev, u64 token);
+ int smc_ism_signal_shutdown(struct smc_link_group *lgr);
+ void smc_ism_get_system_eid(u8 **eid);
+ u16 smc_ism_get_chid(struct smcd_dev *dev);
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch b/queue-6.6/net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch
new file mode 100644 (file)
index 0000000..1369ee7
--- /dev/null
@@ -0,0 +1,180 @@
+From 48daf19b52680d489b64e6e66725242ce02df0af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Apr 2024 14:07:36 +0800
+Subject: net/smc: {at|de}tach sndbuf to peer DMB if supported
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit ae2be35cbed2c8385e890147ea321a3fcc3ca5fa ]
+
+If the device used by SMC-D supports merging local sndbuf to peer DMB,
+then create sndbuf descriptor and attach it to peer DMB once peer
+token is obtained, and detach and free the sndbuf descriptor when the
+connection is freed.
+
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-and-tested-by: Jan Karcher <jaka@linux.ibm.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c   | 16 ++++++++++++
+ net/smc/smc_core.c | 61 +++++++++++++++++++++++++++++++++++++++++++++-
+ net/smc/smc_core.h |  1 +
+ 3 files changed, 77 insertions(+), 1 deletion(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index f3ed53ae849d3..c4b30ea4b6ca0 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1418,6 +1418,14 @@ static int smc_connect_ism(struct smc_sock *smc,
+       }
+       smc_conn_save_peer_info(smc, aclc);
++
++      if (smc_ism_support_dmb_nocopy(smc->conn.lgr->smcd)) {
++              rc = smcd_buf_attach(smc);
++              if (rc) {
++                      rc = SMC_CLC_DECL_MEM;  /* try to fallback */
++                      goto connect_abort;
++              }
++      }
+       smc_close_init(smc);
+       smc_rx_init(smc);
+       smc_tx_init(smc);
+@@ -2522,6 +2530,14 @@ static void smc_listen_work(struct work_struct *work)
+               mutex_unlock(&smc_server_lgr_pending);
+       }
+       smc_conn_save_peer_info(new_smc, cclc);
++
++      if (ini->is_smcd &&
++          smc_ism_support_dmb_nocopy(new_smc->conn.lgr->smcd)) {
++              rc = smcd_buf_attach(new_smc);
++              if (rc)
++                      goto out_decl;
++      }
++
+       smc_listen_out_connected(new_smc);
+       SMC_STAT_SERV_SUCC_INC(sock_net(newclcsock->sk), ini);
+       goto out_free;
+diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
+index 605cdff671d65..0eeb0d4353446 100644
+--- a/net/smc/smc_core.c
++++ b/net/smc/smc_core.c
+@@ -1143,6 +1143,20 @@ static void smcr_buf_unuse(struct smc_buf_desc *buf_desc, bool is_rmb,
+       }
+ }
++static void smcd_buf_detach(struct smc_connection *conn)
++{
++      struct smcd_dev *smcd = conn->lgr->smcd;
++      u64 peer_token = conn->peer_token;
++
++      if (!conn->sndbuf_desc)
++              return;
++
++      smc_ism_detach_dmb(smcd, peer_token);
++
++      kfree(conn->sndbuf_desc);
++      conn->sndbuf_desc = NULL;
++}
++
+ static void smc_buf_unuse(struct smc_connection *conn,
+                         struct smc_link_group *lgr)
+ {
+@@ -1186,6 +1200,8 @@ void smc_conn_free(struct smc_connection *conn)
+       if (lgr->is_smcd) {
+               if (!list_empty(&lgr->list))
+                       smc_ism_unset_conn(conn);
++              if (smc_ism_support_dmb_nocopy(lgr->smcd))
++                      smcd_buf_detach(conn);
+               tasklet_kill(&conn->rx_tsklet);
+       } else {
+               smc_cdc_wait_pend_tx_wr(conn);
+@@ -1439,6 +1455,8 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
+       smc_sk_wake_ups(smc);
+       if (conn->lgr->is_smcd) {
+               smc_ism_unset_conn(conn);
++              if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
++                      smcd_buf_detach(conn);
+               if (soft)
+                       tasklet_kill(&conn->rx_tsklet);
+               else
+@@ -2453,12 +2471,18 @@ int smc_buf_create(struct smc_sock *smc, bool is_smcd)
+       int rc;
+       /* create send buffer */
++      if (is_smcd &&
++          smc_ism_support_dmb_nocopy(smc->conn.lgr->smcd))
++              goto create_rmb;
++
+       rc = __smc_buf_create(smc, is_smcd, false);
+       if (rc)
+               return rc;
++
++create_rmb:
+       /* create rmb */
+       rc = __smc_buf_create(smc, is_smcd, true);
+-      if (rc) {
++      if (rc && smc->conn.sndbuf_desc) {
+               down_write(&smc->conn.lgr->sndbufs_lock);
+               list_del(&smc->conn.sndbuf_desc->list);
+               up_write(&smc->conn.lgr->sndbufs_lock);
+@@ -2468,6 +2492,41 @@ int smc_buf_create(struct smc_sock *smc, bool is_smcd)
+       return rc;
+ }
++int smcd_buf_attach(struct smc_sock *smc)
++{
++      struct smc_connection *conn = &smc->conn;
++      struct smcd_dev *smcd = conn->lgr->smcd;
++      u64 peer_token = conn->peer_token;
++      struct smc_buf_desc *buf_desc;
++      int rc;
++
++      buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL);
++      if (!buf_desc)
++              return -ENOMEM;
++
++      /* The ghost sndbuf_desc describes the same memory region as
++       * peer RMB. Its lifecycle is consistent with the connection's
++       * and it will be freed with the connections instead of the
++       * link group.
++       */
++      rc = smc_ism_attach_dmb(smcd, peer_token, buf_desc);
++      if (rc)
++              goto free;
++
++      smc->sk.sk_sndbuf = buf_desc->len;
++      buf_desc->cpu_addr =
++              (u8 *)buf_desc->cpu_addr + sizeof(struct smcd_cdc_msg);
++      buf_desc->len -= sizeof(struct smcd_cdc_msg);
++      conn->sndbuf_desc = buf_desc;
++      conn->sndbuf_desc->used = 1;
++      atomic_set(&conn->sndbuf_space, conn->sndbuf_desc->len);
++      return 0;
++
++free:
++      kfree(buf_desc);
++      return rc;
++}
++
+ static inline int smc_rmb_reserve_rtoken_idx(struct smc_link_group *lgr)
+ {
+       int i;
+diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
+index 670f8359da558..de001f4b46c7d 100644
+--- a/net/smc/smc_core.h
++++ b/net/smc/smc_core.h
+@@ -556,6 +556,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
+ void smc_smcd_terminate_all(struct smcd_dev *dev);
+ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev);
+ int smc_buf_create(struct smc_sock *smc, bool is_smcd);
++int smcd_buf_attach(struct smc_sock *smc);
+ int smc_uncompress_bufsize(u8 compressed);
+ int smc_rmb_rtoken_handling(struct smc_connection *conn, struct smc_link *link,
+                           struct smc_clc_msg_accept_confirm *clc);
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-compatible-with-128-bits-extended-gid-of-vir.patch b/queue-6.6/net-smc-compatible-with-128-bits-extended-gid-of-vir.patch
new file mode 100644 (file)
index 0000000..b663d3c
--- /dev/null
@@ -0,0 +1,694 @@
+From b1a79e6f353052fa8cf1e0fc0b3fc34023b83080 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 22:26:13 +0800
+Subject: net/smc: compatible with 128-bits extended GID of virtual ISM device
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit b40584d145700addc70cc29e4f0850a4ed955b1c ]
+
+According to virtual ISM support feature defined by SMCv2.1, GIDs of
+virtual ISM device are UUIDs defined by RFC4122, which are 128-bits
+long. So some adaptation work is required. And note that the GIDs of
+existing platform firmware ISM devices still remain 64-bits long.
+
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/s390/net/ism_drv.c | 19 ++++++-----
+ include/net/smc.h          | 15 ++++++---
+ net/smc/af_smc.c           | 66 ++++++++++++++++++++++++++++++--------
+ net/smc/smc.h              |  3 --
+ net/smc/smc_clc.c          | 43 ++++++++++++++++++-------
+ net/smc/smc_clc.h          | 10 ++++--
+ net/smc/smc_core.c         | 31 ++++++++++++------
+ net/smc/smc_core.h         | 17 +++++++---
+ net/smc/smc_diag.c         |  7 ++--
+ net/smc/smc_ism.c          | 17 ++++++----
+ net/smc/smc_ism.h          |  3 +-
+ net/smc/smc_pnet.c         |  4 +--
+ 12 files changed, 167 insertions(+), 68 deletions(-)
+
+diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
+index 622a61f8a3b84..f6a0626a6b3ec 100644
+--- a/drivers/s390/net/ism_drv.c
++++ b/drivers/s390/net/ism_drv.c
+@@ -762,10 +762,10 @@ static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid,
+       return ism_cmd(ism, &cmd);
+ }
+-static int smcd_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid,
+-                         u32 vid)
++static int smcd_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid,
++                         u32 vid_valid, u32 vid)
+ {
+-      return ism_query_rgid(smcd->priv, rgid, vid_valid, vid);
++      return ism_query_rgid(smcd->priv, rgid->gid, vid_valid, vid);
+ }
+ static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
+@@ -816,10 +816,11 @@ static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
+       return ism_cmd(ism, &cmd);
+ }
+-static int smcd_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq,
+-                         u32 event_code, u64 info)
++static int smcd_signal_ieq(struct smcd_dev *smcd, struct smcd_gid *rgid,
++                         u32 trigger_irq, u32 event_code, u64 info)
+ {
+-      return ism_signal_ieq(smcd->priv, rgid, trigger_irq, event_code, info);
++      return ism_signal_ieq(smcd->priv, rgid->gid,
++                            trigger_irq, event_code, info);
+ }
+ static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
+@@ -840,9 +841,11 @@ static u64 ism_get_local_gid(struct ism_dev *ism)
+       return ism->local_gid;
+ }
+-static u64 smcd_get_local_gid(struct smcd_dev *smcd)
++static void smcd_get_local_gid(struct smcd_dev *smcd,
++                             struct smcd_gid *smcd_gid)
+ {
+-      return ism_get_local_gid(smcd->priv);
++      smcd_gid->gid = ism_get_local_gid(smcd->priv);
++      smcd_gid->gid_ext = 0;
+ }
+ static u16 ism_get_chid(struct ism_dev *ism)
+diff --git a/include/net/smc.h b/include/net/smc.h
+index a002552be29c3..a0dc1187e96ed 100644
+--- a/include/net/smc.h
++++ b/include/net/smc.h
+@@ -52,9 +52,14 @@ struct smcd_dmb {
+ struct smcd_dev;
+ struct ism_client;
++struct smcd_gid {
++      u64     gid;
++      u64     gid_ext;
++};
++
+ struct smcd_ops {
+-      int (*query_remote_gid)(struct smcd_dev *dev, u64 rgid, u32 vid_valid,
+-                              u32 vid);
++      int (*query_remote_gid)(struct smcd_dev *dev, struct smcd_gid *rgid,
++                              u32 vid_valid, u32 vid);
+       int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb,
+                           struct ism_client *client);
+       int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
+@@ -62,14 +67,14 @@ struct smcd_ops {
+       int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
+       int (*set_vlan_required)(struct smcd_dev *dev);
+       int (*reset_vlan_required)(struct smcd_dev *dev);
+-      int (*signal_event)(struct smcd_dev *dev, u64 rgid, u32 trigger_irq,
+-                          u32 event_code, u64 info);
++      int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
++                          u32 trigger_irq, u32 event_code, u64 info);
+       int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
+                        bool sf, unsigned int offset, void *data,
+                        unsigned int size);
+       int (*supports_v2)(void);
+       u8* (*get_system_eid)(void);
+-      u64 (*get_local_gid)(struct smcd_dev *dev);
++      void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
+       u16 (*get_chid)(struct smcd_dev *dev);
+       struct device* (*get_dev)(struct smcd_dev *dev);
+ };
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index ea24fb4dae0df..f3ed53ae849d3 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1026,7 +1026,8 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
+ {
+       int rc = SMC_CLC_DECL_NOSMCDDEV;
+       struct smcd_dev *smcd;
+-      int i = 1;
++      int i = 1, entry = 1;
++      bool is_virtual;
+       u16 chid;
+       if (smcd_indicated(ini->smc_type_v1))
+@@ -1038,14 +1039,23 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
+               chid = smc_ism_get_chid(smcd);
+               if (!smc_find_ism_v2_is_unique_chid(chid, ini, i))
+                       continue;
++              is_virtual = __smc_ism_is_virtual(chid);
+               if (!smc_pnet_is_pnetid_set(smcd->pnetid) ||
+                   smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) {
++                      if (is_virtual && entry == SMCD_CLC_MAX_V2_GID_ENTRIES)
++                              /* It's the last GID-CHID entry left in CLC
++                               * Proposal SMC-Dv2 extension, but a virtual
++                               * ISM device will take two entries. So give
++                               * up it and try the next potential ISM device.
++                               */
++                              continue;
+                       ini->ism_dev[i] = smcd;
+                       ini->ism_chid[i] = chid;
+                       ini->is_smcd = true;
+                       rc = 0;
+                       i++;
+-                      if (i > SMC_MAX_ISM_DEVS)
++                      entry = is_virtual ? entry + 2 : entry + 1;
++                      if (entry > SMCD_CLC_MAX_V2_GID_ENTRIES)
+                               break;
+               }
+       }
+@@ -1384,8 +1394,13 @@ static int smc_connect_ism(struct smc_sock *smc,
+               rc = smc_v2_determine_accepted_chid(aclc, ini);
+               if (rc)
+                       return rc;
++
++              if (__smc_ism_is_virtual(ini->ism_chid[ini->ism_selected]))
++                      ini->ism_peer_gid[ini->ism_selected].gid_ext =
++                                              ntohll(aclc->d1.gid_ext);
++              /* for non-virtual ISM devices, peer gid_ext remains 0. */
+       }
+-      ini->ism_peer_gid[ini->ism_selected] = ntohll(aclc->d0.gid);
++      ini->ism_peer_gid[ini->ism_selected].gid = ntohll(aclc->d0.gid);
+       /* there is only one lgr role for SMC-D; use server lock */
+       mutex_lock(&smc_server_lgr_pending);
+@@ -2070,7 +2085,8 @@ static bool smc_is_already_selected(struct smcd_dev *smcd,
+ /* check for ISM devices matching proposed ISM devices */
+ static void smc_check_ism_v2_match(struct smc_init_info *ini,
+-                                 u16 proposed_chid, u64 proposed_gid,
++                                 u16 proposed_chid,
++                                 struct smcd_gid *proposed_gid,
+                                  unsigned int *matches)
+ {
+       struct smcd_dev *smcd;
+@@ -2082,7 +2098,11 @@ static void smc_check_ism_v2_match(struct smc_init_info *ini,
+                       continue;
+               if (smc_ism_get_chid(smcd) == proposed_chid &&
+                   !smc_ism_cantalk(proposed_gid, ISM_RESERVED_VLANID, smcd)) {
+-                      ini->ism_peer_gid[*matches] = proposed_gid;
++                      ini->ism_peer_gid[*matches].gid = proposed_gid->gid;
++                      if (__smc_ism_is_virtual(proposed_chid))
++                              ini->ism_peer_gid[*matches].gid_ext =
++                                                      proposed_gid->gid_ext;
++                              /* non-virtual ISM's peer gid_ext remains 0. */
+                       ini->ism_dev[*matches] = smcd;
+                       (*matches)++;
+                       break;
+@@ -2104,9 +2124,11 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
+       struct smc_clc_v2_extension *smc_v2_ext;
+       struct smc_clc_msg_smcd *pclc_smcd;
+       unsigned int matches = 0;
++      struct smcd_gid smcd_gid;
+       u8 smcd_version;
+       u8 *eid = NULL;
+       int i, rc;
++      u16 chid;
+       if (!(ini->smcd_version & SMC_V2) || !smcd_indicated(ini->smc_type_v2))
+               goto not_found;
+@@ -2116,18 +2138,35 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
+       smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
+       mutex_lock(&smcd_dev_list.mutex);
+-      if (pclc_smcd->ism.chid)
++      if (pclc_smcd->ism.chid) {
+               /* check for ISM device matching proposed native ISM device */
++              smcd_gid.gid = ntohll(pclc_smcd->ism.gid);
++              smcd_gid.gid_ext = 0;
+               smc_check_ism_v2_match(ini, ntohs(pclc_smcd->ism.chid),
+-                                     ntohll(pclc_smcd->ism.gid), &matches);
+-      for (i = 1; i <= smc_v2_ext->hdr.ism_gid_cnt; i++) {
++                                     &smcd_gid, &matches);
++      }
++      for (i = 0; i < smc_v2_ext->hdr.ism_gid_cnt; i++) {
+               /* check for ISM devices matching proposed non-native ISM
+                * devices
+                */
+-              smc_check_ism_v2_match(ini,
+-                                     ntohs(smcd_v2_ext->gidchid[i - 1].chid),
+-                                     ntohll(smcd_v2_ext->gidchid[i - 1].gid),
+-                                     &matches);
++              smcd_gid.gid = ntohll(smcd_v2_ext->gidchid[i].gid);
++              smcd_gid.gid_ext = 0;
++              chid = ntohs(smcd_v2_ext->gidchid[i].chid);
++              if (__smc_ism_is_virtual(chid)) {
++                      if ((i + 1) == smc_v2_ext->hdr.ism_gid_cnt ||
++                          chid != ntohs(smcd_v2_ext->gidchid[i + 1].chid))
++                              /* each virtual ISM device takes two GID-CHID
++                               * entries and CHID of the second entry repeats
++                               * that of the first entry.
++                               *
++                               * So check if the next GID-CHID entry exists
++                               * and both two entries' CHIDs are the same.
++                               */
++                              continue;
++                      smcd_gid.gid_ext =
++                              ntohll(smcd_v2_ext->gidchid[++i].gid);
++              }
++              smc_check_ism_v2_match(ini, chid, &smcd_gid, &matches);
+       }
+       mutex_unlock(&smcd_dev_list.mutex);
+@@ -2176,7 +2215,8 @@ static void smc_find_ism_v1_device_serv(struct smc_sock *new_smc,
+       if (!(ini->smcd_version & SMC_V1) || !smcd_indicated(ini->smc_type_v1))
+               goto not_found;
+       ini->is_smcd = true; /* prepare ISM check */
+-      ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid);
++      ini->ism_peer_gid[0].gid = ntohll(pclc_smcd->ism.gid);
++      ini->ism_peer_gid[0].gid_ext = 0;
+       rc = smc_find_ism_device(new_smc, ini);
+       if (rc)
+               goto not_found;
+diff --git a/net/smc/smc.h b/net/smc/smc.h
+index e377980b84145..e0afef7a786f8 100644
+--- a/net/smc/smc.h
++++ b/net/smc/smc.h
+@@ -29,9 +29,6 @@
+ #define SMCPROTO_SMC          0       /* SMC protocol, IPv4 */
+ #define SMCPROTO_SMC6         1       /* SMC protocol, IPv6 */
+-#define SMC_MAX_ISM_DEVS      8       /* max # of proposed non-native ISM
+-                                       * devices
+-                                       */
+ #define SMC_AUTOCORKING_DEFAULT_SIZE  0x10000 /* 64K by default */
+ extern struct proto smc_proto;
+diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
+index a28dee81d6fa4..0084960a203dc 100644
+--- a/net/smc/smc_clc.c
++++ b/net/smc/smc_clc.c
+@@ -891,11 +891,13 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
+                      ETH_ALEN);
+       }
+       if (smcd_indicated(ini->smc_type_v1)) {
++              struct smcd_gid smcd_gid;
++
+               /* add SMC-D specifics */
+               if (ini->ism_dev[0]) {
+                       smcd = ini->ism_dev[0];
+-                      pclc_smcd->ism.gid =
+-                              htonll(smcd->ops->get_local_gid(smcd));
++                      smcd->ops->get_local_gid(smcd, &smcd_gid);
++                      pclc_smcd->ism.gid = htonll(smcd_gid.gid);
+                       pclc_smcd->ism.chid =
+                               htons(smc_ism_get_chid(ini->ism_dev[0]));
+               }
+@@ -927,10 +929,11 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
+               read_unlock(&smc_clc_eid_table.lock);
+       }
+       if (smcd_indicated(ini->smc_type_v2)) {
++              struct smcd_gid smcd_gid;
+               u8 *eid = NULL;
++              int entry = 0;
+               v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled;
+-              v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
+               v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
+                               offsetofend(struct smc_clnt_opts_area_hdr,
+                                           smcd_v2_ext_offset) +
+@@ -942,14 +945,26 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
+               if (ini->ism_offered_cnt) {
+                       for (i = 1; i <= ini->ism_offered_cnt; i++) {
+                               smcd = ini->ism_dev[i];
+-                              gidchids[i - 1].gid =
+-                                      htonll(smcd->ops->get_local_gid(smcd));
+-                              gidchids[i - 1].chid =
++                              smcd->ops->get_local_gid(smcd, &smcd_gid);
++                              gidchids[entry].chid =
+                                       htons(smc_ism_get_chid(ini->ism_dev[i]));
++                              gidchids[entry].gid = htonll(smcd_gid.gid);
++                              if (smc_ism_is_virtual(smcd)) {
++                                      /* a virtual ISM device takes two
++                                       * entries. CHID of the second entry
++                                       * repeats that of the first entry.
++                                       */
++                                      gidchids[entry + 1].chid =
++                                              gidchids[entry].chid;
++                                      gidchids[entry + 1].gid =
++                                              htonll(smcd_gid.gid_ext);
++                                      entry++;
++                              }
++                              entry++;
+                       }
+-                      plen += ini->ism_offered_cnt *
+-                              sizeof(struct smc_clc_smcd_gid_chid);
++                      plen += entry * sizeof(struct smc_clc_smcd_gid_chid);
+               }
++              v2_ext->hdr.ism_gid_cnt = entry;
+       }
+       if (smcr_indicated(ini->smc_type_v2)) {
+               memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE);
+@@ -985,7 +1000,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
+                       vec[i++].iov_len = sizeof(*smcd_v2_ext);
+                       if (ini->ism_offered_cnt) {
+                               vec[i].iov_base = gidchids;
+-                              vec[i++].iov_len = ini->ism_offered_cnt *
++                              vec[i++].iov_len = v2_ext->hdr.ism_gid_cnt *
+                                       sizeof(struct smc_clc_smcd_gid_chid);
+                       }
+               }
+@@ -1016,13 +1031,16 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
+                            struct smc_clc_msg_trail *trl)
+ {
+       struct smcd_dev *smcd = conn->lgr->smcd;
++      struct smcd_gid smcd_gid;
++      u16 chid;
+       int len;
+       /* SMC-D specific settings */
+       memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
+              sizeof(SMCD_EYECATCHER));
++      smcd->ops->get_local_gid(smcd, &smcd_gid);
+       clc->hdr.typev1 = SMC_TYPE_D;
+-      clc->d0.gid = htonll(smcd->ops->get_local_gid(smcd));
++      clc->d0.gid = htonll(smcd_gid.gid);
+       clc->d0.token = htonll(conn->rmb_desc->token);
+       clc->d0.dmbe_size = conn->rmbe_size_comp;
+       clc->d0.dmbe_idx = 0;
+@@ -1030,9 +1048,12 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
+       if (version == SMC_V1) {
+               clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
+       } else {
+-              clc->d1.chid = htons(smc_ism_get_chid(smcd));
++              chid = smc_ism_get_chid(smcd);
++              clc->d1.chid = htons(chid);
+               if (eid && eid[0])
+                       memcpy(clc->d1.eid, eid, SMC_MAX_EID_LEN);
++              if (__smc_ism_is_virtual(chid))
++                      clc->d1.gid_ext = htonll(smcd_gid.gid_ext);
+               len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
+               if (first_contact) {
+                       *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini);
+diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h
+index d7b1716cfb0fd..c8d6282ec9c04 100644
+--- a/net/smc/smc_clc.h
++++ b/net/smc/smc_clc.h
+@@ -171,6 +171,11 @@ struct smc_clc_msg_proposal {     /* clc proposal message sent by Linux */
+ #define SMC_CLC_MAX_V6_PREFIX         8
+ #define SMC_CLC_MAX_UEID              8
++#define SMCD_CLC_MAX_V2_GID_ENTRIES   8 /* max # of CHID-GID entries in CLC
++                                         * proposal SMC-Dv2 extension.
++                                         * each ISM device takes one entry and
++                                         * each virtual ISM takes two entries.
++                                         */
+ struct smc_clc_msg_proposal_area {
+       struct smc_clc_msg_proposal             pclc_base;
+@@ -180,7 +185,8 @@ struct smc_clc_msg_proposal_area {
+       struct smc_clc_v2_extension             pclc_v2_ext;
+       u8                      user_eids[SMC_CLC_MAX_UEID][SMC_MAX_EID_LEN];
+       struct smc_clc_smcd_v2_extension        pclc_smcd_v2_ext;
+-      struct smc_clc_smcd_gid_chid            pclc_gidchids[SMC_MAX_ISM_DEVS];
++      struct smc_clc_smcd_gid_chid
++                              pclc_gidchids[SMCD_CLC_MAX_V2_GID_ENTRIES];
+       struct smc_clc_msg_trail                pclc_trl;
+ };
+@@ -271,7 +277,7 @@ struct smc_clc_msg_accept_confirm {        /* clc accept / confirm message */
+                       struct { /* v2 only, but 12 bytes reserved in v1 */
+                               __be16 chid;
+                               u8 eid[SMC_MAX_EID_LEN];
+-                              u8 reserved5[8];
++                              __be64 gid_ext;
+                       } __packed d1;
+               };
+       };
+diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
+index f99bb9d0adcc6..605cdff671d65 100644
+--- a/net/smc/smc_core.c
++++ b/net/smc/smc_core.c
+@@ -506,6 +506,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
+ {
+       char smc_pnet[SMC_MAX_PNETID_LEN + 1];
+       struct smcd_dev *smcd = lgr->smcd;
++      struct smcd_gid smcd_gid;
+       struct nlattr *attrs;
+       void *nlh;
+@@ -521,11 +522,11 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
+       if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id)))
+               goto errattr;
++      smcd->ops->get_local_gid(smcd, &smcd_gid);
+       if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID,
+-                            smcd->ops->get_local_gid(smcd),
+-                                SMC_NLA_LGR_D_PAD))
++                            smcd_gid.gid, SMC_NLA_LGR_D_PAD))
+               goto errattr;
+-      if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid,
++      if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid.gid,
+                             SMC_NLA_LGR_D_PAD))
+               goto errattr;
+       if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id))
+@@ -876,7 +877,10 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
+               /* SMC-D specific settings */
+               smcd = ini->ism_dev[ini->ism_selected];
+               get_device(smcd->ops->get_dev(smcd));
+-              lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
++              lgr->peer_gid.gid =
++                      ini->ism_peer_gid[ini->ism_selected].gid;
++              lgr->peer_gid.gid_ext =
++                      ini->ism_peer_gid[ini->ism_selected].gid_ext;
+               lgr->smcd = ini->ism_dev[ini->ism_selected];
+               lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
+               lgr_lock = &lgr->smcd->lgr_lock;
+@@ -1514,7 +1518,8 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr)
+ }
+ /* Called when peer lgr shutdown (regularly or abnormally) is received */
+-void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
++void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
++                      unsigned short vlan)
+ {
+       struct smc_link_group *lgr, *l;
+       LIST_HEAD(lgr_free_list);
+@@ -1522,9 +1527,12 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
+       /* run common cleanup function and build free list */
+       spin_lock_bh(&dev->lgr_lock);
+       list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) {
+-              if ((!peer_gid || lgr->peer_gid == peer_gid) &&
++              if ((!peer_gid->gid ||
++                   (lgr->peer_gid.gid == peer_gid->gid &&
++                    !smc_ism_is_virtual(dev) ? 1 :
++                    lgr->peer_gid.gid_ext == peer_gid->gid_ext)) &&
+                   (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
+-                      if (peer_gid) /* peer triggered termination */
++                      if (peer_gid->gid) /* peer triggered termination */
+                               lgr->peer_shutdown = 1;
+                       list_move(&lgr->list, &lgr_free_list);
+                       lgr->freeing = 1;
+@@ -1860,9 +1868,12 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, u8 smcr_version,
+ }
+ static bool smcd_lgr_match(struct smc_link_group *lgr,
+-                         struct smcd_dev *smcismdev, u64 peer_gid)
++                         struct smcd_dev *smcismdev,
++                         struct smcd_gid *peer_gid)
+ {
+-      return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev;
++      return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev &&
++              smc_ism_is_virtual(smcismdev) ?
++              (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1;
+ }
+ /* create a new SMC connection (and a new link group if necessary) */
+@@ -1892,7 +1903,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
+               write_lock_bh(&lgr->conns_lock);
+               if ((ini->is_smcd ?
+                    smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
+-                                  ini->ism_peer_gid[ini->ism_selected]) :
++                                  &ini->ism_peer_gid[ini->ism_selected]) :
+                    smcr_lgr_match(lgr, ini->smcr_version,
+                                   ini->peer_systemid,
+                                   ini->peer_gid, ini->peer_mac, role,
+diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
+index 120027d404692..670f8359da558 100644
+--- a/net/smc/smc_core.h
++++ b/net/smc/smc_core.h
+@@ -17,9 +17,11 @@
+ #include <linux/pci.h>
+ #include <rdma/ib_verbs.h>
+ #include <net/genetlink.h>
++#include <net/smc.h>
+ #include "smc.h"
+ #include "smc_ib.h"
++#include "smc_clc.h"
+ #define SMC_RMBS_PER_LGR_MAX  255     /* max. # of RMBs per link group */
+ #define SMC_CONN_PER_LGR_MIN  16      /* min. # of connections per link group */
+@@ -355,7 +357,7 @@ struct smc_link_group {
+                                               /* max links can be added in lgr */
+               };
+               struct { /* SMC-D */
+-                      u64                     peer_gid;
++                      struct smcd_gid         peer_gid;
+                                               /* Peer GID (remote) */
+                       struct smcd_dev         *smcd;
+                                               /* ISM device for VLAN reg. */
+@@ -392,6 +394,11 @@ struct smc_init_info_smcrv2 {
+       struct smc_gidlist      gidlist;
+ };
++#define SMC_MAX_V2_ISM_DEVS   SMCD_CLC_MAX_V2_GID_ENTRIES
++                              /* max # of proposed non-native ISM devices,
++                               * which can't exceed the max # of CHID-GID
++                               * entries in CLC proposal SMC-Dv2 extension.
++                               */
+ struct smc_init_info {
+       u8                      is_smcd;
+       u8                      smc_type_v1;
+@@ -416,9 +423,9 @@ struct smc_init_info {
+       u32                     ib_clcqpn;
+       struct smc_init_info_smcrv2 smcrv2;
+       /* SMC-D */
+-      u64                     ism_peer_gid[SMC_MAX_ISM_DEVS + 1];
+-      struct smcd_dev         *ism_dev[SMC_MAX_ISM_DEVS + 1];
+-      u16                     ism_chid[SMC_MAX_ISM_DEVS + 1];
++      struct smcd_gid         ism_peer_gid[SMC_MAX_V2_ISM_DEVS + 1];
++      struct smcd_dev         *ism_dev[SMC_MAX_V2_ISM_DEVS + 1];
++      u16                     ism_chid[SMC_MAX_V2_ISM_DEVS + 1];
+       u8                      ism_offered_cnt; /* # of ISM devices offered */
+       u8                      ism_selected;    /* index of selected ISM dev*/
+       u8                      smcd_version;
+@@ -544,7 +551,7 @@ void smc_lgr_hold(struct smc_link_group *lgr);
+ void smc_lgr_put(struct smc_link_group *lgr);
+ void smcr_port_add(struct smc_ib_device *smcibdev, u8 ibport);
+ void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport);
+-void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
++void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
+                       unsigned short vlan);
+ void smc_smcd_terminate_all(struct smcd_dev *dev);
+ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev);
+diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
+index d58c699b5328a..086e48b3cdea6 100644
+--- a/net/smc/smc_diag.c
++++ b/net/smc/smc_diag.c
+@@ -21,6 +21,7 @@
+ #include "smc.h"
+ #include "smc_core.h"
++#include "smc_ism.h"
+ struct smc_diag_dump_ctx {
+       int pos[2];
+@@ -167,12 +168,14 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
+               struct smc_connection *conn = &smc->conn;
+               struct smcd_diag_dmbinfo dinfo;
+               struct smcd_dev *smcd = conn->lgr->smcd;
++              struct smcd_gid smcd_gid;
+               memset(&dinfo, 0, sizeof(dinfo));
+               dinfo.linkid = *((u32 *)conn->lgr->id);
+-              dinfo.peer_gid = conn->lgr->peer_gid;
+-              dinfo.my_gid = smcd->ops->get_local_gid(smcd);
++              dinfo.peer_gid = conn->lgr->peer_gid.gid;
++              smcd->ops->get_local_gid(smcd, &smcd_gid);
++              dinfo.my_gid = smcd_gid.gid;
+               dinfo.token = conn->rmb_desc->token;
+               dinfo.peer_token = conn->peer_token;
+diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
+index fbee2493091f1..a33f861cf7c19 100644
+--- a/net/smc/smc_ism.c
++++ b/net/smc/smc_ism.c
+@@ -44,7 +44,8 @@ static struct ism_client smc_ism_client = {
+ #endif
+ /* Test if an ISM communication is possible - same CPC */
+-int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
++int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
++                  struct smcd_dev *smcd)
+ {
+       return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
+                                          vlan_id);
+@@ -208,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
+       dmb.dmb_len = dmb_len;
+       dmb.sba_idx = dmb_desc->sba_idx;
+       dmb.vlan_id = lgr->vlan_id;
+-      dmb.rgid = lgr->peer_gid;
++      dmb.rgid = lgr->peer_gid.gid;
+       rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client);
+       if (!rc) {
+               dmb_desc->sba_idx = dmb.sba_idx;
+@@ -340,18 +341,20 @@ union smcd_sw_event_info {
+ static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
+ {
++      struct smcd_gid peer_gid = { .gid = wrk->event.tok,
++                                   .gid_ext = 0 };
+       union smcd_sw_event_info ev_info;
+       ev_info.info = wrk->event.info;
+       switch (wrk->event.code) {
+       case ISM_EVENT_CODE_SHUTDOWN:   /* Peer shut down DMBs */
+-              smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id);
++              smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
+               break;
+       case ISM_EVENT_CODE_TESTLINK:   /* Activity timer */
+               if (ev_info.code == ISM_EVENT_REQUEST) {
+                       ev_info.code = ISM_EVENT_RESPONSE;
+                       wrk->smcd->ops->signal_event(wrk->smcd,
+-                                                   wrk->event.tok,
++                                                   &peer_gid,
+                                                    ISM_EVENT_REQUEST_IR,
+                                                    ISM_EVENT_CODE_TESTLINK,
+                                                    ev_info.info);
+@@ -365,10 +368,12 @@ static void smc_ism_event_work(struct work_struct *work)
+ {
+       struct smc_ism_event_work *wrk =
+               container_of(work, struct smc_ism_event_work, work);
++      struct smcd_gid smcd_gid = { .gid = wrk->event.tok,
++                                   .gid_ext = 0 };
+       switch (wrk->event.type) {
+       case ISM_EVENT_GID:     /* GID event, token is peer GID */
+-              smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK);
++              smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK);
+               break;
+       case ISM_EVENT_DMB:
+               break;
+@@ -525,7 +530,7 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
+       memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
+       ev_info.vlan_id = lgr->vlan_id;
+       ev_info.code = ISM_EVENT_REQUEST;
+-      rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
++      rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid,
+                                         ISM_EVENT_REQUEST_IR,
+                                         ISM_EVENT_CODE_SHUTDOWN,
+                                         ev_info.info);
+diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
+index d1228a615f23c..0e5e563099ec3 100644
+--- a/net/smc/smc_ism.h
++++ b/net/smc/smc_ism.h
+@@ -32,7 +32,8 @@ struct smc_ism_vlanid {                      /* VLAN id set on ISM device */
+ struct smcd_dev;
+-int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *dev);
++int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
++                  struct smcd_dev *dev);
+ void smc_ism_set_conn(struct smc_connection *conn);
+ void smc_ism_unset_conn(struct smc_connection *conn);
+ int smc_ism_get_vlan(struct smcd_dev *dev, unsigned short vlan_id);
+diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
+index 284cec1e20ec1..dbcc72b43d0c0 100644
+--- a/net/smc/smc_pnet.c
++++ b/net/smc/smc_pnet.c
+@@ -1113,8 +1113,8 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
+       list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
+               if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) &&
+                   !ismdev->going_away &&
+-                  (!ini->ism_peer_gid[0] ||
+-                   !smc_ism_cantalk(ini->ism_peer_gid[0], ini->vlan_id,
++                  (!ini->ism_peer_gid[0].gid ||
++                   !smc_ism_cantalk(&ini->ism_peer_gid[0], ini->vlan_id,
+                                     ismdev))) {
+                       ini->ism_dev[0] = ismdev;
+                       break;
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-define-a-reserved-chid-range-for-virtual-ism.patch b/queue-6.6/net-smc-define-a-reserved-chid-range-for-virtual-ism.patch
new file mode 100644 (file)
index 0000000..2a60129
--- /dev/null
@@ -0,0 +1,64 @@
+From f199d60614fb7bbaba78492728b5b7a8b4e2dbd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 22:26:12 +0800
+Subject: net/smc: define a reserved CHID range for virtual ISM devices
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit 8dd512df3c98ce8081e3541990bf849157675723 ]
+
+According to virtual ISM support feature defined by SMCv2.1, CHIDs in
+the range 0xFF00 to 0xFFFF are reserved for use by virtual ISM devices.
+
+And two helpers are introduced to distinguish virtual ISM devices from
+the existing platform firmware ISM devices.
+
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-and-tested-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_ism.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
+index 832b2f42d79f3..d1228a615f23c 100644
+--- a/net/smc/smc_ism.h
++++ b/net/smc/smc_ism.h
+@@ -15,6 +15,8 @@
+ #include "smc.h"
++#define SMC_VIRTUAL_ISM_CHID_MASK     0xFF00
++
+ struct smcd_dev_list {        /* List of SMCD devices */
+       struct list_head list;
+       struct mutex mutex;     /* Protects list of devices */
+@@ -56,4 +58,22 @@ static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok,
+       return rc < 0 ? rc : 0;
+ }
++static inline bool __smc_ism_is_virtual(u16 chid)
++{
++      /* CHIDs in range of 0xFF00 to 0xFFFF are reserved
++       * for virtual ISM device.
++       *
++       * loopback-ism:        0xFFFF
++       * virtio-ism:          0xFF00 ~ 0xFFFE
++       */
++      return ((chid & 0xFF00) == 0xFF00);
++}
++
++static inline bool smc_ism_is_virtual(struct smcd_dev *smcd)
++{
++      u16 chid = smcd->ops->get_chid(smcd);
++
++      return __smc_ism_is_virtual(chid);
++}
++
+ #endif
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-fix-lgr-and-link-use-after-free-issue.patch b/queue-6.6/net-smc-fix-lgr-and-link-use-after-free-issue.patch
new file mode 100644 (file)
index 0000000..7c4882d
--- /dev/null
@@ -0,0 +1,92 @@
+From 7510ba86773185e342545903770f1f0be0813dfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Nov 2024 21:30:14 +0800
+Subject: net/smc: fix LGR and link use-after-free issue
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit 2c7f14ed9c19ec0f149479d1c2842ec1f9bf76d7 ]
+
+We encountered a LGR/link use-after-free issue, which manifested as
+the LGR/link refcnt reaching 0 early and entering the clear process,
+making resource access unsafe.
+
+ refcount_t: addition on 0; use-after-free.
+ WARNING: CPU: 14 PID: 107447 at lib/refcount.c:25 refcount_warn_saturate+0x9c/0x140
+ Workqueue: events smc_lgr_terminate_work [smc]
+ Call trace:
+  refcount_warn_saturate+0x9c/0x140
+  __smc_lgr_terminate.part.45+0x2a8/0x370 [smc]
+  smc_lgr_terminate_work+0x28/0x30 [smc]
+  process_one_work+0x1b8/0x420
+  worker_thread+0x158/0x510
+  kthread+0x114/0x118
+
+or
+
+ refcount_t: underflow; use-after-free.
+ WARNING: CPU: 6 PID: 93140 at lib/refcount.c:28 refcount_warn_saturate+0xf0/0x140
+ Workqueue: smc_hs_wq smc_listen_work [smc]
+ Call trace:
+  refcount_warn_saturate+0xf0/0x140
+  smcr_link_put+0x1cc/0x1d8 [smc]
+  smc_conn_free+0x110/0x1b0 [smc]
+  smc_conn_abort+0x50/0x60 [smc]
+  smc_listen_find_device+0x75c/0x790 [smc]
+  smc_listen_work+0x368/0x8a0 [smc]
+  process_one_work+0x1b8/0x420
+  worker_thread+0x158/0x510
+  kthread+0x114/0x118
+
+It is caused by repeated release of LGR/link refcnt. One suspect is that
+smc_conn_free() is called repeatedly because some smc_conn_free() from
+server listening path are not protected by sock lock.
+
+e.g.
+
+Calls under socklock        | smc_listen_work
+-------------------------------------------------------
+lock_sock(sk)               | smc_conn_abort
+smc_conn_free               | \- smc_conn_free
+\- smcr_link_put            |    \- smcr_link_put (duplicated)
+release_sock(sk)
+
+So here add sock lock protection in smc_listen_work() path, making it
+exclusive with other connection operations.
+
+Fixes: 3b2dec2603d5 ("net/smc: restructure client and server code in af_smc")
+Co-developed-by: Guangguan Wang <guangguan.wang@linux.alibaba.com>
+Signed-off-by: Guangguan Wang <guangguan.wang@linux.alibaba.com>
+Co-developed-by: Kai <KaiShen@linux.alibaba.com>
+Signed-off-by: Kai <KaiShen@linux.alibaba.com>
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index 755659703a625..77c6c0dff069e 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -1907,6 +1907,7 @@ static void smc_listen_out(struct smc_sock *new_smc)
+       if (tcp_sk(new_smc->clcsock->sk)->syn_smc)
+               atomic_dec(&lsmc->queued_smc_hs);
++      release_sock(newsmcsk); /* lock in smc_listen_work() */
+       if (lsmc->sk.sk_state == SMC_LISTEN) {
+               lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
+               smc_accept_enqueue(&lsmc->sk, newsmcsk);
+@@ -2428,6 +2429,7 @@ static void smc_listen_work(struct work_struct *work)
+       u8 accept_version;
+       int rc = 0;
++      lock_sock(&new_smc->sk); /* release in smc_listen_out() */
+       if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN)
+               return smc_listen_out_err(new_smc);
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-initialize-close_work-early-to-avoid-warning.patch b/queue-6.6/net-smc-initialize-close_work-early-to-avoid-warning.patch
new file mode 100644 (file)
index 0000000..2c3cd3a
--- /dev/null
@@ -0,0 +1,100 @@
+From 2abd14f64246ccfa5bbaa214b9e7247ba5bd9f07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Nov 2024 21:30:13 +0800
+Subject: net/smc: initialize close_work early to avoid warning
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit 0541db8ee32c09463a72d0987382b3a3336b0043 ]
+
+We encountered a warning that close_work was canceled before
+initialization.
+
+  WARNING: CPU: 7 PID: 111103 at kernel/workqueue.c:3047 __flush_work+0x19e/0x1b0
+  Workqueue: events smc_lgr_terminate_work [smc]
+  RIP: 0010:__flush_work+0x19e/0x1b0
+  Call Trace:
+   ? __wake_up_common+0x7a/0x190
+   ? work_busy+0x80/0x80
+   __cancel_work_timer+0xe3/0x160
+   smc_close_cancel_work+0x1a/0x70 [smc]
+   smc_close_active_abort+0x207/0x360 [smc]
+   __smc_lgr_terminate.part.38+0xc8/0x180 [smc]
+   process_one_work+0x19e/0x340
+   worker_thread+0x30/0x370
+   ? process_one_work+0x340/0x340
+   kthread+0x117/0x130
+   ? __kthread_cancel_work+0x50/0x50
+   ret_from_fork+0x22/0x30
+
+This is because when smc_close_cancel_work is triggered, e.g. the RDMA
+driver is rmmod and the LGR is terminated, the conn->close_work is
+flushed before initialization, resulting in WARN_ON(!work->func).
+
+__smc_lgr_terminate             | smc_connect_{rdma|ism}
+-------------------------------------------------------------
+                                | smc_conn_create
+                               | \- smc_lgr_register_conn
+for conn in lgr->conns_all      |
+\- smc_conn_kill                |
+   \- smc_close_active_abort    |
+      \- smc_close_cancel_work  |
+         \- cancel_work_sync    |
+            \- __flush_work     |
+                (close_work)   |
+                               | smc_close_init
+                               | \- INIT_WORK(&close_work)
+
+So fix this by initializing close_work before establishing the
+connection.
+
+Fixes: 46c28dbd4c23 ("net/smc: no socket state changes in tasklet context")
+Fixes: 413498440e30 ("net/smc: add SMC-D support in af_smc")
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index f343e91eec0e4..755659703a625 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -383,6 +383,7 @@ void smc_sk_init(struct net *net, struct sock *sk, int protocol)
+       smc->limit_smc_hs = net->smc.limit_smc_hs;
+       smc->use_fallback = false; /* assume rdma capability first */
+       smc->fallback_rsn = 0;
++      smc_close_init(smc);
+ }
+ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
+@@ -1298,7 +1299,6 @@ static int smc_connect_rdma(struct smc_sock *smc,
+               goto connect_abort;
+       }
+-      smc_close_init(smc);
+       smc_rx_init(smc);
+       if (ini->first_contact_local) {
+@@ -1434,7 +1434,6 @@ static int smc_connect_ism(struct smc_sock *smc,
+                       goto connect_abort;
+               }
+       }
+-      smc_close_init(smc);
+       smc_rx_init(smc);
+       smc_tx_init(smc);
+@@ -2486,7 +2485,6 @@ static void smc_listen_work(struct work_struct *work)
+               goto out_decl;
+       mutex_lock(&smc_server_lgr_pending);
+-      smc_close_init(new_smc);
+       smc_rx_init(new_smc);
+       smc_tx_init(new_smc);
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-introduce-sub-functions-for-smc_clc_send_con.patch b/queue-6.6/net-smc-introduce-sub-functions-for-smc_clc_send_con.patch
new file mode 100644 (file)
index 0000000..1608640
--- /dev/null
@@ -0,0 +1,250 @@
+From a00eb93176ca82cf4e16fce91b293593a10f4f2c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 22:26:08 +0800
+Subject: net/smc: introduce sub-functions for smc_clc_send_confirm_accept()
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit 5205ac4483b630e47c65f192a3ac19be7a8ea648 ]
+
+There is a large if-else block in smc_clc_send_confirm_accept() and it
+is better to split it into two sub-functions.
+
+Suggested-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_clc.c | 197 +++++++++++++++++++++++++++-------------------
+ 1 file changed, 115 insertions(+), 82 deletions(-)
+
+diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
+index b34aff73ada4c..d471a06baac32 100644
+--- a/net/smc/smc_clc.c
++++ b/net/smc/smc_clc.c
+@@ -1007,6 +1007,112 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
+       return reason_code;
+ }
++static void
++smcd_clc_prep_confirm_accept(struct smc_connection *conn,
++                           struct smc_clc_msg_accept_confirm_v2 *clc_v2,
++                           int first_contact, u8 version,
++                           u8 *eid, struct smc_init_info *ini,
++                           int *fce_len,
++                           struct smc_clc_first_contact_ext_v2x *fce_v2x,
++                           struct smc_clc_msg_trail *trl)
++{
++      struct smcd_dev *smcd = conn->lgr->smcd;
++      struct smc_clc_msg_accept_confirm *clc;
++      int len;
++
++      /* SMC-D specific settings */
++      clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
++      memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
++             sizeof(SMCD_EYECATCHER));
++      clc->hdr.typev1 = SMC_TYPE_D;
++      clc->d0.gid = htonll(smcd->ops->get_local_gid(smcd));
++      clc->d0.token = htonll(conn->rmb_desc->token);
++      clc->d0.dmbe_size = conn->rmbe_size_comp;
++      clc->d0.dmbe_idx = 0;
++      memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
++      if (version == SMC_V1) {
++              clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
++      } else {
++              clc_v2->d1.chid = htons(smc_ism_get_chid(smcd));
++              if (eid && eid[0])
++                      memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
++              len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
++              if (first_contact) {
++                      *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini);
++                      len += *fce_len;
++              }
++              clc_v2->hdr.length = htons(len);
++      }
++      memcpy(trl->eyecatcher, SMCD_EYECATCHER,
++             sizeof(SMCD_EYECATCHER));
++}
++
++static void
++smcr_clc_prep_confirm_accept(struct smc_connection *conn,
++                           struct smc_clc_msg_accept_confirm_v2 *clc_v2,
++                           int first_contact, u8 version,
++                           u8 *eid, struct smc_init_info *ini,
++                           int *fce_len,
++                           struct smc_clc_first_contact_ext_v2x *fce_v2x,
++                           struct smc_clc_fce_gid_ext *gle,
++                           struct smc_clc_msg_trail *trl)
++{
++      struct smc_clc_msg_accept_confirm *clc;
++      struct smc_link *link = conn->lnk;
++      int len;
++
++      /* SMC-R specific settings */
++      clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
++      memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER,
++             sizeof(SMC_EYECATCHER));
++      clc->hdr.typev1 = SMC_TYPE_R;
++      memcpy(clc->r0.lcl.id_for_peer, local_systemid,
++             sizeof(local_systemid));
++      memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE);
++      memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
++             ETH_ALEN);
++      hton24(clc->r0.qpn, link->roce_qp->qp_num);
++      clc->r0.rmb_rkey =
++              htonl(conn->rmb_desc->mr[link->link_idx]->rkey);
++      clc->r0.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */
++      clc->r0.rmbe_alert_token = htonl(conn->alert_token_local);
++      switch (clc->hdr.type) {
++      case SMC_CLC_ACCEPT:
++              clc->r0.qp_mtu = link->path_mtu;
++              break;
++      case SMC_CLC_CONFIRM:
++              clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu);
++              break;
++      }
++      clc->r0.rmbe_size = conn->rmbe_size_comp;
++      clc->r0.rmb_dma_addr = conn->rmb_desc->is_vm ?
++              cpu_to_be64((uintptr_t)conn->rmb_desc->cpu_addr) :
++              cpu_to_be64((u64)sg_dma_address
++                          (conn->rmb_desc->sgt[link->link_idx].sgl));
++      hton24(clc->r0.psn, link->psn_initial);
++      if (version == SMC_V1) {
++              clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
++      } else {
++              if (eid && eid[0])
++                      memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
++              len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
++              if (first_contact) {
++                      *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini);
++                      len += *fce_len;
++                      fce_v2x->fce_v2_base.v2_direct =
++                              !link->lgr->uses_gateway;
++                      if (clc->hdr.type == SMC_CLC_CONFIRM) {
++                              memset(gle, 0, sizeof(*gle));
++                              gle->gid_cnt = ini->smcrv2.gidlist.len;
++                              len += sizeof(*gle);
++                              len += gle->gid_cnt * sizeof(gle->gid[0]);
++                      }
++              }
++              clc_v2->hdr.length = htons(len);
++      }
++      memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
++}
++
+ /* build and send CLC CONFIRM / ACCEPT message */
+ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+                                      struct smc_clc_msg_accept_confirm_v2 *clc_v2,
+@@ -1015,11 +1121,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+ {
+       struct smc_clc_first_contact_ext_v2x fce_v2x;
+       struct smc_connection *conn = &smc->conn;
+-      struct smcd_dev *smcd = conn->lgr->smcd;
+       struct smc_clc_msg_accept_confirm *clc;
+       struct smc_clc_fce_gid_ext gle;
+       struct smc_clc_msg_trail trl;
+-      int i, len, fce_len;
++      int i, fce_len;
+       struct kvec vec[5];
+       struct msghdr msg;
+@@ -1028,86 +1133,14 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+       clc->hdr.version = version;     /* SMC version */
+       if (first_contact)
+               clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
+-      if (conn->lgr->is_smcd) {
+-              /* SMC-D specific settings */
+-              memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
+-                     sizeof(SMCD_EYECATCHER));
+-              clc->hdr.typev1 = SMC_TYPE_D;
+-              clc->d0.gid = htonll(smcd->ops->get_local_gid(smcd));
+-              clc->d0.token = htonll(conn->rmb_desc->token);
+-              clc->d0.dmbe_size = conn->rmbe_size_comp;
+-              clc->d0.dmbe_idx = 0;
+-              memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
+-              if (version == SMC_V1) {
+-                      clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
+-              } else {
+-                      clc_v2->d1.chid = htons(smc_ism_get_chid(smcd));
+-                      if (eid && eid[0])
+-                              memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
+-                      len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
+-                      if (first_contact) {
+-                              fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
+-                              len += fce_len;
+-                      }
+-                      clc_v2->hdr.length = htons(len);
+-              }
+-              memcpy(trl.eyecatcher, SMCD_EYECATCHER,
+-                     sizeof(SMCD_EYECATCHER));
+-      } else {
+-              struct smc_link *link = conn->lnk;
+-
+-              /* SMC-R specific settings */
+-              memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER,
+-                     sizeof(SMC_EYECATCHER));
+-              clc->hdr.typev1 = SMC_TYPE_R;
+-              clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
+-              memcpy(clc->r0.lcl.id_for_peer, local_systemid,
+-                     sizeof(local_systemid));
+-              memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE);
+-              memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
+-                     ETH_ALEN);
+-              hton24(clc->r0.qpn, link->roce_qp->qp_num);
+-              clc->r0.rmb_rkey =
+-                      htonl(conn->rmb_desc->mr[link->link_idx]->rkey);
+-              clc->r0.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */
+-              clc->r0.rmbe_alert_token = htonl(conn->alert_token_local);
+-              switch (clc->hdr.type) {
+-              case SMC_CLC_ACCEPT:
+-                      clc->r0.qp_mtu = link->path_mtu;
+-                      break;
+-              case SMC_CLC_CONFIRM:
+-                      clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu);
+-                      break;
+-              }
+-              clc->r0.rmbe_size = conn->rmbe_size_comp;
+-              clc->r0.rmb_dma_addr = conn->rmb_desc->is_vm ?
+-                      cpu_to_be64((uintptr_t)conn->rmb_desc->cpu_addr) :
+-                      cpu_to_be64((u64)sg_dma_address
+-                                  (conn->rmb_desc->sgt[link->link_idx].sgl));
+-              hton24(clc->r0.psn, link->psn_initial);
+-              if (version == SMC_V1) {
+-                      clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
+-              } else {
+-                      if (eid && eid[0])
+-                              memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
+-                      len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
+-                      if (first_contact) {
+-                              fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
+-                              len += fce_len;
+-                              fce_v2x.fce_v2_base.v2_direct =
+-                                      !link->lgr->uses_gateway;
+-                              if (clc->hdr.type == SMC_CLC_CONFIRM) {
+-                                      memset(&gle, 0, sizeof(gle));
+-                                      gle.gid_cnt = ini->smcrv2.gidlist.len;
+-                                      len += sizeof(gle);
+-                                      len += gle.gid_cnt * sizeof(gle.gid[0]);
+-                              }
+-                      }
+-                      clc_v2->hdr.length = htons(len);
+-              }
+-              memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
+-      }
+-
++      if (conn->lgr->is_smcd)
++              smcd_clc_prep_confirm_accept(conn, clc_v2, first_contact,
++                                           version, eid, ini, &fce_len,
++                                           &fce_v2x, &trl);
++      else
++              smcr_clc_prep_confirm_accept(conn, clc_v2, first_contact,
++                                           version, eid, ini, &fce_len,
++                                           &fce_v2x, &gle, &trl);
+       memset(&msg, 0, sizeof(msg));
+       i = 0;
+       vec[i].iov_base = clc_v2;
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-mark-optional-smcd_ops-and-check-for-support.patch b/queue-6.6/net-smc-mark-optional-smcd_ops-and-check-for-support.patch
new file mode 100644 (file)
index 0000000..9e282ee
--- /dev/null
@@ -0,0 +1,99 @@
+From 1dc94ae6574e8c5068e87374548931af15df371e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Apr 2024 14:07:32 +0800
+Subject: net/smc: mark optional smcd_ops and check for support when called
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit d1d8d0b6c7c68b0665456831fa779174ebd78f90 ]
+
+Some operations are not supported by new introduced Emulated-ISM, so
+mark them as optional and check if the device supports them when called.
+
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-and-tested-by: Jan Karcher <jaka@linux.ibm.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/smc.h | 14 ++++++++------
+ net/smc/smc_ism.c |  9 ++++++++-
+ 2 files changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/include/net/smc.h b/include/net/smc.h
+index a0dc1187e96ed..9dfe57f3e4f0b 100644
+--- a/include/net/smc.h
++++ b/include/net/smc.h
+@@ -63,12 +63,6 @@ struct smcd_ops {
+       int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb,
+                           struct ism_client *client);
+       int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
+-      int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
+-      int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
+-      int (*set_vlan_required)(struct smcd_dev *dev);
+-      int (*reset_vlan_required)(struct smcd_dev *dev);
+-      int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
+-                          u32 trigger_irq, u32 event_code, u64 info);
+       int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
+                        bool sf, unsigned int offset, void *data,
+                        unsigned int size);
+@@ -77,6 +71,14 @@ struct smcd_ops {
+       void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
+       u16 (*get_chid)(struct smcd_dev *dev);
+       struct device* (*get_dev)(struct smcd_dev *dev);
++
++      /* optional operations */
++      int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
++      int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
++      int (*set_vlan_required)(struct smcd_dev *dev);
++      int (*reset_vlan_required)(struct smcd_dev *dev);
++      int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
++                          u32 trigger_irq, u32 event_code, u64 info);
+ };
+ struct smcd_dev {
+diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
+index a33f861cf7c19..3623df320de55 100644
+--- a/net/smc/smc_ism.c
++++ b/net/smc/smc_ism.c
+@@ -105,6 +105,8 @@ int smc_ism_get_vlan(struct smcd_dev *smcd, unsigned short vlanid)
+       if (!vlanid)                    /* No valid vlan id */
+               return -EINVAL;
++      if (!smcd->ops->add_vlan_id)
++              return -EOPNOTSUPP;
+       /* create new vlan entry, in case we need it */
+       new_vlan = kzalloc(sizeof(*new_vlan), GFP_KERNEL);
+@@ -150,6 +152,8 @@ int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid)
+       if (!vlanid)                    /* No valid vlan id */
+               return -EINVAL;
++      if (!smcd->ops->del_vlan_id)
++              return -EOPNOTSUPP;
+       spin_lock_irqsave(&smcd->lock, flags);
+       list_for_each_entry(vlan, &smcd->vlan, list) {
+@@ -351,7 +355,8 @@ static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
+               smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
+               break;
+       case ISM_EVENT_CODE_TESTLINK:   /* Activity timer */
+-              if (ev_info.code == ISM_EVENT_REQUEST) {
++              if (ev_info.code == ISM_EVENT_REQUEST &&
++                  wrk->smcd->ops->signal_event) {
+                       ev_info.code = ISM_EVENT_RESPONSE;
+                       wrk->smcd->ops->signal_event(wrk->smcd,
+                                                    &peer_gid,
+@@ -526,6 +531,8 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
+       if (lgr->peer_shutdown)
+               return 0;
++      if (!lgr->smcd->ops->signal_event)
++              return 0;
+       memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
+       ev_info.vlan_id = lgr->vlan_id;
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-refactoring-initialization-of-smc-sock.patch b/queue-6.6/net-smc-refactoring-initialization-of-smc-sock.patch
new file mode 100644 (file)
index 0000000..1c345ca
--- /dev/null
@@ -0,0 +1,177 @@
+From 41ea23f5fc1b637a56820282043ffbc028f2b10d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Jun 2024 02:00:28 +0800
+Subject: net/smc: refactoring initialization of smc sock
+
+From: D. Wythe <alibuda@linux.alibaba.com>
+
+[ Upstream commit d0e35656d83458d668593930f1568d464dde429c ]
+
+This patch aims to isolate the shared components of SMC socket
+allocation by introducing smc_sk_init() for sock initialization
+and __smc_create_clcsk() for the initialization of clcsock.
+
+This is in preparation for the subsequent implementation of the
+AF_INET version of SMC.
+
+Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
+Reviewed-by: Tony Lu <tonylu@linux.alibaba.com>
+Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
+Tested-by: Wenjia Zhang <wenjia@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c | 86 +++++++++++++++++++++++++++---------------------
+ net/smc/smc.h    |  5 +++
+ 2 files changed, 53 insertions(+), 38 deletions(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index c4b30ea4b6ca0..f343e91eec0e4 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -362,25 +362,15 @@ static void smc_destruct(struct sock *sk)
+               return;
+ }
+-static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
+-                                 int protocol)
++void smc_sk_init(struct net *net, struct sock *sk, int protocol)
+ {
+-      struct smc_sock *smc;
+-      struct proto *prot;
+-      struct sock *sk;
+-
+-      prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto;
+-      sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0);
+-      if (!sk)
+-              return NULL;
++      struct smc_sock *smc = smc_sk(sk);
+-      sock_init_data(sock, sk); /* sets sk_refcnt to 1 */
+       sk->sk_state = SMC_INIT;
+       sk->sk_destruct = smc_destruct;
+       sk->sk_protocol = protocol;
+       WRITE_ONCE(sk->sk_sndbuf, 2 * READ_ONCE(net->smc.sysctl_wmem));
+       WRITE_ONCE(sk->sk_rcvbuf, 2 * READ_ONCE(net->smc.sysctl_rmem));
+-      smc = smc_sk(sk);
+       INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work);
+       INIT_WORK(&smc->connect_work, smc_connect_work);
+       INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work);
+@@ -390,6 +380,24 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
+       sk->sk_prot->hash(sk);
+       mutex_init(&smc->clcsock_release_lock);
+       smc_init_saved_callbacks(smc);
++      smc->limit_smc_hs = net->smc.limit_smc_hs;
++      smc->use_fallback = false; /* assume rdma capability first */
++      smc->fallback_rsn = 0;
++}
++
++static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
++                                 int protocol)
++{
++      struct proto *prot;
++      struct sock *sk;
++
++      prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto;
++      sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0);
++      if (!sk)
++              return NULL;
++
++      sock_init_data(sock, sk); /* sets sk_refcnt to 1 */
++      smc_sk_init(net, sk, protocol);
+       return sk;
+ }
+@@ -3303,6 +3311,31 @@ static const struct proto_ops smc_sock_ops = {
+       .splice_read    = smc_splice_read,
+ };
++int smc_create_clcsk(struct net *net, struct sock *sk, int family)
++{
++      struct smc_sock *smc = smc_sk(sk);
++      int rc;
++
++      rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP,
++                            &smc->clcsock);
++      if (rc) {
++              sk_common_release(sk);
++              return rc;
++      }
++
++      /* smc_clcsock_release() does not wait smc->clcsock->sk's
++       * destruction;  its sk_state might not be TCP_CLOSE after
++       * smc->sk is close()d, and TCP timers can be fired later,
++       * which need net ref.
++       */
++      sk = smc->clcsock->sk;
++      __netns_tracker_free(net, &sk->ns_tracker, false);
++      sk->sk_net_refcnt = 1;
++      get_net_track(net, &sk->ns_tracker, GFP_KERNEL);
++      sock_inuse_add(net, 1);
++      return 0;
++}
++
+ static int __smc_create(struct net *net, struct socket *sock, int protocol,
+                       int kern, struct socket *clcsock)
+ {
+@@ -3328,35 +3361,12 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol,
+       /* create internal TCP socket for CLC handshake and fallback */
+       smc = smc_sk(sk);
+-      smc->use_fallback = false; /* assume rdma capability first */
+-      smc->fallback_rsn = 0;
+-
+-      /* default behavior from limit_smc_hs in every net namespace */
+-      smc->limit_smc_hs = net->smc.limit_smc_hs;
+       rc = 0;
+-      if (!clcsock) {
+-              rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP,
+-                                    &smc->clcsock);
+-              if (rc) {
+-                      sk_common_release(sk);
+-                      goto out;
+-              }
+-
+-              /* smc_clcsock_release() does not wait smc->clcsock->sk's
+-               * destruction;  its sk_state might not be TCP_CLOSE after
+-               * smc->sk is close()d, and TCP timers can be fired later,
+-               * which need net ref.
+-               */
+-              sk = smc->clcsock->sk;
+-              __netns_tracker_free(net, &sk->ns_tracker, false);
+-              sk->sk_net_refcnt = 1;
+-              get_net_track(net, &sk->ns_tracker, GFP_KERNEL);
+-              sock_inuse_add(net, 1);
+-      } else {
++      if (clcsock)
+               smc->clcsock = clcsock;
+-      }
+-
++      else
++              rc = smc_create_clcsk(net, sk, family);
+ out:
+       return rc;
+ }
+diff --git a/net/smc/smc.h b/net/smc/smc.h
+index e0afef7a786f8..36699ba551887 100644
+--- a/net/smc/smc.h
++++ b/net/smc/smc.h
+@@ -34,6 +34,11 @@
+ extern struct proto smc_proto;
+ extern struct proto smc_proto6;
++/* smc sock initialization */
++void smc_sk_init(struct net *net, struct sock *sk, int protocol);
++/* clcsock initialization */
++int smc_create_clcsk(struct net *net, struct sock *sk, int family);
++
+ #ifdef ATOMIC64_INIT
+ #define KERNEL_HAS_ATOMIC64
+ #endif
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch b/queue-6.6/net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch
new file mode 100644 (file)
index 0000000..ee47f6e
--- /dev/null
@@ -0,0 +1,103 @@
+From 0043baf8ea53dbe5a0a3469307e5d8e81cbd9127 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 22:26:07 +0800
+Subject: net/smc: rename some 'fce' to 'fce_v2x' for clarity
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit ac053a169c71ceb0f25f784fce9ea720455097b4 ]
+
+Rename some functions or variables with 'fce' in their name but used in
+SMCv2.1 as 'fce_v2x' for clarity.
+
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/smc_clc.c | 30 ++++++++++++++++--------------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
+index 1489a8421d786..b34aff73ada4c 100644
+--- a/net/smc/smc_clc.c
++++ b/net/smc/smc_clc.c
+@@ -428,15 +428,16 @@ smc_clc_msg_decl_valid(struct smc_clc_msg_decline *dclc)
+       return true;
+ }
+-static int smc_clc_fill_fce(struct smc_clc_first_contact_ext_v2x *fce,
+-                          struct smc_init_info *ini)
++static int smc_clc_fill_fce_v2x(struct smc_clc_first_contact_ext_v2x *fce_v2x,
++                              struct smc_init_info *ini)
+ {
+-      int ret = sizeof(*fce);
++      int ret = sizeof(*fce_v2x);
+-      memset(fce, 0, sizeof(*fce));
+-      fce->fce_v2_base.os_type = SMC_CLC_OS_LINUX;
+-      fce->fce_v2_base.release = ini->release_nr;
+-      memcpy(fce->fce_v2_base.hostname, smc_hostname, sizeof(smc_hostname));
++      memset(fce_v2x, 0, sizeof(*fce_v2x));
++      fce_v2x->fce_v2_base.os_type = SMC_CLC_OS_LINUX;
++      fce_v2x->fce_v2_base.release = ini->release_nr;
++      memcpy(fce_v2x->fce_v2_base.hostname,
++             smc_hostname, sizeof(smc_hostname));
+       if (ini->is_smcd && ini->release_nr < SMC_RELEASE_1) {
+               ret = sizeof(struct smc_clc_first_contact_ext);
+               goto out;
+@@ -444,8 +445,8 @@ static int smc_clc_fill_fce(struct smc_clc_first_contact_ext_v2x *fce,
+       if (ini->release_nr >= SMC_RELEASE_1) {
+               if (!ini->is_smcd) {
+-                      fce->max_conns = ini->max_conns;
+-                      fce->max_links = ini->max_links;
++                      fce_v2x->max_conns = ini->max_conns;
++                      fce_v2x->max_links = ini->max_links;
+               }
+       }
+@@ -1012,8 +1013,8 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+                                      int first_contact, u8 version,
+                                      u8 *eid, struct smc_init_info *ini)
+ {
++      struct smc_clc_first_contact_ext_v2x fce_v2x;
+       struct smc_connection *conn = &smc->conn;
+-      struct smc_clc_first_contact_ext_v2x fce;
+       struct smcd_dev *smcd = conn->lgr->smcd;
+       struct smc_clc_msg_accept_confirm *clc;
+       struct smc_clc_fce_gid_ext gle;
+@@ -1045,7 +1046,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+                               memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
+                       len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
+                       if (first_contact) {
+-                              fce_len = smc_clc_fill_fce(&fce, ini);
++                              fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
+                               len += fce_len;
+                       }
+                       clc_v2->hdr.length = htons(len);
+@@ -1091,9 +1092,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+                               memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
+                       len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
+                       if (first_contact) {
+-                              fce_len = smc_clc_fill_fce(&fce, ini);
++                              fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
+                               len += fce_len;
+-                              fce.fce_v2_base.v2_direct = !link->lgr->uses_gateway;
++                              fce_v2x.fce_v2_base.v2_direct =
++                                      !link->lgr->uses_gateway;
+                               if (clc->hdr.type == SMC_CLC_CONFIRM) {
+                                       memset(&gle, 0, sizeof(gle));
+                                       gle.gid_cnt = ini->smcrv2.gidlist.len;
+@@ -1120,7 +1122,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+                                               SMCR_CLC_ACCEPT_CONFIRM_LEN) -
+                                  sizeof(trl);
+       if (version > SMC_V1 && first_contact) {
+-              vec[i].iov_base = &fce;
++              vec[i].iov_base = &fce_v2x;
+               vec[i++].iov_len = fce_len;
+               if (!conn->lgr->is_smcd) {
+                       if (clc->hdr.type == SMC_CLC_CONFIRM) {
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-smc-unify-the-structs-of-accept-or-confirm-messa.patch b/queue-6.6/net-smc-unify-the-structs-of-accept-or-confirm-messa.patch
new file mode 100644 (file)
index 0000000..c8822b8
--- /dev/null
@@ -0,0 +1,474 @@
+From 5e39581587629a940e2a3959aee26b2fb4572ba9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 22:26:09 +0800
+Subject: net/smc: unify the structs of accept or confirm message for v1 and v2
+
+From: Wen Gu <guwen@linux.alibaba.com>
+
+[ Upstream commit 9505450d55b0f7809fe63c36ad9339a909461c87 ]
+
+The structs of CLC accept and confirm messages for SMCv1 and SMCv2 are
+separately defined and often casted to each other in the code, which may
+increase the risk of errors caused by future divergence of them. So
+unify them into one struct for better maintainability.
+
+Suggested-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: Wen Gu <guwen@linux.alibaba.com>
+Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/smc/af_smc.c  | 52 +++++++++++++------------------------
+ net/smc/smc_clc.c | 65 ++++++++++++++++++++---------------------------
+ net/smc/smc_clc.h | 42 +++++++++++++-----------------
+ 3 files changed, 62 insertions(+), 97 deletions(-)
+
+diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
+index 3158b94fd347a..ea24fb4dae0df 100644
+--- a/net/smc/af_smc.c
++++ b/net/smc/af_smc.c
+@@ -659,8 +659,6 @@ static bool smc_isascii(char *hostname)
+ static void smc_conn_save_peer_info_fce(struct smc_sock *smc,
+                                       struct smc_clc_msg_accept_confirm *clc)
+ {
+-      struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
+-              (struct smc_clc_msg_accept_confirm_v2 *)clc;
+       struct smc_clc_first_contact_ext *fce;
+       int clc_v2_len;
+@@ -669,17 +667,15 @@ static void smc_conn_save_peer_info_fce(struct smc_sock *smc,
+               return;
+       if (smc->conn.lgr->is_smcd) {
+-              memcpy(smc->conn.lgr->negotiated_eid, clc_v2->d1.eid,
++              memcpy(smc->conn.lgr->negotiated_eid, clc->d1.eid,
+                      SMC_MAX_EID_LEN);
+-              clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm_v2,
+-                                       d1);
++              clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm, d1);
+       } else {
+-              memcpy(smc->conn.lgr->negotiated_eid, clc_v2->r1.eid,
++              memcpy(smc->conn.lgr->negotiated_eid, clc->r1.eid,
+                      SMC_MAX_EID_LEN);
+-              clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm_v2,
+-                                       r1);
++              clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm, r1);
+       }
+-      fce = (struct smc_clc_first_contact_ext *)(((u8 *)clc_v2) + clc_v2_len);
++      fce = (struct smc_clc_first_contact_ext *)(((u8 *)clc) + clc_v2_len);
+       smc->conn.lgr->peer_os = fce->os_type;
+       smc->conn.lgr->peer_smc_release = fce->release;
+       if (smc_isascii(fce->hostname))
+@@ -1131,13 +1127,13 @@ static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc,
+ }
+ #define SMC_CLC_MAX_ACCEPT_LEN \
+-      (sizeof(struct smc_clc_msg_accept_confirm_v2) + \
++      (sizeof(struct smc_clc_msg_accept_confirm) + \
+        sizeof(struct smc_clc_first_contact_ext_v2x) + \
+        sizeof(struct smc_clc_msg_trail))
+ /* CLC handshake during connect */
+ static int smc_connect_clc(struct smc_sock *smc,
+-                         struct smc_clc_msg_accept_confirm_v2 *aclc2,
++                         struct smc_clc_msg_accept_confirm *aclc,
+                          struct smc_init_info *ini)
+ {
+       int rc = 0;
+@@ -1147,7 +1143,7 @@ static int smc_connect_clc(struct smc_sock *smc,
+       if (rc)
+               return rc;
+       /* receive SMC Accept CLC message */
+-      return smc_clc_wait_msg(smc, aclc2, SMC_CLC_MAX_ACCEPT_LEN,
++      return smc_clc_wait_msg(smc, aclc, SMC_CLC_MAX_ACCEPT_LEN,
+                               SMC_CLC_ACCEPT, CLC_WAIT_TIME);
+ }
+@@ -1183,10 +1179,8 @@ static int smc_connect_rdma_v2_prepare(struct smc_sock *smc,
+                                      struct smc_clc_msg_accept_confirm *aclc,
+                                      struct smc_init_info *ini)
+ {
+-      struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
+-              (struct smc_clc_msg_accept_confirm_v2 *)aclc;
+       struct smc_clc_first_contact_ext *fce =
+-              smc_get_clc_first_contact_ext(clc_v2, false);
++              smc_get_clc_first_contact_ext(aclc, false);
+       struct net *net = sock_net(&smc->sk);
+       int rc;
+@@ -1309,10 +1303,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
+       }
+       if (aclc->hdr.version > SMC_V1) {
+-              struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
+-                      (struct smc_clc_msg_accept_confirm_v2 *)aclc;
+-
+-              eid = clc_v2->r1.eid;
++              eid = aclc->r1.eid;
+               if (ini->first_contact_local)
+                       smc_fill_gid_list(link->lgr, &ini->smcrv2.gidlist,
+                                         link->smcibdev, link->gid);
+@@ -1353,7 +1344,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
+  * Determine from the CHID of the received CLC ACCEPT the ISM device chosen.
+  */
+ static int
+-smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm_v2 *aclc,
++smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc,
+                              struct smc_init_info *ini)
+ {
+       int i;
+@@ -1380,12 +1371,9 @@ static int smc_connect_ism(struct smc_sock *smc,
+       ini->first_contact_peer = aclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK;
+       if (aclc->hdr.version == SMC_V2) {
+-              struct smc_clc_msg_accept_confirm_v2 *aclc_v2 =
+-                      (struct smc_clc_msg_accept_confirm_v2 *)aclc;
+-
+               if (ini->first_contact_peer) {
+                       struct smc_clc_first_contact_ext *fce =
+-                              smc_get_clc_first_contact_ext(aclc_v2, true);
++                              smc_get_clc_first_contact_ext(aclc, true);
+                       ini->release_nr = fce->release;
+                       rc = smc_clc_clnt_v2x_features_validate(fce, ini);
+@@ -1393,7 +1381,7 @@ static int smc_connect_ism(struct smc_sock *smc,
+                               return rc;
+               }
+-              rc = smc_v2_determine_accepted_chid(aclc_v2, ini);
++              rc = smc_v2_determine_accepted_chid(aclc, ini);
+               if (rc)
+                       return rc;
+       }
+@@ -1419,12 +1407,8 @@ static int smc_connect_ism(struct smc_sock *smc,
+       smc_rx_init(smc);
+       smc_tx_init(smc);
+-      if (aclc->hdr.version > SMC_V1) {
+-              struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
+-                      (struct smc_clc_msg_accept_confirm_v2 *)aclc;
+-
+-              eid = clc_v2->d1.eid;
+-      }
++      if (aclc->hdr.version > SMC_V1)
++              eid = aclc->d1.eid;
+       rc = smc_clc_send_confirm(smc, ini->first_contact_local,
+                                 aclc->hdr.version, eid, ini);
+@@ -1475,7 +1459,6 @@ static int smc_connect_check_aclc(struct smc_init_info *ini,
+ static int __smc_connect(struct smc_sock *smc)
+ {
+       u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1;
+-      struct smc_clc_msg_accept_confirm_v2 *aclc2;
+       struct smc_clc_msg_accept_confirm *aclc;
+       struct smc_init_info *ini = NULL;
+       u8 *buf = NULL;
+@@ -1523,11 +1506,10 @@ static int __smc_connect(struct smc_sock *smc)
+               rc = SMC_CLC_DECL_MEM;
+               goto fallback;
+       }
+-      aclc2 = (struct smc_clc_msg_accept_confirm_v2 *)buf;
+-      aclc = (struct smc_clc_msg_accept_confirm *)aclc2;
++      aclc = (struct smc_clc_msg_accept_confirm *)buf;
+       /* perform CLC handshake */
+-      rc = smc_connect_clc(smc, aclc2, ini);
++      rc = smc_connect_clc(smc, aclc, ini);
+       if (rc) {
+               /* -EAGAIN on timeout, see tcp_recvmsg() */
+               if (rc == -EAGAIN) {
+diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
+index d471a06baac32..a28dee81d6fa4 100644
+--- a/net/smc/smc_clc.c
++++ b/net/smc/smc_clc.c
+@@ -387,9 +387,9 @@ static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
+ /* check arriving CLC accept or confirm */
+ static bool
+-smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2)
++smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm *clc)
+ {
+-      struct smc_clc_msg_hdr *hdr = &clc_v2->hdr;
++      struct smc_clc_msg_hdr *hdr = &clc->hdr;
+       if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D)
+               return false;
+@@ -459,7 +459,7 @@ static int smc_clc_fill_fce_v2x(struct smc_clc_first_contact_ext_v2x *fce_v2x,
+  */
+ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
+ {
+-      struct smc_clc_msg_accept_confirm_v2 *clc_v2;
++      struct smc_clc_msg_accept_confirm *clc;
+       struct smc_clc_msg_proposal *pclc;
+       struct smc_clc_msg_decline *dclc;
+       struct smc_clc_msg_trail *trl;
+@@ -477,12 +477,11 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
+               break;
+       case SMC_CLC_ACCEPT:
+       case SMC_CLC_CONFIRM:
+-              clc_v2 = (struct smc_clc_msg_accept_confirm_v2 *)clcm;
+-              if (!smc_clc_msg_acc_conf_valid(clc_v2))
++              clc = (struct smc_clc_msg_accept_confirm *)clcm;
++              if (!smc_clc_msg_acc_conf_valid(clc))
+                       return false;
+               trl = (struct smc_clc_msg_trail *)
+-                      ((u8 *)clc_v2 + ntohs(clc_v2->hdr.length) -
+-                                                      sizeof(*trl));
++                      ((u8 *)clc + ntohs(clc->hdr.length) - sizeof(*trl));
+               break;
+       case SMC_CLC_DECLINE:
+               dclc = (struct smc_clc_msg_decline *)clcm;
+@@ -1009,7 +1008,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
+ static void
+ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
+-                           struct smc_clc_msg_accept_confirm_v2 *clc_v2,
++                           struct smc_clc_msg_accept_confirm *clc,
+                            int first_contact, u8 version,
+                            u8 *eid, struct smc_init_info *ini,
+                            int *fce_len,
+@@ -1017,11 +1016,9 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
+                            struct smc_clc_msg_trail *trl)
+ {
+       struct smcd_dev *smcd = conn->lgr->smcd;
+-      struct smc_clc_msg_accept_confirm *clc;
+       int len;
+       /* SMC-D specific settings */
+-      clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
+       memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
+              sizeof(SMCD_EYECATCHER));
+       clc->hdr.typev1 = SMC_TYPE_D;
+@@ -1033,15 +1030,15 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
+       if (version == SMC_V1) {
+               clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
+       } else {
+-              clc_v2->d1.chid = htons(smc_ism_get_chid(smcd));
++              clc->d1.chid = htons(smc_ism_get_chid(smcd));
+               if (eid && eid[0])
+-                      memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
++                      memcpy(clc->d1.eid, eid, SMC_MAX_EID_LEN);
+               len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
+               if (first_contact) {
+                       *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini);
+                       len += *fce_len;
+               }
+-              clc_v2->hdr.length = htons(len);
++              clc->hdr.length = htons(len);
+       }
+       memcpy(trl->eyecatcher, SMCD_EYECATCHER,
+              sizeof(SMCD_EYECATCHER));
+@@ -1049,7 +1046,7 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
+ static void
+ smcr_clc_prep_confirm_accept(struct smc_connection *conn,
+-                           struct smc_clc_msg_accept_confirm_v2 *clc_v2,
++                           struct smc_clc_msg_accept_confirm *clc,
+                            int first_contact, u8 version,
+                            u8 *eid, struct smc_init_info *ini,
+                            int *fce_len,
+@@ -1057,12 +1054,10 @@ smcr_clc_prep_confirm_accept(struct smc_connection *conn,
+                            struct smc_clc_fce_gid_ext *gle,
+                            struct smc_clc_msg_trail *trl)
+ {
+-      struct smc_clc_msg_accept_confirm *clc;
+       struct smc_link *link = conn->lnk;
+       int len;
+       /* SMC-R specific settings */
+-      clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
+       memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER,
+              sizeof(SMC_EYECATCHER));
+       clc->hdr.typev1 = SMC_TYPE_R;
+@@ -1094,7 +1089,7 @@ smcr_clc_prep_confirm_accept(struct smc_connection *conn,
+               clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
+       } else {
+               if (eid && eid[0])
+-                      memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
++                      memcpy(clc->r1.eid, eid, SMC_MAX_EID_LEN);
+               len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
+               if (first_contact) {
+                       *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini);
+@@ -1108,20 +1103,19 @@ smcr_clc_prep_confirm_accept(struct smc_connection *conn,
+                               len += gle->gid_cnt * sizeof(gle->gid[0]);
+                       }
+               }
+-              clc_v2->hdr.length = htons(len);
++              clc->hdr.length = htons(len);
+       }
+       memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
+ }
+ /* build and send CLC CONFIRM / ACCEPT message */
+ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+-                                     struct smc_clc_msg_accept_confirm_v2 *clc_v2,
++                                     struct smc_clc_msg_accept_confirm *clc,
+                                      int first_contact, u8 version,
+                                      u8 *eid, struct smc_init_info *ini)
+ {
+       struct smc_clc_first_contact_ext_v2x fce_v2x;
+       struct smc_connection *conn = &smc->conn;
+-      struct smc_clc_msg_accept_confirm *clc;
+       struct smc_clc_fce_gid_ext gle;
+       struct smc_clc_msg_trail trl;
+       int i, fce_len;
+@@ -1129,21 +1123,20 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+       struct msghdr msg;
+       /* send SMC Confirm CLC msg */
+-      clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
+       clc->hdr.version = version;     /* SMC version */
+       if (first_contact)
+               clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
+       if (conn->lgr->is_smcd)
+-              smcd_clc_prep_confirm_accept(conn, clc_v2, first_contact,
++              smcd_clc_prep_confirm_accept(conn, clc, first_contact,
+                                            version, eid, ini, &fce_len,
+                                            &fce_v2x, &trl);
+       else
+-              smcr_clc_prep_confirm_accept(conn, clc_v2, first_contact,
++              smcr_clc_prep_confirm_accept(conn, clc, first_contact,
+                                            version, eid, ini, &fce_len,
+                                            &fce_v2x, &gle, &trl);
+       memset(&msg, 0, sizeof(msg));
+       i = 0;
+-      vec[i].iov_base = clc_v2;
++      vec[i].iov_base = clc;
+       if (version > SMC_V1)
+               vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ?
+                                       SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 :
+@@ -1177,16 +1170,16 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
+ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
+                        u8 version, u8 *eid, struct smc_init_info *ini)
+ {
+-      struct smc_clc_msg_accept_confirm_v2 cclc_v2;
++      struct smc_clc_msg_accept_confirm cclc;
+       int reason_code = 0;
+       int len;
+       /* send SMC Confirm CLC msg */
+-      memset(&cclc_v2, 0, sizeof(cclc_v2));
+-      cclc_v2.hdr.type = SMC_CLC_CONFIRM;
+-      len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact,
++      memset(&cclc, 0, sizeof(cclc));
++      cclc.hdr.type = SMC_CLC_CONFIRM;
++      len = smc_clc_send_confirm_accept(smc, &cclc, clnt_first_contact,
+                                         version, eid, ini);
+-      if (len < ntohs(cclc_v2.hdr.length)) {
++      if (len < ntohs(cclc.hdr.length)) {
+               if (len >= 0) {
+                       reason_code = -ENETUNREACH;
+                       smc->sk.sk_err = -reason_code;
+@@ -1202,14 +1195,14 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
+ int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
+                       u8 version, u8 *negotiated_eid, struct smc_init_info *ini)
+ {
+-      struct smc_clc_msg_accept_confirm_v2 aclc_v2;
++      struct smc_clc_msg_accept_confirm aclc;
+       int len;
+-      memset(&aclc_v2, 0, sizeof(aclc_v2));
+-      aclc_v2.hdr.type = SMC_CLC_ACCEPT;
+-      len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact,
++      memset(&aclc, 0, sizeof(aclc));
++      aclc.hdr.type = SMC_CLC_ACCEPT;
++      len = smc_clc_send_confirm_accept(new_smc, &aclc, srv_first_contact,
+                                         version, negotiated_eid, ini);
+-      if (len < ntohs(aclc_v2.hdr.length))
++      if (len < ntohs(aclc.hdr.length))
+               len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;
+       return len > 0 ? 0 : len;
+@@ -1270,10 +1263,8 @@ int smc_clc_clnt_v2x_features_validate(struct smc_clc_first_contact_ext *fce,
+ int smc_clc_v2x_features_confirm_check(struct smc_clc_msg_accept_confirm *cclc,
+                                      struct smc_init_info *ini)
+ {
+-      struct smc_clc_msg_accept_confirm_v2 *clc_v2 =
+-              (struct smc_clc_msg_accept_confirm_v2 *)cclc;
+       struct smc_clc_first_contact_ext *fce =
+-              smc_get_clc_first_contact_ext(clc_v2, ini->is_smcd);
++              smc_get_clc_first_contact_ext(cclc, ini->is_smcd);
+       struct smc_clc_first_contact_ext_v2x *fce_v2x =
+               (struct smc_clc_first_contact_ext_v2x *)fce;
+diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h
+index 08155a96a02a1..d7b1716cfb0fd 100644
+--- a/net/smc/smc_clc.h
++++ b/net/smc/smc_clc.h
+@@ -257,30 +257,23 @@ struct smc_clc_fce_gid_ext {
+ };
+ struct smc_clc_msg_accept_confirm {   /* clc accept / confirm message */
+-      struct smc_clc_msg_hdr hdr;
+-      union {
+-              struct smcr_clc_msg_accept_confirm r0; /* SMC-R */
+-              struct { /* SMC-D */
+-                      struct smcd_clc_msg_accept_confirm_common d0;
+-                      u32 reserved5[3];
+-              };
+-      };
+-} __packed;                   /* format defined in RFC7609 */
+-
+-struct smc_clc_msg_accept_confirm_v2 {        /* clc accept / confirm message */
+       struct smc_clc_msg_hdr hdr;
+       union {
+               struct { /* SMC-R */
+                       struct smcr_clc_msg_accept_confirm r0;
+-                      u8 eid[SMC_MAX_EID_LEN];
+-                      u8 reserved6[8];
+-              } r1;
++                      struct { /* v2 only */
++                              u8 eid[SMC_MAX_EID_LEN];
++                              u8 reserved6[8];
++                      } __packed r1;
++              };
+               struct { /* SMC-D */
+                       struct smcd_clc_msg_accept_confirm_common d0;
+-                      __be16 chid;
+-                      u8 eid[SMC_MAX_EID_LEN];
+-                      u8 reserved5[8];
+-              } d1;
++                      struct { /* v2 only, but 12 bytes reserved in v1 */
++                              __be16 chid;
++                              u8 eid[SMC_MAX_EID_LEN];
++                              u8 reserved5[8];
++                      } __packed d1;
++              };
+       };
+ };
+@@ -389,24 +382,23 @@ smc_get_clc_smcd_v2_ext(struct smc_clc_v2_extension *prop_v2ext)
+ }
+ static inline struct smc_clc_first_contact_ext *
+-smc_get_clc_first_contact_ext(struct smc_clc_msg_accept_confirm_v2 *clc_v2,
++smc_get_clc_first_contact_ext(struct smc_clc_msg_accept_confirm *clc,
+                             bool is_smcd)
+ {
+       int clc_v2_len;
+-      if (clc_v2->hdr.version == SMC_V1 ||
+-          !(clc_v2->hdr.typev2 & SMC_FIRST_CONTACT_MASK))
++      if (clc->hdr.version == SMC_V1 ||
++          !(clc->hdr.typev2 & SMC_FIRST_CONTACT_MASK))
+               return NULL;
+       if (is_smcd)
+               clc_v2_len =
+-                      offsetofend(struct smc_clc_msg_accept_confirm_v2, d1);
++                      offsetofend(struct smc_clc_msg_accept_confirm, d1);
+       else
+               clc_v2_len =
+-                      offsetofend(struct smc_clc_msg_accept_confirm_v2, r1);
++                      offsetofend(struct smc_clc_msg_accept_confirm, r1);
+-      return (struct smc_clc_first_contact_ext *)(((u8 *)clc_v2) +
+-                                                  clc_v2_len);
++      return (struct smc_clc_first_contact_ext *)(((u8 *)clc) + clc_v2_len);
+ }
+ struct smcd_dev;
+-- 
+2.43.0
+
diff --git a/queue-6.6/net-timestamp-make-sk_tskey-more-predictable-in-erro.patch b/queue-6.6/net-timestamp-make-sk_tskey-more-predictable-in-erro.patch
new file mode 100644 (file)
index 0000000..7e78a79
--- /dev/null
@@ -0,0 +1,127 @@
+From 8974b17291faf17ea19920f2949c943f2871f865 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Feb 2024 03:04:28 -0800
+Subject: net-timestamp: make sk_tskey more predictable in error path
+
+From: Vadim Fedorenko <vadfed@meta.com>
+
+[ Upstream commit 488b6d91b07112eaaaa4454332c1480894d4e06e ]
+
+When SOF_TIMESTAMPING_OPT_ID is used to ambiguate timestamped datagrams,
+the sk_tskey can become unpredictable in case of any error happened
+during sendmsg(). Move increment later in the code and make decrement of
+sk_tskey in error path. This solution is still racy in case of multiple
+threads doing snedmsg() over the very same socket in parallel, but still
+makes error path much more predictable.
+
+Fixes: 09c2d251b707 ("net-timestamp: add key to disambiguate concurrent datagrams")
+Reported-by: Andy Lutomirski <luto@amacapital.net>
+Signed-off-by: Vadim Fedorenko <vadfed@meta.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://lore.kernel.org/r/20240213110428.1681540-1-vadfed@meta.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 3301ab7d5aeb ("net/ipv6: release expired exception dst cached in socket")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/ip_output.c  | 13 ++++++++-----
+ net/ipv6/ip6_output.c | 13 ++++++++-----
+ 2 files changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
+index 2458461e24874..765bd3f2a8408 100644
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -972,8 +972,8 @@ static int __ip_append_data(struct sock *sk,
+       unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
+       int csummode = CHECKSUM_NONE;
+       struct rtable *rt = (struct rtable *)cork->dst;
++      bool paged, hold_tskey, extra_uref = false;
+       unsigned int wmem_alloc_delta = 0;
+-      bool paged, extra_uref = false;
+       u32 tskey = 0;
+       skb = skb_peek_tail(queue);
+@@ -982,10 +982,6 @@ static int __ip_append_data(struct sock *sk,
+       mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize;
+       paged = !!cork->gso_size;
+-      if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
+-          READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
+-              tskey = atomic_inc_return(&sk->sk_tskey) - 1;
+-
+       hh_len = LL_RESERVED_SPACE(rt->dst.dev);
+       fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
+@@ -1052,6 +1048,11 @@ static int __ip_append_data(struct sock *sk,
+       cork->length += length;
++      hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP &&
++                   READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID;
++      if (hold_tskey)
++              tskey = atomic_inc_return(&sk->sk_tskey) - 1;
++
+       /* So, what's going on in the loop below?
+        *
+        * We use calculated fragment length to generate chained skb,
+@@ -1274,6 +1275,8 @@ static int __ip_append_data(struct sock *sk,
+       cork->length -= length;
+       IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
+       refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
++      if (hold_tskey)
++              atomic_dec(&sk->sk_tskey);
+       return err;
+ }
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 5d8d86c159dc3..65e2f19814358 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -1501,11 +1501,11 @@ static int __ip6_append_data(struct sock *sk,
+       bool zc = false;
+       u32 tskey = 0;
+       struct rt6_info *rt = (struct rt6_info *)cork->dst;
++      bool paged, hold_tskey, extra_uref = false;
+       struct ipv6_txoptions *opt = v6_cork->opt;
+       int csummode = CHECKSUM_NONE;
+       unsigned int maxnonfragsize, headersize;
+       unsigned int wmem_alloc_delta = 0;
+-      bool paged, extra_uref = false;
+       skb = skb_peek_tail(queue);
+       if (!skb) {
+@@ -1517,10 +1517,6 @@ static int __ip6_append_data(struct sock *sk,
+       mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize;
+       orig_mtu = mtu;
+-      if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
+-          READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
+-              tskey = atomic_inc_return(&sk->sk_tskey) - 1;
+-
+       hh_len = LL_RESERVED_SPACE(rt->dst.dev);
+       fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
+@@ -1617,6 +1613,11 @@ static int __ip6_append_data(struct sock *sk,
+                       flags &= ~MSG_SPLICE_PAGES;
+       }
++      hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP &&
++                   READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID;
++      if (hold_tskey)
++              tskey = atomic_inc_return(&sk->sk_tskey) - 1;
++
+       /*
+        * Let's try using as much space as possible.
+        * Use MTU if total length of the message fits into the MTU.
+@@ -1873,6 +1874,8 @@ static int __ip6_append_data(struct sock *sk,
+       cork->length -= length;
+       IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
+       refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
++      if (hold_tskey)
++              atomic_dec(&sk->sk_tskey);
+       return err;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/netfilter-ipset-hold-module-reference-while-requesti.patch b/queue-6.6/netfilter-ipset-hold-module-reference-while-requesti.patch
new file mode 100644 (file)
index 0000000..515f37b
--- /dev/null
@@ -0,0 +1,49 @@
+From 81c7058b582e861c7ed9183d54dba39fdbc34ab4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 Nov 2024 16:30:38 +0100
+Subject: netfilter: ipset: Hold module reference while requesting a module
+
+From: Phil Sutter <phil@nwl.cc>
+
+[ Upstream commit 456f010bfaefde84d3390c755eedb1b0a5857c3c ]
+
+User space may unload ip_set.ko while it is itself requesting a set type
+backend module, leading to a kernel crash. The race condition may be
+provoked by inserting an mdelay() right after the nfnl_unlock() call.
+
+Fixes: a7b4f989a629 ("netfilter: ipset: IP set core support")
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Acked-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/ipset/ip_set_core.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 61431690cbd5f..cc20e6d56807c 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -104,14 +104,19 @@ find_set_type(const char *name, u8 family, u8 revision)
+ static bool
+ load_settype(const char *name)
+ {
++      if (!try_module_get(THIS_MODULE))
++              return false;
++
+       nfnl_unlock(NFNL_SUBSYS_IPSET);
+       pr_debug("try to load ip_set_%s\n", name);
+       if (request_module("ip_set_%s", name) < 0) {
+               pr_warn("Can't find ip_set type %s\n", name);
+               nfnl_lock(NFNL_SUBSYS_IPSET);
++              module_put(THIS_MODULE);
+               return false;
+       }
+       nfnl_lock(NFNL_SUBSYS_IPSET);
++      module_put(THIS_MODULE);
+       return true;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/netfilter-nft_inner-incorrect-percpu-area-handling-u.patch b/queue-6.6/netfilter-nft_inner-incorrect-percpu-area-handling-u.patch
new file mode 100644 (file)
index 0000000..33c4fe8
--- /dev/null
@@ -0,0 +1,169 @@
+From cffc455e40d4140383413ad4f06f2bd1b892b4fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Nov 2024 12:46:54 +0100
+Subject: netfilter: nft_inner: incorrect percpu area handling under softirq
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 7b1d83da254be3bf054965c8f3b1ad976f460ae5 ]
+
+Softirq can interrupt ongoing packet from process context that is
+walking over the percpu area that contains inner header offsets.
+
+Disable bh and perform three checks before restoring the percpu inner
+header offsets to validate that the percpu area is valid for this
+skbuff:
+
+1) If the NFT_PKTINFO_INNER_FULL flag is set on, then this skbuff
+   has already been parsed before for inner header fetching to
+   register.
+
+2) Validate that the percpu area refers to this skbuff using the
+   skbuff pointer as a cookie. If there is a cookie mismatch, then
+   this skbuff needs to be parsed again.
+
+3) Finally, validate if the percpu area refers to this tunnel type.
+
+Only after these three checks the percpu area is restored to a on-stack
+copy and bh is enabled again.
+
+After inner header fetching, the on-stack copy is stored back to the
+percpu area.
+
+Fixes: 3a07327d10a0 ("netfilter: nft_inner: support for inner tunnel header matching")
+Reported-by: syzbot+84d0441b9860f0d63285@syzkaller.appspotmail.com
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables_core.h |  1 +
+ net/netfilter/nft_inner.c              | 57 ++++++++++++++++++++------
+ 2 files changed, 46 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
+index 780a5f6ad4a67..16855c2a03f8e 100644
+--- a/include/net/netfilter/nf_tables_core.h
++++ b/include/net/netfilter/nf_tables_core.h
+@@ -161,6 +161,7 @@ enum {
+ };
+ struct nft_inner_tun_ctx {
++      unsigned long cookie;
+       u16     type;
+       u16     inner_tunoff;
+       u16     inner_lloff;
+diff --git a/net/netfilter/nft_inner.c b/net/netfilter/nft_inner.c
+index 928312d01eb1d..817ab978d24a1 100644
+--- a/net/netfilter/nft_inner.c
++++ b/net/netfilter/nft_inner.c
+@@ -210,35 +210,66 @@ static int nft_inner_parse(const struct nft_inner *priv,
+                          struct nft_pktinfo *pkt,
+                          struct nft_inner_tun_ctx *tun_ctx)
+ {
+-      struct nft_inner_tun_ctx ctx = {};
+       u32 off = pkt->inneroff;
+       if (priv->flags & NFT_INNER_HDRSIZE &&
+-          nft_inner_parse_tunhdr(priv, pkt, &ctx, &off) < 0)
++          nft_inner_parse_tunhdr(priv, pkt, tun_ctx, &off) < 0)
+               return -1;
+       if (priv->flags & (NFT_INNER_LL | NFT_INNER_NH)) {
+-              if (nft_inner_parse_l2l3(priv, pkt, &ctx, off) < 0)
++              if (nft_inner_parse_l2l3(priv, pkt, tun_ctx, off) < 0)
+                       return -1;
+       } else if (priv->flags & NFT_INNER_TH) {
+-              ctx.inner_thoff = off;
+-              ctx.flags |= NFT_PAYLOAD_CTX_INNER_TH;
++              tun_ctx->inner_thoff = off;
++              tun_ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH;
+       }
+-      *tun_ctx = ctx;
+       tun_ctx->type = priv->type;
++      tun_ctx->cookie = (unsigned long)pkt->skb;
+       pkt->flags |= NFT_PKTINFO_INNER_FULL;
+       return 0;
+ }
++static bool nft_inner_restore_tun_ctx(const struct nft_pktinfo *pkt,
++                                    struct nft_inner_tun_ctx *tun_ctx)
++{
++      struct nft_inner_tun_ctx *this_cpu_tun_ctx;
++
++      local_bh_disable();
++      this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
++      if (this_cpu_tun_ctx->cookie != (unsigned long)pkt->skb) {
++              local_bh_enable();
++              return false;
++      }
++      *tun_ctx = *this_cpu_tun_ctx;
++      local_bh_enable();
++
++      return true;
++}
++
++static void nft_inner_save_tun_ctx(const struct nft_pktinfo *pkt,
++                                 const struct nft_inner_tun_ctx *tun_ctx)
++{
++      struct nft_inner_tun_ctx *this_cpu_tun_ctx;
++
++      local_bh_disable();
++      this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
++      if (this_cpu_tun_ctx->cookie != tun_ctx->cookie)
++              *this_cpu_tun_ctx = *tun_ctx;
++      local_bh_enable();
++}
++
+ static bool nft_inner_parse_needed(const struct nft_inner *priv,
+                                  const struct nft_pktinfo *pkt,
+-                                 const struct nft_inner_tun_ctx *tun_ctx)
++                                 struct nft_inner_tun_ctx *tun_ctx)
+ {
+       if (!(pkt->flags & NFT_PKTINFO_INNER_FULL))
+               return true;
++      if (!nft_inner_restore_tun_ctx(pkt, tun_ctx))
++              return true;
++
+       if (priv->type != tun_ctx->type)
+               return true;
+@@ -248,27 +279,29 @@ static bool nft_inner_parse_needed(const struct nft_inner *priv,
+ static void nft_inner_eval(const struct nft_expr *expr, struct nft_regs *regs,
+                          const struct nft_pktinfo *pkt)
+ {
+-      struct nft_inner_tun_ctx *tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
+       const struct nft_inner *priv = nft_expr_priv(expr);
++      struct nft_inner_tun_ctx tun_ctx = {};
+       if (nft_payload_inner_offset(pkt) < 0)
+               goto err;
+-      if (nft_inner_parse_needed(priv, pkt, tun_ctx) &&
+-          nft_inner_parse(priv, (struct nft_pktinfo *)pkt, tun_ctx) < 0)
++      if (nft_inner_parse_needed(priv, pkt, &tun_ctx) &&
++          nft_inner_parse(priv, (struct nft_pktinfo *)pkt, &tun_ctx) < 0)
+               goto err;
+       switch (priv->expr_type) {
+       case NFT_INNER_EXPR_PAYLOAD:
+-              nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx);
++              nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx);
+               break;
+       case NFT_INNER_EXPR_META:
+-              nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx);
++              nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               goto err;
+       }
++      nft_inner_save_tun_ctx(pkt, &tun_ctx);
++
+       return;
+ err:
+       regs->verdict.code = NFT_BREAK;
+-- 
+2.43.0
+
diff --git a/queue-6.6/netfilter-nft_set_hash-skip-duplicated-elements-pend.patch b/queue-6.6/netfilter-nft_set_hash-skip-duplicated-elements-pend.patch
new file mode 100644 (file)
index 0000000..d5e46c3
--- /dev/null
@@ -0,0 +1,97 @@
+From f2428dc4c12cb808229be4b4f6d1ee885cca3b0d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Dec 2024 00:04:49 +0100
+Subject: netfilter: nft_set_hash: skip duplicated elements pending gc run
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 7ffc7481153bbabf3332c6a19b289730c7e1edf5 ]
+
+rhashtable does not provide stable walk, duplicated elements are
+possible in case of resizing. I considered that checking for errors when
+calling rhashtable_walk_next() was sufficient to detect the resizing.
+However, rhashtable_walk_next() returns -EAGAIN only at the end of the
+iteration, which is too late, because a gc work containing duplicated
+elements could have been already scheduled for removal to the worker.
+
+Add a u32 gc worker sequence number per set, bump it on every workqueue
+run. Annotate gc worker sequence number on the expired element. Use it
+to skip those already seen in this gc workqueue run.
+
+Note that this new field is never reset in case gc transaction fails, so
+next gc worker run on the expired element overrides it. Wraparound of gc
+worker sequence number should not be an issue with stale gc worker
+sequence number in the element, that would just postpone the element
+removal in one gc run.
+
+Note that it is not possible to use flags to annotate that element is
+pending gc run to detect duplicates, given that gc transaction can be
+invalidated in case of update from the control plane, therefore, not
+allowing to clear such flag.
+
+On x86_64, pahole reports no changes in the size of nft_rhash_elem.
+
+Fixes: f6c383b8c31a ("netfilter: nf_tables: adapt set backend to use GC transaction API")
+Reported-by: Laurent Fasnacht <laurent.fasnacht@proton.ch>
+Tested-by: Laurent Fasnacht <laurent.fasnacht@proton.ch>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nft_set_hash.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
+index 3a96d4a77a228..cc1ae18485faf 100644
+--- a/net/netfilter/nft_set_hash.c
++++ b/net/netfilter/nft_set_hash.c
+@@ -24,10 +24,12 @@
+ struct nft_rhash {
+       struct rhashtable               ht;
+       struct delayed_work             gc_work;
++      u32                             wq_gc_seq;
+ };
+ struct nft_rhash_elem {
+       struct rhash_head               node;
++      u32                             wq_gc_seq;
+       struct nft_set_ext              ext;
+ };
+@@ -331,6 +333,10 @@ static void nft_rhash_gc(struct work_struct *work)
+       if (!gc)
+               goto done;
++      /* Elements never collected use a zero gc worker sequence number. */
++      if (unlikely(++priv->wq_gc_seq == 0))
++              priv->wq_gc_seq++;
++
+       rhashtable_walk_enter(&priv->ht, &hti);
+       rhashtable_walk_start(&hti);
+@@ -348,6 +354,14 @@ static void nft_rhash_gc(struct work_struct *work)
+                       goto try_later;
+               }
++              /* rhashtable walk is unstable, already seen in this gc run?
++               * Then, skip this element. In case of (unlikely) sequence
++               * wraparound and stale element wq_gc_seq, next gc run will
++               * just find this expired element.
++               */
++              if (he->wq_gc_seq == priv->wq_gc_seq)
++                      continue;
++
+               if (nft_set_elem_is_dead(&he->ext))
+                       goto dead_elem;
+@@ -364,6 +378,8 @@ static void nft_rhash_gc(struct work_struct *work)
+               if (!gc)
+                       goto try_later;
++              /* annotate gc sequence for this attempt. */
++              he->wq_gc_seq = priv->wq_gc_seq;
+               nft_trans_gc_elem_add(gc, he);
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch b/queue-6.6/netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch
new file mode 100644 (file)
index 0000000..7f9b2ef
--- /dev/null
@@ -0,0 +1,38 @@
+From 454666b07ae4bba0f01035e29608ee662499849e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 26 Nov 2024 11:59:06 +0100
+Subject: netfilter: nft_socket: remove WARN_ON_ONCE on maximum cgroup level
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit b7529880cb961d515642ce63f9d7570869bbbdc3 ]
+
+cgroup maximum depth is INT_MAX by default, there is a cgroup toggle to
+restrict this maximum depth to a more reasonable value not to harm
+performance. Remove unnecessary WARN_ON_ONCE which is reachable from
+userspace.
+
+Fixes: 7f3287db6543 ("netfilter: nft_socket: make cgroupsv2 matching work with namespaces")
+Reported-by: syzbot+57bac0866ddd99fe47c0@syzkaller.appspotmail.com
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nft_socket.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c
+index 0a8883a93e836..187b667bad6c3 100644
+--- a/net/netfilter/nft_socket.c
++++ b/net/netfilter/nft_socket.c
+@@ -68,7 +68,7 @@ static noinline int nft_socket_cgroup_subtree_level(void)
+       cgroup_put(cgrp);
+-      if (WARN_ON_ONCE(level > 255))
++      if (level > 255)
+               return -ERANGE;
+       if (WARN_ON_ONCE(level < 0))
+-- 
+2.43.0
+
diff --git a/queue-6.6/netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch b/queue-6.6/netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch
new file mode 100644 (file)
index 0000000..f32df6c
--- /dev/null
@@ -0,0 +1,109 @@
+From e9a09adef9ad20f3f9bbf736bde73ad35ef66ee7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 Nov 2024 09:55:42 +0300
+Subject: netfilter: x_tables: fix LED ID check in led_tg_check()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit 04317f4eb2aad312ad85c1a17ad81fe75f1f9bc7 ]
+
+Syzbot has reported the following BUG detected by KASAN:
+
+BUG: KASAN: slab-out-of-bounds in strlen+0x58/0x70
+Read of size 1 at addr ffff8881022da0c8 by task repro/5879
+...
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x241/0x360
+ ? __pfx_dump_stack_lvl+0x10/0x10
+ ? __pfx__printk+0x10/0x10
+ ? _printk+0xd5/0x120
+ ? __virt_addr_valid+0x183/0x530
+ ? __virt_addr_valid+0x183/0x530
+ print_report+0x169/0x550
+ ? __virt_addr_valid+0x183/0x530
+ ? __virt_addr_valid+0x183/0x530
+ ? __virt_addr_valid+0x45f/0x530
+ ? __phys_addr+0xba/0x170
+ ? strlen+0x58/0x70
+ kasan_report+0x143/0x180
+ ? strlen+0x58/0x70
+ strlen+0x58/0x70
+ kstrdup+0x20/0x80
+ led_tg_check+0x18b/0x3c0
+ xt_check_target+0x3bb/0xa40
+ ? __pfx_xt_check_target+0x10/0x10
+ ? stack_depot_save_flags+0x6e4/0x830
+ ? nft_target_init+0x174/0xc30
+ nft_target_init+0x82d/0xc30
+ ? __pfx_nft_target_init+0x10/0x10
+ ? nf_tables_newrule+0x1609/0x2980
+ ? nf_tables_newrule+0x1609/0x2980
+ ? rcu_is_watching+0x15/0xb0
+ ? nf_tables_newrule+0x1609/0x2980
+ ? nf_tables_newrule+0x1609/0x2980
+ ? __kmalloc_noprof+0x21a/0x400
+ nf_tables_newrule+0x1860/0x2980
+ ? __pfx_nf_tables_newrule+0x10/0x10
+ ? __nla_parse+0x40/0x60
+ nfnetlink_rcv+0x14e5/0x2ab0
+ ? __pfx_validate_chain+0x10/0x10
+ ? __pfx_nfnetlink_rcv+0x10/0x10
+ ? __lock_acquire+0x1384/0x2050
+ ? netlink_deliver_tap+0x2e/0x1b0
+ ? __pfx_lock_release+0x10/0x10
+ ? netlink_deliver_tap+0x2e/0x1b0
+ netlink_unicast+0x7f8/0x990
+ ? __pfx_netlink_unicast+0x10/0x10
+ ? __virt_addr_valid+0x183/0x530
+ ? __check_object_size+0x48e/0x900
+ netlink_sendmsg+0x8e4/0xcb0
+ ? __pfx_netlink_sendmsg+0x10/0x10
+ ? aa_sock_msg_perm+0x91/0x160
+ ? __pfx_netlink_sendmsg+0x10/0x10
+ __sock_sendmsg+0x223/0x270
+ ____sys_sendmsg+0x52a/0x7e0
+ ? __pfx_____sys_sendmsg+0x10/0x10
+ __sys_sendmsg+0x292/0x380
+ ? __pfx___sys_sendmsg+0x10/0x10
+ ? lockdep_hardirqs_on_prepare+0x43d/0x780
+ ? __pfx_lockdep_hardirqs_on_prepare+0x10/0x10
+ ? exc_page_fault+0x590/0x8c0
+ ? do_syscall_64+0xb6/0x230
+ do_syscall_64+0xf3/0x230
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+...
+ </TASK>
+
+Since an invalid (without '\0' byte at all) byte sequence may be passed
+from userspace, add an extra check to ensure that such a sequence is
+rejected as possible ID and so never passed to 'kstrdup()' and further.
+
+Reported-by: syzbot+6c8215822f35fdb35667@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=6c8215822f35fdb35667
+Fixes: 268cb38e1802 ("netfilter: x_tables: add LED trigger target")
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/xt_LED.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c
+index f7b0286d106ac..8a80fd76fe45b 100644
+--- a/net/netfilter/xt_LED.c
++++ b/net/netfilter/xt_LED.c
+@@ -96,7 +96,9 @@ static int led_tg_check(const struct xt_tgchk_param *par)
+       struct xt_led_info_internal *ledinternal;
+       int err;
+-      if (ledinfo->id[0] == '\0')
++      /* Bail out if empty string or not a string at all. */
++      if (ledinfo->id[0] == '\0' ||
++          !memchr(ledinfo->id, '\0', sizeof(ledinfo->id)))
+               return -EINVAL;
+       mutex_lock(&xt_led_mutex);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-clean-up-comments.patch b/queue-6.6/ntp-clean-up-comments.patch
new file mode 100644 (file)
index 0000000..e0f91d4
--- /dev/null
@@ -0,0 +1,425 @@
+From a952ef82c4ecc4b4ef6ddae4b810213d5944b945 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:39 +0200
+Subject: ntp: Clean up comments
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit a0581cdb2e5d3ad633e51a945b6f0527ce70b68a ]
+
+Usage of different comment formatting makes fast reading and parsing the
+code harder. There are several multi-line comments which do not follow the
+coding style by starting with a line only containing '/*'. There are also
+comments which do not start with capitals.
+
+Clean up all those comments to be consistent and remove comments which
+document the obvious.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-3-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 144 +++++++++++++++++++++++++---------------------
+ 1 file changed, 78 insertions(+), 66 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 8e68a85996f7d..99213d931f63f 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -119,7 +119,8 @@ static long pps_stbcnt;            /* stability limit exceeded */
+ static long pps_errcnt;               /* calibration errors */
+-/* PPS kernel consumer compensates the whole phase error immediately.
++/*
++ * PPS kernel consumer compensates the whole phase error immediately.
+  * Otherwise, reduce the offset by a fixed factor times the time constant.
+  */
+ static inline s64 ntp_offset_chunk(s64 offset)
+@@ -132,8 +133,7 @@ static inline s64 ntp_offset_chunk(s64 offset)
+ static inline void pps_reset_freq_interval(void)
+ {
+-      /* the PPS calibration interval may end
+-         surprisingly early */
++      /* The PPS calibration interval may end surprisingly early */
+       pps_shift = PPS_INTMIN;
+       pps_intcnt = 0;
+ }
+@@ -151,9 +151,9 @@ static inline void pps_clear(void)
+       pps_freq = 0;
+ }
+-/* Decrease pps_valid to indicate that another second has passed since
+- * the last PPS signal. When it reaches 0, indicate that PPS signal is
+- * missing.
++/*
++ * Decrease pps_valid to indicate that another second has passed since the
++ * last PPS signal. When it reaches 0, indicate that PPS signal is missing.
+  */
+ static inline void pps_dec_valid(void)
+ {
+@@ -174,17 +174,21 @@ static inline void pps_set_freq(s64 freq)
+ static inline int is_error_status(int status)
+ {
+       return (status & (STA_UNSYNC|STA_CLOCKERR))
+-              /* PPS signal lost when either PPS time or
+-               * PPS frequency synchronization requested
++              /*
++               * PPS signal lost when either PPS time or PPS frequency
++               * synchronization requested
+                */
+               || ((status & (STA_PPSFREQ|STA_PPSTIME))
+                       && !(status & STA_PPSSIGNAL))
+-              /* PPS jitter exceeded when
+-               * PPS time synchronization requested */
++              /*
++               * PPS jitter exceeded when PPS time synchronization
++               * requested
++               */
+               || ((status & (STA_PPSTIME|STA_PPSJITTER))
+                       == (STA_PPSTIME|STA_PPSJITTER))
+-              /* PPS wander exceeded or calibration error when
+-               * PPS frequency synchronization requested
++              /*
++               * PPS wander exceeded or calibration error when PPS
++               * frequency synchronization requested
+                */
+               || ((status & STA_PPSFREQ)
+                       && (status & (STA_PPSWANDER|STA_PPSERROR)));
+@@ -270,8 +274,8 @@ static void ntp_update_frequency(void)
+       new_base                 = div_u64(second_length, NTP_INTERVAL_FREQ);
+       /*
+-       * Don't wait for the next second_overflow, apply
+-       * the change to the tick length immediately:
++       * Don't wait for the next second_overflow, apply the change to the
++       * tick length immediately:
+        */
+       tick_length             += new_base - tick_length_base;
+       tick_length_base         = new_base;
+@@ -307,10 +311,7 @@ static void ntp_update_offset(long offset)
+               offset *= NSEC_PER_USEC;
+       }
+-      /*
+-       * Scale the phase adjustment and
+-       * clamp to the operating range.
+-       */
++      /* Scale the phase adjustment and clamp to the operating range. */
+       offset = clamp(offset, -MAXPHASE, MAXPHASE);
+       /*
+@@ -349,7 +350,8 @@ static void ntp_update_offset(long offset)
+  */
+ void ntp_clear(void)
+ {
+-      time_adjust     = 0;            /* stop active adjtime() */
++      /* Stop active adjtime() */
++      time_adjust     = 0;
+       time_status     |= STA_UNSYNC;
+       time_maxerror   = NTP_PHASE_LIMIT;
+       time_esterror   = NTP_PHASE_LIMIT;
+@@ -387,7 +389,7 @@ ktime_t ntp_get_next_leap(void)
+ }
+ /*
+- * this routine handles the overflow of the microsecond field
++ * This routine handles the overflow of the microsecond field
+  *
+  * The tricky bits of code to handle the accurate clock support
+  * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+@@ -452,7 +454,6 @@ int second_overflow(time64_t secs)
+               break;
+       }
+-
+       /* Bump the maxerror field */
+       time_maxerror += MAXFREQ / NSEC_PER_USEC;
+       if (time_maxerror > NTP_PHASE_LIMIT) {
+@@ -688,7 +689,7 @@ static inline void process_adj_status(const struct __kernel_timex *txc)
+               time_state = TIME_OK;
+               time_status = STA_UNSYNC;
+               ntp_next_leap_sec = TIME64_MAX;
+-              /* restart PPS frequency calibration */
++              /* Restart PPS frequency calibration */
+               pps_reset_freq_interval();
+       }
+@@ -699,7 +700,7 @@ static inline void process_adj_status(const struct __kernel_timex *txc)
+       if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
+               time_reftime = __ktime_get_real_seconds();
+-      /* only set allowed bits */
++      /* Only set allowed bits */
+       time_status &= STA_RONLY;
+       time_status |= txc->status & ~STA_RONLY;
+ }
+@@ -721,7 +722,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
+               time_freq = txc->freq * PPM_SCALE;
+               time_freq = min(time_freq, MAXFREQ_SCALED);
+               time_freq = max(time_freq, -MAXFREQ_SCALED);
+-              /* update pps_freq */
++              /* Update pps_freq */
+               pps_set_freq(time_freq);
+       }
+@@ -754,7 +755,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
+ /*
+- * adjtimex mainly allows reading (and writing, if superuser) of
++ * adjtimex() mainly allows reading (and writing, if superuser) of
+  * kernel time-keeping variables. used by xntpd.
+  */
+ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+@@ -798,8 +799,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+                       txc->offset = (u32)txc->offset / NSEC_PER_USEC;
+       }
+-      result = time_state;    /* mostly `TIME_OK' */
+-      /* check for errors */
++      result = time_state;
+       if (is_error_status(time_status))
+               result = TIME_ERROR;
+@@ -814,7 +814,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+       txc->tick          = tick_usec;
+       txc->tai           = *time_tai;
+-      /* fill PPS status fields */
++      /* Fill PPS status fields */
+       pps_fill_timex(txc);
+       txc->time.tv_sec = ts->tv_sec;
+@@ -845,17 +845,21 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+ #ifdef        CONFIG_NTP_PPS
+-/* actually struct pps_normtime is good old struct timespec, but it is
++/*
++ * struct pps_normtime is basically a struct timespec, but it is
+  * semantically different (and it is the reason why it was invented):
+  * pps_normtime.nsec has a range of ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ]
+- * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) */
++ * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC)
++ */
+ struct pps_normtime {
+       s64             sec;    /* seconds */
+       long            nsec;   /* nanoseconds */
+ };
+-/* normalize the timestamp so that nsec is in the
+-   ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval */
++/*
++ * Normalize the timestamp so that nsec is in the
++ * [ -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval
++ */
+ static inline struct pps_normtime pps_normalize_ts(struct timespec64 ts)
+ {
+       struct pps_normtime norm = {
+@@ -871,7 +875,7 @@ static inline struct pps_normtime pps_normalize_ts(struct timespec64 ts)
+       return norm;
+ }
+-/* get current phase correction and jitter */
++/* Get current phase correction and jitter */
+ static inline long pps_phase_filter_get(long *jitter)
+ {
+       *jitter = pps_tf[0] - pps_tf[1];
+@@ -882,7 +886,7 @@ static inline long pps_phase_filter_get(long *jitter)
+       return pps_tf[0];
+ }
+-/* add the sample to the phase filter */
++/* Add the sample to the phase filter */
+ static inline void pps_phase_filter_add(long err)
+ {
+       pps_tf[2] = pps_tf[1];
+@@ -890,8 +894,9 @@ static inline void pps_phase_filter_add(long err)
+       pps_tf[0] = err;
+ }
+-/* decrease frequency calibration interval length.
+- * It is halved after four consecutive unstable intervals.
++/*
++ * Decrease frequency calibration interval length. It is halved after four
++ * consecutive unstable intervals.
+  */
+ static inline void pps_dec_freq_interval(void)
+ {
+@@ -904,8 +909,9 @@ static inline void pps_dec_freq_interval(void)
+       }
+ }
+-/* increase frequency calibration interval length.
+- * It is doubled after four consecutive stable intervals.
++/*
++ * Increase frequency calibration interval length. It is doubled after
++ * four consecutive stable intervals.
+  */
+ static inline void pps_inc_freq_interval(void)
+ {
+@@ -918,7 +924,8 @@ static inline void pps_inc_freq_interval(void)
+       }
+ }
+-/* update clock frequency based on MONOTONIC_RAW clock PPS signal
++/*
++ * Update clock frequency based on MONOTONIC_RAW clock PPS signal
+  * timestamps
+  *
+  * At the end of the calibration interval the difference between the
+@@ -932,7 +939,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+       long delta, delta_mod;
+       s64 ftemp;
+-      /* check if the frequency interval was too long */
++      /* Check if the frequency interval was too long */
+       if (freq_norm.sec > (2 << pps_shift)) {
+               time_status |= STA_PPSERROR;
+               pps_errcnt++;
+@@ -943,9 +950,10 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+               return 0;
+       }
+-      /* here the raw frequency offset and wander (stability) is
+-       * calculated. If the wander is less than the wander threshold
+-       * the interval is increased; otherwise it is decreased.
++      /*
++       * Here the raw frequency offset and wander (stability) is
++       * calculated. If the wander is less than the wander threshold the
++       * interval is increased; otherwise it is decreased.
+        */
+       ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT,
+                       freq_norm.sec);
+@@ -957,13 +965,14 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+               time_status |= STA_PPSWANDER;
+               pps_stbcnt++;
+               pps_dec_freq_interval();
+-      } else {        /* good sample */
++      } else {
++              /* Good sample */
+               pps_inc_freq_interval();
+       }
+-      /* the stability metric is calculated as the average of recent
+-       * frequency changes, but is used only for performance
+-       * monitoring
++      /*
++       * The stability metric is calculated as the average of recent
++       * frequency changes, but is used only for performance monitoring
+        */
+       delta_mod = delta;
+       if (delta_mod < 0)
+@@ -972,7 +981,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+                               (NTP_SCALE_SHIFT - SHIFT_USEC),
+                               NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
+-      /* if enabled, the system clock frequency is updated */
++      /* If enabled, the system clock frequency is updated */
+       if ((time_status & STA_PPSFREQ) != 0 &&
+           (time_status & STA_FREQHOLD) == 0) {
+               time_freq = pps_freq;
+@@ -982,17 +991,18 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+       return delta;
+ }
+-/* correct REALTIME clock phase error against PPS signal */
++/* Correct REALTIME clock phase error against PPS signal */
+ static void hardpps_update_phase(long error)
+ {
+       long correction = -error;
+       long jitter;
+-      /* add the sample to the median filter */
++      /* Add the sample to the median filter */
+       pps_phase_filter_add(correction);
+       correction = pps_phase_filter_get(&jitter);
+-      /* Nominal jitter is due to PPS signal noise. If it exceeds the
++      /*
++       * Nominal jitter is due to PPS signal noise. If it exceeds the
+        * threshold, the sample is discarded; otherwise, if so enabled,
+        * the time offset is updated.
+        */
+@@ -1003,13 +1013,13 @@ static void hardpps_update_phase(long error)
+               time_status |= STA_PPSJITTER;
+               pps_jitcnt++;
+       } else if (time_status & STA_PPSTIME) {
+-              /* correct the time using the phase offset */
++              /* Correct the time using the phase offset */
+               time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT,
+                               NTP_INTERVAL_FREQ);
+-              /* cancel running adjtime() */
++              /* Cancel running adjtime() */
+               time_adjust = 0;
+       }
+-      /* update jitter */
++      /* Update jitter */
+       pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN;
+ }
+@@ -1031,41 +1041,43 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
+       pts_norm = pps_normalize_ts(*phase_ts);
+-      /* clear the error bits, they will be set again if needed */
++      /* Clear the error bits, they will be set again if needed */
+       time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
+-      /* indicate signal presence */
++      /* Indicate signal presence */
+       time_status |= STA_PPSSIGNAL;
+       pps_valid = PPS_VALID;
+-      /* when called for the first time,
+-       * just start the frequency interval */
++      /*
++       * When called for the first time, just start the frequency
++       * interval
++       */
+       if (unlikely(pps_fbase.tv_sec == 0)) {
+               pps_fbase = *raw_ts;
+               return;
+       }
+-      /* ok, now we have a base for frequency calculation */
++      /* Ok, now we have a base for frequency calculation */
+       freq_norm = pps_normalize_ts(timespec64_sub(*raw_ts, pps_fbase));
+-      /* check that the signal is in the range
+-       * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */
++      /*
++       * Check that the signal is in the range
++       * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it
++       */
+       if ((freq_norm.sec == 0) ||
+                       (freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
+                       (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
+               time_status |= STA_PPSJITTER;
+-              /* restart the frequency calibration interval */
++              /* Restart the frequency calibration interval */
+               pps_fbase = *raw_ts;
+               printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n");
+               return;
+       }
+-      /* signal is ok */
+-
+-      /* check if the current frequency interval is finished */
++      /* Signal is ok. Check if the current frequency interval is finished */
+       if (freq_norm.sec >= (1 << pps_shift)) {
+               pps_calcnt++;
+-              /* restart the frequency calibration interval */
++              /* Restart the frequency calibration interval */
+               pps_fbase = *raw_ts;
+               hardpps_update_freq(freq_norm);
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-cleanup-formatting-of-code.patch b/queue-6.6/ntp-cleanup-formatting-of-code.patch
new file mode 100644 (file)
index 0000000..aeb5d6b
--- /dev/null
@@ -0,0 +1,134 @@
+From c0d8606cfcee702fb4097c32d30a2cd87d35ddf1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:40 +0200
+Subject: ntp: Cleanup formatting of code
+
+From: Anna-Maria Behnsen <anna-maria@linutronix.de>
+
+[ Upstream commit 38007dc032bd90920463c5d2e6a27d89f7617d6d ]
+
+Code is partially formatted in a creative way which makes reading
+harder. Examples are function calls over several lines where the
+indentation does not start at the same height then the open bracket after
+the function name.
+
+Improve formatting but do not make a functional change.
+
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-4-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 37 +++++++++++++------------------------
+ 1 file changed, 13 insertions(+), 24 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 99213d931f63f..eca9de85b0a76 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -428,8 +428,7 @@ int second_overflow(time64_t secs)
+               } else if (secs == ntp_next_leap_sec) {
+                       leap = -1;
+                       time_state = TIME_OOP;
+-                      printk(KERN_NOTICE
+-                              "Clock: inserting leap second 23:59:60 UTC\n");
++                      pr_notice("Clock: inserting leap second 23:59:60 UTC\n");
+               }
+               break;
+       case TIME_DEL:
+@@ -440,8 +439,7 @@ int second_overflow(time64_t secs)
+                       leap = 1;
+                       ntp_next_leap_sec = TIME64_MAX;
+                       time_state = TIME_WAIT;
+-                      printk(KERN_NOTICE
+-                              "Clock: deleting leap second 23:59:59 UTC\n");
++                      pr_notice("Clock: deleting leap second 23:59:59 UTC\n");
+               }
+               break;
+       case TIME_OOP:
+@@ -834,10 +832,8 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+                       txc->tai--;
+                       txc->time.tv_sec++;
+               }
+-              if ((time_state == TIME_OOP) &&
+-                                      (ts->tv_sec == ntp_next_leap_sec)) {
++              if ((time_state == TIME_OOP) && (ts->tv_sec == ntp_next_leap_sec))
+                       result = TIME_WAIT;
+-              }
+       }
+       return result;
+@@ -944,9 +940,8 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+               time_status |= STA_PPSERROR;
+               pps_errcnt++;
+               pps_dec_freq_interval();
+-              printk_deferred(KERN_ERR
+-                      "hardpps: PPSERROR: interval too long - %lld s\n",
+-                      freq_norm.sec);
++              printk_deferred(KERN_ERR "hardpps: PPSERROR: interval too long - %lld s\n",
++                              freq_norm.sec);
+               return 0;
+       }
+@@ -960,8 +955,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+       delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT);
+       pps_freq = ftemp;
+       if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
+-              printk_deferred(KERN_WARNING
+-                              "hardpps: PPSWANDER: change=%ld\n", delta);
++              printk_deferred(KERN_WARNING "hardpps: PPSWANDER: change=%ld\n", delta);
+               time_status |= STA_PPSWANDER;
+               pps_stbcnt++;
+               pps_dec_freq_interval();
+@@ -977,13 +971,11 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+       delta_mod = delta;
+       if (delta_mod < 0)
+               delta_mod = -delta_mod;
+-      pps_stabil += (div_s64(((s64)delta_mod) <<
+-                              (NTP_SCALE_SHIFT - SHIFT_USEC),
+-                              NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
++      pps_stabil += (div_s64(((s64)delta_mod) << (NTP_SCALE_SHIFT - SHIFT_USEC),
++                             NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
+       /* If enabled, the system clock frequency is updated */
+-      if ((time_status & STA_PPSFREQ) != 0 &&
+-          (time_status & STA_FREQHOLD) == 0) {
++      if ((time_status & STA_PPSFREQ) && !(time_status & STA_FREQHOLD)) {
+               time_freq = pps_freq;
+               ntp_update_frequency();
+       }
+@@ -1007,15 +999,13 @@ static void hardpps_update_phase(long error)
+        * the time offset is updated.
+        */
+       if (jitter > (pps_jitter << PPS_POPCORN)) {
+-              printk_deferred(KERN_WARNING
+-                              "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
++              printk_deferred(KERN_WARNING "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
+                               jitter, (pps_jitter << PPS_POPCORN));
+               time_status |= STA_PPSJITTER;
+               pps_jitcnt++;
+       } else if (time_status & STA_PPSTIME) {
+               /* Correct the time using the phase offset */
+-              time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT,
+-                              NTP_INTERVAL_FREQ);
++              time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
+               /* Cancel running adjtime() */
+               time_adjust = 0;
+       }
+@@ -1064,9 +1054,8 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
+        * Check that the signal is in the range
+        * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it
+        */
+-      if ((freq_norm.sec == 0) ||
+-                      (freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
+-                      (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
++      if ((freq_norm.sec == 0) || (freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
++          (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
+               time_status |= STA_PPSJITTER;
+               /* Restart the frequency calibration interval */
+               pps_fbase = *raw_ts;
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-convert-functions-with-only-two-states-to-bool.patch b/queue-6.6/ntp-convert-functions-with-only-two-states-to-bool.patch
new file mode 100644 (file)
index 0000000..7e4e8f9
--- /dev/null
@@ -0,0 +1,92 @@
+From 7066dbaf1f80ebb01a0858ac1700e39e5010bb3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:41 +0200
+Subject: ntp: Convert functions with only two states to bool
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 48c3c65f64b01164f1704b40b38f60837d484f13 ]
+
+is_error_status() and ntp_synced() return whether a state is set or
+not. Both functions use unsigned int for it even if it would be a perfect
+job for a bool.
+
+Use bool instead of unsigned int. And while at it, move ntp_synced()
+function to the place where it is used.
+
+No functional change.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-5-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 28 +++++++++++-----------------
+ 1 file changed, 11 insertions(+), 17 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index eca9de85b0a76..ef758aafdfd54 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -171,7 +171,7 @@ static inline void pps_set_freq(s64 freq)
+       pps_freq = freq;
+ }
+-static inline int is_error_status(int status)
++static inline bool is_error_status(int status)
+ {
+       return (status & (STA_UNSYNC|STA_CLOCKERR))
+               /*
+@@ -221,7 +221,7 @@ static inline void pps_clear(void) {}
+ static inline void pps_dec_valid(void) {}
+ static inline void pps_set_freq(s64 freq) {}
+-static inline int is_error_status(int status)
++static inline bool is_error_status(int status)
+ {
+       return status & (STA_UNSYNC|STA_CLOCKERR);
+ }
+@@ -241,21 +241,6 @@ static inline void pps_fill_timex(struct __kernel_timex *txc)
+ #endif /* CONFIG_NTP_PPS */
+-
+-/**
+- * ntp_synced - Returns 1 if the NTP status is not UNSYNC
+- *
+- */
+-static inline int ntp_synced(void)
+-{
+-      return !(time_status & STA_UNSYNC);
+-}
+-
+-
+-/*
+- * NTP methods:
+- */
+-
+ /*
+  * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and
+  * time_freq:
+@@ -609,6 +594,15 @@ static inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_ns
+ }
+ #endif
++/**
++ * ntp_synced - Tells whether the NTP status is not UNSYNC
++ * Returns:   true if not UNSYNC, false otherwise
++ */
++static inline bool ntp_synced(void)
++{
++      return !(time_status & STA_UNSYNC);
++}
++
+ /*
+  * If we have an externally synchronized Linux clock, then update RTC clock
+  * accordingly every ~11 minutes. Generally RTCs can only store second
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-introduce-struct-ntp_data.patch b/queue-6.6/ntp-introduce-struct-ntp_data.patch
new file mode 100644 (file)
index 0000000..00a66e2
--- /dev/null
@@ -0,0 +1,220 @@
+From 6018e1b206968dd5a882e341c5582d81b808ffa5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:43 +0200
+Subject: ntp: Introduce struct ntp_data
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 68f66f97c5689825012877f58df65964056d4b5d ]
+
+All NTP data is held in static variables. That prevents the NTP code from
+being reuasble for non-system time timekeepers, e.g. per PTP clock
+timekeeping.
+
+Introduce struct ntp_data and move tick_usec into it for a start.
+
+No functional change.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-7-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 65 ++++++++++++++++++++++++++---------------------
+ 1 file changed, 36 insertions(+), 29 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 477cb08062bc5..0222f8e460810 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -22,16 +22,19 @@
+ #include "ntp_internal.h"
+ #include "timekeeping_internal.h"
+-
+-/*
+- * NTP timekeeping variables:
++/**
++ * struct ntp_data - Structure holding all NTP related state
++ * @tick_usec:                USER_HZ period in microseconds
+  *
+- * Note: All of the NTP state is protected by the timekeeping locks.
++ * Protected by the timekeeping locks.
+  */
++struct ntp_data {
++      unsigned long           tick_usec;
++};
+-
+-/* USER_HZ period (usecs): */
+-static unsigned long          tick_usec = USER_TICK_USEC;
++static struct ntp_data tk_ntp_data = {
++      .tick_usec              = USER_TICK_USEC,
++};
+ static u64                    tick_length;
+ static u64                    tick_length_base;
+@@ -245,13 +248,11 @@ static inline void pps_fill_timex(struct __kernel_timex *txc)
+  * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and
+  * time_freq:
+  */
+-static void ntp_update_frequency(void)
++static void ntp_update_frequency(struct ntp_data *ntpdata)
+ {
+-      u64 second_length;
+-      u64 new_base;
++      u64 second_length, new_base, tick_usec = (u64)ntpdata->tick_usec;
+-      second_length            = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)
+-                                              << NTP_SCALE_SHIFT;
++      second_length            = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << NTP_SCALE_SHIFT;
+       second_length           += ntp_tick_adj;
+       second_length           += time_freq;
+@@ -330,10 +331,7 @@ static void ntp_update_offset(long offset)
+       time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
+ }
+-/**
+- * ntp_clear - Clears the NTP state variables
+- */
+-void ntp_clear(void)
++static void __ntp_clear(struct ntp_data *ntpdata)
+ {
+       /* Stop active adjtime() */
+       time_adjust     = 0;
+@@ -341,7 +339,7 @@ void ntp_clear(void)
+       time_maxerror   = NTP_PHASE_LIMIT;
+       time_esterror   = NTP_PHASE_LIMIT;
+-      ntp_update_frequency();
++      ntp_update_frequency(ntpdata);
+       tick_length     = tick_length_base;
+       time_offset     = 0;
+@@ -351,6 +349,14 @@ void ntp_clear(void)
+       pps_clear();
+ }
++/**
++ * ntp_clear - Clears the NTP state variables
++ */
++void ntp_clear(void)
++{
++      __ntp_clear(&tk_ntp_data);
++}
++
+ u64 ntp_tick_length(void)
+ {
+@@ -698,7 +704,7 @@ static inline void process_adj_status(const struct __kernel_timex *txc)
+ }
+-static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
++static inline void process_adjtimex_modes(struct ntp_data *ntpdata, const struct __kernel_timex *txc,
+                                         s32 *time_tai)
+ {
+       if (txc->modes & ADJ_STATUS)
+@@ -739,13 +745,12 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
+               ntp_update_offset(txc->offset);
+       if (txc->modes & ADJ_TICK)
+-              tick_usec = txc->tick;
++              ntpdata->tick_usec = txc->tick;
+       if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
+-              ntp_update_frequency();
++              ntp_update_frequency(ntpdata);
+ }
+-
+ /*
+  * adjtimex() mainly allows reading (and writing, if superuser) of
+  * kernel time-keeping variables. used by xntpd.
+@@ -753,6 +758,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
+ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+                 s32 *time_tai, struct audit_ntp_data *ad)
+ {
++      struct ntp_data *ntpdata = &tk_ntp_data;
+       int result;
+       if (txc->modes & ADJ_ADJTIME) {
+@@ -761,7 +767,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+               if (!(txc->modes & ADJ_OFFSET_READONLY)) {
+                       /* adjtime() is independent from ntp_adjtime() */
+                       time_adjust = txc->offset;
+-                      ntp_update_frequency();
++                      ntp_update_frequency(ntpdata);
+                       audit_ntp_set_old(ad, AUDIT_NTP_ADJUST, save_adjust);
+                       audit_ntp_set_new(ad, AUDIT_NTP_ADJUST, time_adjust);
+@@ -774,15 +780,15 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+                       audit_ntp_set_old(ad, AUDIT_NTP_FREQ,   time_freq);
+                       audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status);
+                       audit_ntp_set_old(ad, AUDIT_NTP_TAI,    *time_tai);
+-                      audit_ntp_set_old(ad, AUDIT_NTP_TICK,   tick_usec);
++                      audit_ntp_set_old(ad, AUDIT_NTP_TICK,   ntpdata->tick_usec);
+-                      process_adjtimex_modes(txc, time_tai);
++                      process_adjtimex_modes(ntpdata, txc, time_tai);
+                       audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset);
+                       audit_ntp_set_new(ad, AUDIT_NTP_FREQ,   time_freq);
+                       audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status);
+                       audit_ntp_set_new(ad, AUDIT_NTP_TAI,    *time_tai);
+-                      audit_ntp_set_new(ad, AUDIT_NTP_TICK,   tick_usec);
++                      audit_ntp_set_new(ad, AUDIT_NTP_TICK,   ntpdata->tick_usec);
+               }
+               txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+@@ -803,7 +809,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+       txc->constant      = time_constant;
+       txc->precision     = 1;
+       txc->tolerance     = MAXFREQ_SCALED / PPM_SCALE;
+-      txc->tick          = tick_usec;
++      txc->tick          = ntpdata->tick_usec;
+       txc->tai           = *time_tai;
+       /* Fill PPS status fields */
+@@ -924,7 +930,7 @@ static inline void pps_inc_freq_interval(void)
+  * too long, the data are discarded.
+  * Returns the difference between old and new frequency values.
+  */
+-static long hardpps_update_freq(struct pps_normtime freq_norm)
++static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime freq_norm)
+ {
+       long delta, delta_mod;
+       s64 ftemp;
+@@ -971,7 +977,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
+       /* If enabled, the system clock frequency is updated */
+       if ((time_status & STA_PPSFREQ) && !(time_status & STA_FREQHOLD)) {
+               time_freq = pps_freq;
+-              ntp_update_frequency();
++              ntp_update_frequency(ntpdata);
+       }
+       return delta;
+@@ -1022,6 +1028,7 @@ static void hardpps_update_phase(long error)
+ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts)
+ {
+       struct pps_normtime pts_norm, freq_norm;
++      struct ntp_data *ntpdata = &tk_ntp_data;
+       pts_norm = pps_normalize_ts(*phase_ts);
+@@ -1062,7 +1069,7 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
+               pps_calcnt++;
+               /* Restart the frequency calibration interval */
+               pps_fbase = *raw_ts;
+-              hardpps_update_freq(freq_norm);
++              hardpps_update_freq(ntpdata, freq_norm);
+       }
+       hardpps_update_phase(pts_norm.nsec);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-make-tick_usec-static.patch b/queue-6.6/ntp-make-tick_usec-static.patch
new file mode 100644 (file)
index 0000000..6611eec
--- /dev/null
@@ -0,0 +1,68 @@
+From ed880bbf9b143c63503fc3517068434dee9d390f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:38 +0200
+Subject: ntp: Make tick_usec static
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 66606a93849bfe3cbe9f0b801b40f60b87c54e11 ]
+
+There are no users of tick_usec outside of the NTP core code. Therefore
+make tick_usec static.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-2-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/timex.h | 7 -------
+ kernel/time/ntp.c     | 5 ++++-
+ 2 files changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/include/linux/timex.h b/include/linux/timex.h
+index 7f7a12fd8200c..4ee32eff3f221 100644
+--- a/include/linux/timex.h
++++ b/include/linux/timex.h
+@@ -139,13 +139,6 @@ unsigned long random_get_entropy_fallback(void);
+ #define MAXSEC 2048           /* max interval between updates (s) */
+ #define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */
+-/*
+- * kernel variables
+- * Note: maximum error = NTP sync distance = dispersion + delay / 2;
+- * estimated error = NTP dispersion.
+- */
+-extern unsigned long tick_usec;               /* USER_HZ period (usec) */
+-
+ /* Required to safely shift negative values */
+ #define shift_right(x, s) ({  \
+       __typeof__(x) __x = (x);        \
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 0dba1179d81d2..8e68a85996f7d 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -31,7 +31,7 @@
+ /* USER_HZ period (usecs): */
+-unsigned long                 tick_usec = USER_TICK_USEC;
++static unsigned long          tick_usec = USER_TICK_USEC;
+ static u64                    tick_length;
+ static u64                    tick_length_base;
+@@ -44,6 +44,9 @@ static u64                   tick_length_base;
+ /*
+  * phase-lock loop variables
++ *
++ * Note: maximum error = NTP sync distance = dispersion + delay / 2;
++ * estimated error = NTP dispersion.
+  */
+ /*
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-move-tick_length-into-ntp_data.patch b/queue-6.6/ntp-move-tick_length-into-ntp_data.patch
new file mode 100644 (file)
index 0000000..1f0d3ac
--- /dev/null
@@ -0,0 +1,134 @@
+From 57c1e66e29a0a5d9499dfab702f04b00251e7e6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:44 +0200
+Subject: ntp: Move tick_length* into ntp_data
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit ec93ec22aa10fb5311c0f068ee66c5b6d39788fe ]
+
+Continue the conversion from static variables to struct based data.
+
+No functional change.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-8-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 34 ++++++++++++++++++----------------
+ 1 file changed, 18 insertions(+), 16 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 0222f8e460810..6c5f684328c82 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -25,20 +25,21 @@
+ /**
+  * struct ntp_data - Structure holding all NTP related state
+  * @tick_usec:                USER_HZ period in microseconds
++ * @tick_length:      Adjusted tick length
++ * @tick_length_base: Base value for @tick_length
+  *
+  * Protected by the timekeeping locks.
+  */
+ struct ntp_data {
+       unsigned long           tick_usec;
++      u64                     tick_length;
++      u64                     tick_length_base;
+ };
+ static struct ntp_data tk_ntp_data = {
+       .tick_usec              = USER_TICK_USEC,
+ };
+-static u64                    tick_length;
+-static u64                    tick_length_base;
+-
+ #define SECS_PER_DAY          86400
+ #define MAX_TICKADJ           500LL           /* usecs */
+ #define MAX_TICKADJ_SCALED \
+@@ -263,8 +264,8 @@ static void ntp_update_frequency(struct ntp_data *ntpdata)
+        * Don't wait for the next second_overflow, apply the change to the
+        * tick length immediately:
+        */
+-      tick_length             += new_base - tick_length_base;
+-      tick_length_base         = new_base;
++      ntpdata->tick_length            += new_base - ntpdata->tick_length_base;
++      ntpdata->tick_length_base        = new_base;
+ }
+ static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
+@@ -341,8 +342,8 @@ static void __ntp_clear(struct ntp_data *ntpdata)
+       ntp_update_frequency(ntpdata);
+-      tick_length     = tick_length_base;
+-      time_offset     = 0;
++      ntpdata->tick_length    = ntpdata->tick_length_base;
++      time_offset             = 0;
+       ntp_next_leap_sec = TIME64_MAX;
+       /* Clear PPS state variables */
+@@ -360,7 +361,7 @@ void ntp_clear(void)
+ u64 ntp_tick_length(void)
+ {
+-      return tick_length;
++      return tk_ntp_data.tick_length;
+ }
+ /**
+@@ -391,6 +392,7 @@ ktime_t ntp_get_next_leap(void)
+  */
+ int second_overflow(time64_t secs)
+ {
++      struct ntp_data *ntpdata = &tk_ntp_data;
+       s64 delta;
+       int leap = 0;
+       s32 rem;
+@@ -451,11 +453,11 @@ int second_overflow(time64_t secs)
+       }
+       /* Compute the phase adjustment for the next second */
+-      tick_length      = tick_length_base;
++      ntpdata->tick_length     = ntpdata->tick_length_base;
+-      delta            = ntp_offset_chunk(time_offset);
+-      time_offset     -= delta;
+-      tick_length     += delta;
++      delta                    = ntp_offset_chunk(time_offset);
++      time_offset             -= delta;
++      ntpdata->tick_length    += delta;
+       /* Check PPS signal */
+       pps_dec_valid();
+@@ -465,18 +467,18 @@ int second_overflow(time64_t secs)
+       if (time_adjust > MAX_TICKADJ) {
+               time_adjust -= MAX_TICKADJ;
+-              tick_length += MAX_TICKADJ_SCALED;
++              ntpdata->tick_length += MAX_TICKADJ_SCALED;
+               goto out;
+       }
+       if (time_adjust < -MAX_TICKADJ) {
+               time_adjust += MAX_TICKADJ;
+-              tick_length -= MAX_TICKADJ_SCALED;
++              ntpdata->tick_length -= MAX_TICKADJ_SCALED;
+               goto out;
+       }
+-      tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
+-                                                       << NTP_SCALE_SHIFT;
++      ntpdata->tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
++                              << NTP_SCALE_SHIFT;
+       time_adjust = 0;
+ out:
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-move-tick_stat-into-ntp_data.patch b/queue-6.6/ntp-move-tick_stat-into-ntp_data.patch
new file mode 100644 (file)
index 0000000..b09d17e
--- /dev/null
@@ -0,0 +1,539 @@
+From 69572175a7bf6c25a1cb294df994464fe1fd3467 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:45 +0200
+Subject: ntp: Move tick_stat* into ntp_data
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit bee18a2301f97465a464176767f3a3a64f900d93 ]
+
+Continue the conversion from static variables to struct based data.
+
+No functional change.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-9-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 175 ++++++++++++++++++++++------------------------
+ 1 file changed, 85 insertions(+), 90 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 6c5f684328c82..6d87f9889b039 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -27,6 +27,8 @@
+  * @tick_usec:                USER_HZ period in microseconds
+  * @tick_length:      Adjusted tick length
+  * @tick_length_base: Base value for @tick_length
++ * @time_state:               State of the clock synchronization
++ * @time_status:      Clock status bits
+  *
+  * Protected by the timekeeping locks.
+  */
+@@ -34,10 +36,14 @@ struct ntp_data {
+       unsigned long           tick_usec;
+       u64                     tick_length;
+       u64                     tick_length_base;
++      int                     time_state;
++      int                     time_status;
+ };
+ static struct ntp_data tk_ntp_data = {
+       .tick_usec              = USER_TICK_USEC,
++      .time_state             = TIME_OK,
++      .time_status            = STA_UNSYNC,
+ };
+ #define SECS_PER_DAY          86400
+@@ -53,16 +59,6 @@ static struct ntp_data tk_ntp_data = {
+  * estimated error = NTP dispersion.
+  */
+-/*
+- * clock synchronization status
+- *
+- * (TIME_ERROR prevents overwriting the CMOS clock)
+- */
+-static int                    time_state = TIME_OK;
+-
+-/* clock status bits:                                                 */
+-static int                    time_status = STA_UNSYNC;
+-
+ /* time adjustment (nsecs):                                           */
+ static s64                    time_offset;
+@@ -127,9 +123,9 @@ static long pps_errcnt;            /* calibration errors */
+  * PPS kernel consumer compensates the whole phase error immediately.
+  * Otherwise, reduce the offset by a fixed factor times the time constant.
+  */
+-static inline s64 ntp_offset_chunk(s64 offset)
++static inline s64 ntp_offset_chunk(struct ntp_data *ntpdata, s64 offset)
+ {
+-      if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)
++      if (ntpdata->time_status & STA_PPSTIME && ntpdata->time_status & STA_PPSSIGNAL)
+               return offset;
+       else
+               return shift_right(offset, SHIFT_PLL + time_constant);
+@@ -159,13 +155,13 @@ static inline void pps_clear(void)
+  * Decrease pps_valid to indicate that another second has passed since the
+  * last PPS signal. When it reaches 0, indicate that PPS signal is missing.
+  */
+-static inline void pps_dec_valid(void)
++static inline void pps_dec_valid(struct ntp_data *ntpdata)
+ {
+       if (pps_valid > 0)
+               pps_valid--;
+       else {
+-              time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
+-                               STA_PPSWANDER | STA_PPSERROR);
++              ntpdata->time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
++                                        STA_PPSWANDER | STA_PPSERROR);
+               pps_clear();
+       }
+ }
+@@ -198,12 +194,12 @@ static inline bool is_error_status(int status)
+                       && (status & (STA_PPSWANDER|STA_PPSERROR)));
+ }
+-static inline void pps_fill_timex(struct __kernel_timex *txc)
++static inline void pps_fill_timex(struct ntp_data *ntpdata, struct __kernel_timex *txc)
+ {
+       txc->ppsfreq       = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) *
+                                        PPM_SCALE_INV, NTP_SCALE_SHIFT);
+       txc->jitter        = pps_jitter;
+-      if (!(time_status & STA_NANO))
++      if (!(ntpdata->time_status & STA_NANO))
+               txc->jitter = pps_jitter / NSEC_PER_USEC;
+       txc->shift         = pps_shift;
+       txc->stabil        = pps_stabil;
+@@ -215,14 +211,14 @@ static inline void pps_fill_timex(struct __kernel_timex *txc)
+ #else /* !CONFIG_NTP_PPS */
+-static inline s64 ntp_offset_chunk(s64 offset)
++static inline s64 ntp_offset_chunk(struct ntp_data *ntp, s64 offset)
+ {
+       return shift_right(offset, SHIFT_PLL + time_constant);
+ }
+ static inline void pps_reset_freq_interval(void) {}
+ static inline void pps_clear(void) {}
+-static inline void pps_dec_valid(void) {}
++static inline void pps_dec_valid(struct ntp_data *ntpdata) {}
+ static inline void pps_set_freq(s64 freq) {}
+ static inline bool is_error_status(int status)
+@@ -230,7 +226,7 @@ static inline bool is_error_status(int status)
+       return status & (STA_UNSYNC|STA_CLOCKERR);
+ }
+-static inline void pps_fill_timex(struct __kernel_timex *txc)
++static inline void pps_fill_timex(struct ntp_data *ntpdata, struct __kernel_timex *txc)
+ {
+       /* PPS is not implemented, so these are zero */
+       txc->ppsfreq       = 0;
+@@ -268,30 +264,30 @@ static void ntp_update_frequency(struct ntp_data *ntpdata)
+       ntpdata->tick_length_base        = new_base;
+ }
+-static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
++static inline s64 ntp_update_offset_fll(struct ntp_data *ntpdata, s64 offset64, long secs)
+ {
+-      time_status &= ~STA_MODE;
++      ntpdata->time_status &= ~STA_MODE;
+       if (secs < MINSEC)
+               return 0;
+-      if (!(time_status & STA_FLL) && (secs <= MAXSEC))
++      if (!(ntpdata->time_status & STA_FLL) && (secs <= MAXSEC))
+               return 0;
+-      time_status |= STA_MODE;
++      ntpdata->time_status |= STA_MODE;
+       return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
+ }
+-static void ntp_update_offset(long offset)
++static void ntp_update_offset(struct ntp_data *ntpdata, long offset)
+ {
+       s64 freq_adj, offset64;
+       long secs, real_secs;
+-      if (!(time_status & STA_PLL))
++      if (!(ntpdata->time_status & STA_PLL))
+               return;
+-      if (!(time_status & STA_NANO)) {
++      if (!(ntpdata->time_status & STA_NANO)) {
+               /* Make sure the multiplication below won't overflow */
+               offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC);
+               offset *= NSEC_PER_USEC;
+@@ -306,13 +302,13 @@ static void ntp_update_offset(long offset)
+        */
+       real_secs = __ktime_get_real_seconds();
+       secs = (long)(real_secs - time_reftime);
+-      if (unlikely(time_status & STA_FREQHOLD))
++      if (unlikely(ntpdata->time_status & STA_FREQHOLD))
+               secs = 0;
+       time_reftime = real_secs;
+       offset64    = offset;
+-      freq_adj    = ntp_update_offset_fll(offset64, secs);
++      freq_adj    = ntp_update_offset_fll(ntpdata, offset64, secs);
+       /*
+        * Clamp update interval to reduce PLL gain with low
+@@ -335,10 +331,10 @@ static void ntp_update_offset(long offset)
+ static void __ntp_clear(struct ntp_data *ntpdata)
+ {
+       /* Stop active adjtime() */
+-      time_adjust     = 0;
+-      time_status     |= STA_UNSYNC;
+-      time_maxerror   = NTP_PHASE_LIMIT;
+-      time_esterror   = NTP_PHASE_LIMIT;
++      time_adjust             = 0;
++      ntpdata->time_status    |= STA_UNSYNC;
++      time_maxerror           = NTP_PHASE_LIMIT;
++      time_esterror           = NTP_PHASE_LIMIT;
+       ntp_update_frequency(ntpdata);
+@@ -372,9 +368,10 @@ u64 ntp_tick_length(void)
+  */
+ ktime_t ntp_get_next_leap(void)
+ {
++      struct ntp_data *ntpdata = &tk_ntp_data;
+       ktime_t ret;
+-      if ((time_state == TIME_INS) && (time_status & STA_INS))
++      if ((ntpdata->time_state == TIME_INS) && (ntpdata->time_status & STA_INS))
+               return ktime_set(ntp_next_leap_sec, 0);
+       ret = KTIME_MAX;
+       return ret;
+@@ -402,46 +399,46 @@ int second_overflow(time64_t secs)
+        * day, the system clock is set back one second; if in leap-delete
+        * state, the system clock is set ahead one second.
+        */
+-      switch (time_state) {
++      switch (ntpdata->time_state) {
+       case TIME_OK:
+-              if (time_status & STA_INS) {
+-                      time_state = TIME_INS;
++              if (ntpdata->time_status & STA_INS) {
++                      ntpdata->time_state = TIME_INS;
+                       div_s64_rem(secs, SECS_PER_DAY, &rem);
+                       ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
+-              } else if (time_status & STA_DEL) {
+-                      time_state = TIME_DEL;
++              } else if (ntpdata->time_status & STA_DEL) {
++                      ntpdata->time_state = TIME_DEL;
+                       div_s64_rem(secs + 1, SECS_PER_DAY, &rem);
+                       ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
+               }
+               break;
+       case TIME_INS:
+-              if (!(time_status & STA_INS)) {
++              if (!(ntpdata->time_status & STA_INS)) {
+                       ntp_next_leap_sec = TIME64_MAX;
+-                      time_state = TIME_OK;
++                      ntpdata->time_state = TIME_OK;
+               } else if (secs == ntp_next_leap_sec) {
+                       leap = -1;
+-                      time_state = TIME_OOP;
++                      ntpdata->time_state = TIME_OOP;
+                       pr_notice("Clock: inserting leap second 23:59:60 UTC\n");
+               }
+               break;
+       case TIME_DEL:
+-              if (!(time_status & STA_DEL)) {
++              if (!(ntpdata->time_status & STA_DEL)) {
+                       ntp_next_leap_sec = TIME64_MAX;
+-                      time_state = TIME_OK;
++                      ntpdata->time_state = TIME_OK;
+               } else if (secs == ntp_next_leap_sec) {
+                       leap = 1;
+                       ntp_next_leap_sec = TIME64_MAX;
+-                      time_state = TIME_WAIT;
++                      ntpdata->time_state = TIME_WAIT;
+                       pr_notice("Clock: deleting leap second 23:59:59 UTC\n");
+               }
+               break;
+       case TIME_OOP:
+               ntp_next_leap_sec = TIME64_MAX;
+-              time_state = TIME_WAIT;
++              ntpdata->time_state = TIME_WAIT;
+               break;
+       case TIME_WAIT:
+-              if (!(time_status & (STA_INS | STA_DEL)))
+-                      time_state = TIME_OK;
++              if (!(ntpdata->time_status & (STA_INS | STA_DEL)))
++                      ntpdata->time_state = TIME_OK;
+               break;
+       }
+@@ -449,18 +446,18 @@ int second_overflow(time64_t secs)
+       time_maxerror += MAXFREQ / NSEC_PER_USEC;
+       if (time_maxerror > NTP_PHASE_LIMIT) {
+               time_maxerror = NTP_PHASE_LIMIT;
+-              time_status |= STA_UNSYNC;
++              ntpdata->time_status |= STA_UNSYNC;
+       }
+       /* Compute the phase adjustment for the next second */
+       ntpdata->tick_length     = ntpdata->tick_length_base;
+-      delta                    = ntp_offset_chunk(time_offset);
++      delta                    = ntp_offset_chunk(ntpdata, time_offset);
+       time_offset             -= delta;
+       ntpdata->tick_length    += delta;
+       /* Check PPS signal */
+-      pps_dec_valid();
++      pps_dec_valid(ntpdata);
+       if (!time_adjust)
+               goto out;
+@@ -608,7 +605,7 @@ static inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_ns
+  */
+ static inline bool ntp_synced(void)
+ {
+-      return !(time_status & STA_UNSYNC);
++      return !(tk_ntp_data.time_status & STA_UNSYNC);
+ }
+ /*
+@@ -683,11 +680,11 @@ static inline void __init ntp_init_cmos_sync(void) { }
+ /*
+  * Propagate a new txc->status value into the NTP state:
+  */
+-static inline void process_adj_status(const struct __kernel_timex *txc)
++static inline void process_adj_status(struct ntp_data *ntpdata, const struct __kernel_timex *txc)
+ {
+-      if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
+-              time_state = TIME_OK;
+-              time_status = STA_UNSYNC;
++      if ((ntpdata->time_status & STA_PLL) && !(txc->status & STA_PLL)) {
++              ntpdata->time_state = TIME_OK;
++              ntpdata->time_status = STA_UNSYNC;
+               ntp_next_leap_sec = TIME64_MAX;
+               /* Restart PPS frequency calibration */
+               pps_reset_freq_interval();
+@@ -697,26 +694,25 @@ static inline void process_adj_status(const struct __kernel_timex *txc)
+        * If we turn on PLL adjustments then reset the
+        * reference time to current time.
+        */
+-      if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
++      if (!(ntpdata->time_status & STA_PLL) && (txc->status & STA_PLL))
+               time_reftime = __ktime_get_real_seconds();
+-      /* Only set allowed bits */
+-      time_status &= STA_RONLY;
+-      time_status |= txc->status & ~STA_RONLY;
++      /* only set allowed bits */
++      ntpdata->time_status &= STA_RONLY;
++      ntpdata->time_status |= txc->status & ~STA_RONLY;
+ }
+-
+ static inline void process_adjtimex_modes(struct ntp_data *ntpdata, const struct __kernel_timex *txc,
+                                         s32 *time_tai)
+ {
+       if (txc->modes & ADJ_STATUS)
+-              process_adj_status(txc);
++              process_adj_status(ntpdata, txc);
+       if (txc->modes & ADJ_NANO)
+-              time_status |= STA_NANO;
++              ntpdata->time_status |= STA_NANO;
+       if (txc->modes & ADJ_MICRO)
+-              time_status &= ~STA_NANO;
++              ntpdata->time_status &= ~STA_NANO;
+       if (txc->modes & ADJ_FREQUENCY) {
+               time_freq = txc->freq * PPM_SCALE;
+@@ -734,17 +730,16 @@ static inline void process_adjtimex_modes(struct ntp_data *ntpdata, const struct
+       if (txc->modes & ADJ_TIMECONST) {
+               time_constant = clamp(txc->constant, 0, MAXTC);
+-              if (!(time_status & STA_NANO))
++              if (!(ntpdata->time_status & STA_NANO))
+                       time_constant += 4;
+               time_constant = clamp(time_constant, 0, MAXTC);
+       }
+-      if (txc->modes & ADJ_TAI &&
+-                      txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET)
++      if (txc->modes & ADJ_TAI && txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET)
+               *time_tai = txc->constant;
+       if (txc->modes & ADJ_OFFSET)
+-              ntp_update_offset(txc->offset);
++              ntp_update_offset(ntpdata, txc->offset);
+       if (txc->modes & ADJ_TICK)
+               ntpdata->tick_usec = txc->tick;
+@@ -780,7 +775,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+               if (txc->modes) {
+                       audit_ntp_set_old(ad, AUDIT_NTP_OFFSET, time_offset);
+                       audit_ntp_set_old(ad, AUDIT_NTP_FREQ,   time_freq);
+-                      audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status);
++                      audit_ntp_set_old(ad, AUDIT_NTP_STATUS, ntpdata->time_status);
+                       audit_ntp_set_old(ad, AUDIT_NTP_TAI,    *time_tai);
+                       audit_ntp_set_old(ad, AUDIT_NTP_TICK,   ntpdata->tick_usec);
+@@ -788,26 +783,26 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+                       audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset);
+                       audit_ntp_set_new(ad, AUDIT_NTP_FREQ,   time_freq);
+-                      audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status);
++                      audit_ntp_set_new(ad, AUDIT_NTP_STATUS, ntpdata->time_status);
+                       audit_ntp_set_new(ad, AUDIT_NTP_TAI,    *time_tai);
+                       audit_ntp_set_new(ad, AUDIT_NTP_TICK,   ntpdata->tick_usec);
+               }
+               txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+                                 NTP_SCALE_SHIFT);
+-              if (!(time_status & STA_NANO))
++              if (!(ntpdata->time_status & STA_NANO))
+                       txc->offset = (u32)txc->offset / NSEC_PER_USEC;
+       }
+-      result = time_state;
+-      if (is_error_status(time_status))
++      result = ntpdata->time_state;
++      if (is_error_status(ntpdata->time_status))
+               result = TIME_ERROR;
+       txc->freq          = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) *
+                                        PPM_SCALE_INV, NTP_SCALE_SHIFT);
+       txc->maxerror      = time_maxerror;
+       txc->esterror      = time_esterror;
+-      txc->status        = time_status;
++      txc->status        = ntpdata->time_status;
+       txc->constant      = time_constant;
+       txc->precision     = 1;
+       txc->tolerance     = MAXFREQ_SCALED / PPM_SCALE;
+@@ -815,26 +810,26 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+       txc->tai           = *time_tai;
+       /* Fill PPS status fields */
+-      pps_fill_timex(txc);
++      pps_fill_timex(ntpdata, txc);
+       txc->time.tv_sec = ts->tv_sec;
+       txc->time.tv_usec = ts->tv_nsec;
+-      if (!(time_status & STA_NANO))
++      if (!(ntpdata->time_status & STA_NANO))
+               txc->time.tv_usec = ts->tv_nsec / NSEC_PER_USEC;
+       /* Handle leapsec adjustments */
+       if (unlikely(ts->tv_sec >= ntp_next_leap_sec)) {
+-              if ((time_state == TIME_INS) && (time_status & STA_INS)) {
++              if ((ntpdata->time_state == TIME_INS) && (ntpdata->time_status & STA_INS)) {
+                       result = TIME_OOP;
+                       txc->tai++;
+                       txc->time.tv_sec--;
+               }
+-              if ((time_state == TIME_DEL) && (time_status & STA_DEL)) {
++              if ((ntpdata->time_state == TIME_DEL) && (ntpdata->time_status & STA_DEL)) {
+                       result = TIME_WAIT;
+                       txc->tai--;
+                       txc->time.tv_sec++;
+               }
+-              if ((time_state == TIME_OOP) && (ts->tv_sec == ntp_next_leap_sec))
++              if ((ntpdata->time_state == TIME_OOP) && (ts->tv_sec == ntp_next_leap_sec))
+                       result = TIME_WAIT;
+       }
+@@ -939,7 +934,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr
+       /* Check if the frequency interval was too long */
+       if (freq_norm.sec > (2 << pps_shift)) {
+-              time_status |= STA_PPSERROR;
++              ntpdata->time_status |= STA_PPSERROR;
+               pps_errcnt++;
+               pps_dec_freq_interval();
+               printk_deferred(KERN_ERR "hardpps: PPSERROR: interval too long - %lld s\n",
+@@ -958,7 +953,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr
+       pps_freq = ftemp;
+       if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
+               printk_deferred(KERN_WARNING "hardpps: PPSWANDER: change=%ld\n", delta);
+-              time_status |= STA_PPSWANDER;
++              ntpdata->time_status |= STA_PPSWANDER;
+               pps_stbcnt++;
+               pps_dec_freq_interval();
+       } else {
+@@ -977,7 +972,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr
+                              NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
+       /* If enabled, the system clock frequency is updated */
+-      if ((time_status & STA_PPSFREQ) && !(time_status & STA_FREQHOLD)) {
++      if ((ntpdata->time_status & STA_PPSFREQ) && !(ntpdata->time_status & STA_FREQHOLD)) {
+               time_freq = pps_freq;
+               ntp_update_frequency(ntpdata);
+       }
+@@ -986,7 +981,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr
+ }
+ /* Correct REALTIME clock phase error against PPS signal */
+-static void hardpps_update_phase(long error)
++static void hardpps_update_phase(struct ntp_data *ntpdata, long error)
+ {
+       long correction = -error;
+       long jitter;
+@@ -1003,9 +998,9 @@ static void hardpps_update_phase(long error)
+       if (jitter > (pps_jitter << PPS_POPCORN)) {
+               printk_deferred(KERN_WARNING "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
+                               jitter, (pps_jitter << PPS_POPCORN));
+-              time_status |= STA_PPSJITTER;
++              ntpdata->time_status |= STA_PPSJITTER;
+               pps_jitcnt++;
+-      } else if (time_status & STA_PPSTIME) {
++      } else if (ntpdata->time_status & STA_PPSTIME) {
+               /* Correct the time using the phase offset */
+               time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
+               /* Cancel running adjtime() */
+@@ -1035,10 +1030,10 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
+       pts_norm = pps_normalize_ts(*phase_ts);
+       /* Clear the error bits, they will be set again if needed */
+-      time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
++      ntpdata->time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
+-      /* Indicate signal presence */
+-      time_status |= STA_PPSSIGNAL;
++      /* indicate signal presence */
++      ntpdata->time_status |= STA_PPSSIGNAL;
+       pps_valid = PPS_VALID;
+       /*
+@@ -1059,7 +1054,7 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
+        */
+       if ((freq_norm.sec == 0) || (freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
+           (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
+-              time_status |= STA_PPSJITTER;
++              ntpdata->time_status |= STA_PPSJITTER;
+               /* Restart the frequency calibration interval */
+               pps_fbase = *raw_ts;
+               printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n");
+@@ -1074,7 +1069,7 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
+               hardpps_update_freq(ntpdata, freq_norm);
+       }
+-      hardpps_update_phase(pts_norm.nsec);
++      hardpps_update_phase(ntpdata, pts_norm.nsec);
+ }
+ #endif        /* CONFIG_NTP_PPS */
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-read-reference-time-only-once.patch b/queue-6.6/ntp-read-reference-time-only-once.patch
new file mode 100644 (file)
index 0000000..40c2214
--- /dev/null
@@ -0,0 +1,58 @@
+From 8e4573a49f37687504fff95d8733b62bdcf3afb0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:42 +0200
+Subject: ntp: Read reference time only once
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 136bccbc2e78d3cd0bd8831e4c5a4509c0ddd945 ]
+
+The reference time is required twice in ntp_update_offset(). It will not
+change in the meantime as the calling code holds the timekeeper lock. Read
+it only once and store it into a local variable.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-6-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index ef758aafdfd54..477cb08062bc5 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -283,9 +283,8 @@ static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
+ static void ntp_update_offset(long offset)
+ {
+-      s64 freq_adj;
+-      s64 offset64;
+-      long secs;
++      s64 freq_adj, offset64;
++      long secs, real_secs;
+       if (!(time_status & STA_PLL))
+               return;
+@@ -303,11 +302,12 @@ static void ntp_update_offset(long offset)
+        * Select how the frequency is to be controlled
+        * and in which mode (PLL or FLL).
+        */
+-      secs = (long)(__ktime_get_real_seconds() - time_reftime);
++      real_secs = __ktime_get_real_seconds();
++      secs = (long)(real_secs - time_reftime);
+       if (unlikely(time_status & STA_FREQHOLD))
+               secs = 0;
+-      time_reftime = __ktime_get_real_seconds();
++      time_reftime = real_secs;
+       offset64    = offset;
+       freq_adj    = ntp_update_offset_fll(offset64, secs);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-remove-invalid-cast-in-time-offset-math.patch b/queue-6.6/ntp-remove-invalid-cast-in-time-offset-math.patch
new file mode 100644 (file)
index 0000000..b586571
--- /dev/null
@@ -0,0 +1,52 @@
+From 48de567858d5dc7108ccecf728b033cf598093e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Nov 2024 12:16:09 +0000
+Subject: ntp: Remove invalid cast in time offset math
+
+From: Marcelo Dalmas <marcelo.dalmas@ge.com>
+
+[ Upstream commit f5807b0606da7ac7c1b74a386b22134ec7702d05 ]
+
+Due to an unsigned cast, adjtimex() returns the wrong offest when using
+ADJ_MICRO and the offset is negative. In this case a small negative offset
+returns approximately 4.29 seconds (~ 2^32/1000 milliseconds) due to the
+unsigned cast of the negative offset.
+
+This cast was added when the kernel internal struct timex was changed to
+use type long long for the time offset value to address the problem of a
+64bit/32bit division on 32bit systems.
+
+The correct cast would have been (s32), which is correct as time_offset can
+only be in the range of [INT_MIN..INT_MAX] because the shift constant used
+for calculating it is 32. But that's non-obvious.
+
+Remove the cast and use div_s64() to cure the issue.
+
+[ tglx: Fix white space damage, use div_s64() and amend the change log ]
+
+Fixes: ead25417f82e ("timex: use __kernel_timex internally")
+Signed-off-by: Marcelo Dalmas <marcelo.dalmas@ge.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/all/SJ0P101MB03687BF7D5A10FD3C49C51E5F42E2@SJ0P101MB0368.NAMP101.PROD.OUTLOOK.COM
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/ntp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 6d87f9889b039..d1b7a3909de1d 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -791,7 +791,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
+               txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+                                 NTP_SCALE_SHIFT);
+               if (!(ntpdata->time_status & STA_NANO))
+-                      txc->offset = (u32)txc->offset / NSEC_PER_USEC;
++                      txc->offset = div_s64(txc->offset, NSEC_PER_USEC);
+       }
+       result = ntpdata->time_state;
+-- 
+2.43.0
+
diff --git a/queue-6.6/ntp-remove-unused-tick_nsec.patch b/queue-6.6/ntp-remove-unused-tick_nsec.patch
new file mode 100644 (file)
index 0000000..80dab7e
--- /dev/null
@@ -0,0 +1,87 @@
+From 06eb310a927bf861dd76379723b48d54b71b933a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 15:17:37 +0200
+Subject: ntp: Remove unused tick_nsec
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit a849a0273d0f73a252d14d31c5003a8059ea51fc ]
+
+tick_nsec is only updated in the NTP core, but there are no users.
+
+Remove it.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-1-2d52f4e13476@linutronix.de
+Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/timer.h | 2 --
+ include/linux/timex.h        | 1 -
+ kernel/time/ntp.c            | 8 ++------
+ 3 files changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h
+index 7365dd4acffb6..23baf8c9b34ca 100644
+--- a/arch/x86/include/asm/timer.h
++++ b/arch/x86/include/asm/timer.h
+@@ -6,8 +6,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/math64.h>
+-#define TICK_SIZE (tick_nsec / 1000)
+-
+ unsigned long long native_sched_clock(void);
+ extern void recalibrate_cpu_khz(void);
+diff --git a/include/linux/timex.h b/include/linux/timex.h
+index 3871b06bd302c..7f7a12fd8200c 100644
+--- a/include/linux/timex.h
++++ b/include/linux/timex.h
+@@ -145,7 +145,6 @@ unsigned long random_get_entropy_fallback(void);
+  * estimated error = NTP dispersion.
+  */
+ extern unsigned long tick_usec;               /* USER_HZ period (usec) */
+-extern unsigned long tick_nsec;               /* SHIFTED_HZ period (nsec) */
+ /* Required to safely shift negative values */
+ #define shift_right(x, s) ({  \
+diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
+index 8d2dd214ec682..0dba1179d81d2 100644
+--- a/kernel/time/ntp.c
++++ b/kernel/time/ntp.c
+@@ -33,9 +33,6 @@
+ /* USER_HZ period (usecs): */
+ unsigned long                 tick_usec = USER_TICK_USEC;
+-/* SHIFTED_HZ period (nsecs): */
+-unsigned long                 tick_nsec;
+-
+ static u64                    tick_length;
+ static u64                    tick_length_base;
+@@ -253,8 +250,8 @@ static inline int ntp_synced(void)
+  */
+ /*
+- * Update (tick_length, tick_length_base, tick_nsec), based
+- * on (tick_usec, ntp_tick_adj, time_freq):
++ * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and
++ * time_freq:
+  */
+ static void ntp_update_frequency(void)
+ {
+@@ -267,7 +264,6 @@ static void ntp_update_frequency(void)
+       second_length           += ntp_tick_adj;
+       second_length           += time_freq;
+-      tick_nsec                = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+       new_base                 = div_u64(second_length, NTP_INTERVAL_FREQ);
+       /*
+-- 
+2.43.0
+
diff --git a/queue-6.6/platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch b/queue-6.6/platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch
new file mode 100644 (file)
index 0000000..b9f8212
--- /dev/null
@@ -0,0 +1,305 @@
+From da670681422bd6f814f0ce671be9add30979c2dd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 9 Jun 2024 15:48:49 +0100
+Subject: platform/x86: asus-wmi: add support for vivobook fan profiles
+
+From: Mohamed Ghanmi <mohamed.ghanmi@supcom.tn>
+
+[ Upstream commit bcbfcebda2cbc6a10a347d726e4a4f69e43a864e ]
+
+Add support for vivobook fan profiles wmi call on the ASUS VIVOBOOK
+to adjust power limits.
+
+These fan profiles have a different device id than the ROG series
+and different order. This reorders the existing modes.
+
+As part of keeping the patch clean the throttle_thermal_policy_available
+boolean stored in the driver struct is removed and
+throttle_thermal_policy_dev is used in place (as on init it is zeroed).
+
+Co-developed-by: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Mohamed Ghanmi <mohamed.ghanmi@supcom.tn>
+Reviewed-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20240609144849.2532-2-mohamed.ghanmi@supcom.tn
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Stable-dep-of: 25fb5f47f34d ("platform/x86: asus-wmi: Ignore return value when writing thermal policy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/asus-wmi.c            | 120 ++++++++++++---------
+ include/linux/platform_data/x86/asus-wmi.h |   1 +
+ 2 files changed, 71 insertions(+), 50 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 9c6321c2fc3c5..d0ba8bd83fc3d 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -95,6 +95,12 @@ module_param(fnlock_default, bool, 0444);
+ #define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST        1
+ #define ASUS_THROTTLE_THERMAL_POLICY_SILENT   2
++#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO     0
++#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO      1
++#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO   2
++
++#define PLATFORM_PROFILE_MAX 2
++
+ #define USB_INTEL_XUSB2PR             0xD0
+ #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
+@@ -269,8 +275,8 @@ struct asus_wmi {
+       bool kbd_rgb_mode_available;
+       bool kbd_rgb_state_available;
+-      bool throttle_thermal_policy_available;
+       u8 throttle_thermal_policy_mode;
++      u32 throttle_thermal_policy_dev;
+       bool cpu_fan_curve_available;
+       bool gpu_fan_curve_available;
+@@ -2912,7 +2918,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
+       int err, fan_idx;
+       u8 mode = 0;
+-      if (asus->throttle_thermal_policy_available)
++      if (asus->throttle_thermal_policy_dev)
+               mode = asus->throttle_thermal_policy_mode;
+       /* DEVID_<C/G>PU_FAN_CURVE is switched for OVERBOOST vs SILENT */
+       if (mode == 2)
+@@ -3119,7 +3125,7 @@ static ssize_t fan_curve_enable_store(struct device *dev,
+                * For machines with throttle this is the only way to reset fans
+                * to default mode of operation (does not erase curve data).
+                */
+-              if (asus->throttle_thermal_policy_available) {
++              if (asus->throttle_thermal_policy_dev) {
+                       err = throttle_thermal_policy_write(asus);
+                       if (err)
+                               return err;
+@@ -3336,8 +3342,8 @@ static const struct attribute_group asus_fan_curve_attr_group = {
+ __ATTRIBUTE_GROUPS(asus_fan_curve_attr);
+ /*
+- * Must be initialised after throttle_thermal_policy_check_present() as
+- * we check the status of throttle_thermal_policy_available during init.
++ * Must be initialised after throttle_thermal_policy_dev is set as
++ * we check the status of throttle_thermal_policy_dev during init.
+  */
+ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
+ {
+@@ -3378,38 +3384,13 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
+ }
+ /* Throttle thermal policy ****************************************************/
+-
+-static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
+-{
+-      u32 result;
+-      int err;
+-
+-      asus->throttle_thermal_policy_available = false;
+-
+-      err = asus_wmi_get_devstate(asus,
+-                                  ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
+-                                  &result);
+-      if (err) {
+-              if (err == -ENODEV)
+-                      return 0;
+-              return err;
+-      }
+-
+-      if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
+-              asus->throttle_thermal_policy_available = true;
+-
+-      return 0;
+-}
+-
+ static int throttle_thermal_policy_write(struct asus_wmi *asus)
+ {
+-      int err;
+-      u8 value;
++      u8 value = asus->throttle_thermal_policy_mode;
+       u32 retval;
++      int err;
+-      value = asus->throttle_thermal_policy_mode;
+-
+-      err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
++      err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev,
+                                   value, &retval);
+       sysfs_notify(&asus->platform_device->dev.kobj, NULL,
+@@ -3439,7 +3420,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
+ static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
+ {
+-      if (!asus->throttle_thermal_policy_available)
++      if (!asus->throttle_thermal_policy_dev)
+               return 0;
+       asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+@@ -3451,7 +3432,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
+       u8 new_mode = asus->throttle_thermal_policy_mode + 1;
+       int err;
+-      if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
++      if (new_mode > PLATFORM_PROFILE_MAX)
+               new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+       asus->throttle_thermal_policy_mode = new_mode;
+@@ -3490,7 +3471,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
+       if (result < 0)
+               return result;
+-      if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
++      if (new_mode > PLATFORM_PROFILE_MAX)
+               return -EINVAL;
+       asus->throttle_thermal_policy_mode = new_mode;
+@@ -3507,10 +3488,52 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
+       return count;
+ }
+-// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
++/*
++ * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
++ */
+ static DEVICE_ATTR_RW(throttle_thermal_policy);
+ /* Platform profile ***********************************************************/
++static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
++{
++      bool vivo;
++
++      vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
++
++      if (vivo) {
++              switch (mode) {
++              case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
++                      return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO;
++              case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
++                      return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO;
++              case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
++                      return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO;
++              }
++      }
++
++      return mode;
++}
++
++static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode)
++{
++      bool vivo;
++
++      vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
++
++      if (vivo) {
++              switch (mode) {
++              case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO:
++                      return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
++              case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO:
++                      return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
++              case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO:
++                      return ASUS_THROTTLE_THERMAL_POLICY_SILENT;
++              }
++      }
++
++      return mode;
++}
++
+ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
+                                       enum platform_profile_option *profile)
+ {
+@@ -3518,10 +3541,9 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
+       int tp;
+       asus = container_of(pprof, struct asus_wmi, platform_profile_handler);
+-
+       tp = asus->throttle_thermal_policy_mode;
+-      switch (tp) {
++      switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) {
+       case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
+               *profile = PLATFORM_PROFILE_BALANCED;
+               break;
+@@ -3560,7 +3582,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof,
+               return -EOPNOTSUPP;
+       }
+-      asus->throttle_thermal_policy_mode = tp;
++      asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp);
+       return throttle_thermal_policy_write(asus);
+ }
+@@ -3573,7 +3595,7 @@ static int platform_profile_setup(struct asus_wmi *asus)
+        * Not an error if a component platform_profile relies on is unavailable
+        * so early return, skipping the setup of platform_profile.
+        */
+-      if (!asus->throttle_thermal_policy_available)
++      if (!asus->throttle_thermal_policy_dev)
+               return 0;
+       dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n");
+@@ -3870,7 +3892,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+       if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) {
+               if (asus->fan_boost_mode_available)
+                       fan_boost_mode_switch_next(asus);
+-              if (asus->throttle_thermal_policy_available)
++              if (asus->throttle_thermal_policy_dev)
+                       throttle_thermal_policy_switch_next(asus);
+               return;
+@@ -4075,7 +4097,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
+       else if (attr == &dev_attr_fan_boost_mode.attr)
+               ok = asus->fan_boost_mode_available;
+       else if (attr == &dev_attr_throttle_thermal_policy.attr)
+-              ok = asus->throttle_thermal_policy_available;
++              ok = asus->throttle_thermal_policy_dev != 0;
+       else if (attr == &dev_attr_ppt_pl2_sppt.attr)
+               ok = asus->ppt_pl2_sppt_available;
+       else if (attr == &dev_attr_ppt_pl1_spl.attr)
+@@ -4365,16 +4387,15 @@ static int asus_wmi_add(struct platform_device *pdev)
+       asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
+       asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
++      if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
++              asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
++      else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
++              asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
++
+       err = fan_boost_mode_check_present(asus);
+       if (err)
+               goto fail_fan_boost_mode;
+-      err = throttle_thermal_policy_check_present(asus);
+-      if (err)
+-              goto fail_throttle_thermal_policy;
+-      else
+-              throttle_thermal_policy_set_default(asus);
+-
+       err = platform_profile_setup(asus);
+       if (err)
+               goto fail_platform_profile_setup;
+@@ -4461,7 +4482,6 @@ static int asus_wmi_add(struct platform_device *pdev)
+ fail_input:
+       asus_wmi_sysfs_exit(asus->platform_device);
+ fail_sysfs:
+-fail_throttle_thermal_policy:
+ fail_custom_fan_curve:
+ fail_platform_profile_setup:
+       if (asus->platform_profile_support)
+diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
+index 16e99a1c37fc4..8e48bdeb55493 100644
+--- a/include/linux/platform_data/x86/asus-wmi.h
++++ b/include/linux/platform_data/x86/asus-wmi.h
+@@ -60,6 +60,7 @@
+ #define ASUS_WMI_DEVID_LIGHTBAR               0x00050025
+ #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
+ #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
++#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
+ /* Misc */
+ #define ASUS_WMI_DEVID_PANEL_OD               0x00050019
+-- 
+2.43.0
+
diff --git a/queue-6.6/platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch b/queue-6.6/platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch
new file mode 100644 (file)
index 0000000..3a87625
--- /dev/null
@@ -0,0 +1,139 @@
+From 08caab514c7f4b7fb20ffcf587b6497f7ee10b36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 7 Nov 2024 01:38:10 +0100
+Subject: platform/x86: asus-wmi: Fix inconsistent use of thermal policies
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Armin Wolf <W_Armin@gmx.de>
+
+[ Upstream commit 895085ec3f2ed7a26389943729e2904df1f88dc0 ]
+
+When changing the thermal policy using the platform profile API,
+a Vivobook thermal policy is stored in throttle_thermal_policy_mode.
+
+However everywhere else a normal thermal policy is stored inside this
+variable, potentially confusing the platform profile.
+
+Fix this by always storing normal thermal policy values inside
+throttle_thermal_policy_mode and only do the conversion when writing
+the thermal policy to hardware. This also fixes the order in which
+throttle_thermal_policy_switch_next() steps through the thermal modes
+on Vivobook machines.
+
+Tested-by: Casey G Bowman <casey.g.bowman@intel.com>
+Fixes: bcbfcebda2cb ("platform/x86: asus-wmi: add support for vivobook fan profiles")
+Signed-off-by: Armin Wolf <W_Armin@gmx.de>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20241107003811.615574-2-W_Armin@gmx.de
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Stable-dep-of: 25fb5f47f34d ("platform/x86: asus-wmi: Ignore return value when writing thermal policy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/asus-wmi.c | 64 +++++++++++----------------------
+ 1 file changed, 21 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index d0ba8bd83fc3d..e36c299dcfb17 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -3386,10 +3386,28 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
+ /* Throttle thermal policy ****************************************************/
+ static int throttle_thermal_policy_write(struct asus_wmi *asus)
+ {
+-      u8 value = asus->throttle_thermal_policy_mode;
+       u32 retval;
++      u8 value;
+       int err;
++      if (asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO) {
++              switch (asus->throttle_thermal_policy_mode) {
++              case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
++                      value = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO;
++                      break;
++              case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
++                      value = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO;
++                      break;
++              case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
++                      value = ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO;
++                      break;
++              default:
++                      return -EINVAL;
++              }
++      } else {
++              value = asus->throttle_thermal_policy_mode;
++      }
++
+       err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev,
+                                   value, &retval);
+@@ -3494,46 +3512,6 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
+ static DEVICE_ATTR_RW(throttle_thermal_policy);
+ /* Platform profile ***********************************************************/
+-static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
+-{
+-      bool vivo;
+-
+-      vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
+-
+-      if (vivo) {
+-              switch (mode) {
+-              case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
+-                      return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO;
+-              case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
+-                      return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO;
+-              case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
+-                      return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO;
+-              }
+-      }
+-
+-      return mode;
+-}
+-
+-static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode)
+-{
+-      bool vivo;
+-
+-      vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
+-
+-      if (vivo) {
+-              switch (mode) {
+-              case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO:
+-                      return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+-              case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO:
+-                      return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
+-              case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO:
+-                      return ASUS_THROTTLE_THERMAL_POLICY_SILENT;
+-              }
+-      }
+-
+-      return mode;
+-}
+-
+ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
+                                       enum platform_profile_option *profile)
+ {
+@@ -3543,7 +3521,7 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
+       asus = container_of(pprof, struct asus_wmi, platform_profile_handler);
+       tp = asus->throttle_thermal_policy_mode;
+-      switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) {
++      switch (tp) {
+       case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
+               *profile = PLATFORM_PROFILE_BALANCED;
+               break;
+@@ -3582,7 +3560,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof,
+               return -EOPNOTSUPP;
+       }
+-      asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp);
++      asus->throttle_thermal_policy_mode = tp;
+       return throttle_thermal_policy_write(asus);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/platform-x86-asus-wmi-ignore-return-value-when-writi.patch b/queue-6.6/platform-x86-asus-wmi-ignore-return-value-when-writi.patch
new file mode 100644 (file)
index 0000000..de52047
--- /dev/null
@@ -0,0 +1,71 @@
+From a0f791313f048d0d70e37282f90db23b9c523a09 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 Nov 2024 18:19:41 +0100
+Subject: platform/x86: asus-wmi: Ignore return value when writing thermal
+ policy
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Armin Wolf <W_Armin@gmx.de>
+
+[ Upstream commit 25fb5f47f34d90aceda2c47a4230315536e97fa8 ]
+
+On some machines like the ASUS Vivobook S14 writing the thermal policy
+returns the currently writen thermal policy instead of an error code.
+
+Ignore the return code to avoid falsely returning an error when the
+thermal policy was written successfully.
+
+Reported-by: auslands-kv@gmx.de
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219517
+Fixes: 2daa86e78c49 ("platform/x86: asus_wmi: Support throttle thermal policy")
+Signed-off-by: Armin Wolf <W_Armin@gmx.de>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20241124171941.29789-1-W_Armin@gmx.de
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/asus-wmi.c | 11 ++---------
+ 1 file changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index e36c299dcfb17..1bf6178a3a105 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -3386,7 +3386,6 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
+ /* Throttle thermal policy ****************************************************/
+ static int throttle_thermal_policy_write(struct asus_wmi *asus)
+ {
+-      u32 retval;
+       u8 value;
+       int err;
+@@ -3408,8 +3407,8 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
+               value = asus->throttle_thermal_policy_mode;
+       }
+-      err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev,
+-                                  value, &retval);
++      /* Some machines do not return an error code as a result, so we ignore it */
++      err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, value, NULL);
+       sysfs_notify(&asus->platform_device->dev.kobj, NULL,
+                       "throttle_thermal_policy");
+@@ -3419,12 +3418,6 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
+               return err;
+       }
+-      if (retval != 1) {
+-              pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n",
+-                      retval);
+-              return -EIO;
+-      }
+-
+       /* Must set to disabled if mode is toggled */
+       if (asus->cpu_fan_curve_available)
+               asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false;
+-- 
+2.43.0
+
diff --git a/queue-6.6/powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch b/queue-6.6/powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch
new file mode 100644 (file)
index 0000000..3bec5b4
--- /dev/null
@@ -0,0 +1,59 @@
+From 93646e2c580c33a9c5f77c0e5791d22c3b48ed8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Oct 2024 11:41:37 -0700
+Subject: powerpc/vdso: Drop -mstack-protector-guard flags in 32-bit files with
+ clang
+
+From: Nathan Chancellor <nathan@kernel.org>
+
+[ Upstream commit d677ce521334d8f1f327cafc8b1b7854b0833158 ]
+
+Under certain conditions, the 64-bit '-mstack-protector-guard' flags may
+end up in the 32-bit vDSO flags, resulting in build failures due to the
+structure of clang's argument parsing of the stack protector options,
+which validates the arguments of the stack protector guard flags
+unconditionally in the frontend, choking on the 64-bit values when
+targeting 32-bit:
+
+  clang: error: invalid value 'r13' in 'mstack-protector-guard-reg=', expected one of: r2
+  clang: error: invalid value 'r13' in 'mstack-protector-guard-reg=', expected one of: r2
+  make[3]: *** [arch/powerpc/kernel/vdso/Makefile:85: arch/powerpc/kernel/vdso/vgettimeofday-32.o] Error 1
+  make[3]: *** [arch/powerpc/kernel/vdso/Makefile:87: arch/powerpc/kernel/vdso/vgetrandom-32.o] Error 1
+
+Remove these flags by adding them to the CC32FLAGSREMOVE variable, which
+already handles situations similar to this. Additionally, reformat and
+align a comment better for the expanding CONFIG_CC_IS_CLANG block.
+
+Cc: stable@vger.kernel.org # v6.1+
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://patch.msgid.link/20241030-powerpc-vdso-drop-stackp-flags-clang-v1-1-d95e7376d29c@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/kernel/vdso/Makefile | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile
+index 5c7af93018865..d5defff8472da 100644
+--- a/arch/powerpc/kernel/vdso/Makefile
++++ b/arch/powerpc/kernel/vdso/Makefile
+@@ -51,10 +51,14 @@ ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -W
+ CC32FLAGS := -m32
+ CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
+-  # This flag is supported by clang for 64-bit but not 32-bit so it will cause
+-  # an unused command line flag warning for this file.
+ ifdef CONFIG_CC_IS_CLANG
++# This flag is supported by clang for 64-bit but not 32-bit so it will cause
++# an unused command line flag warning for this file.
+ CC32FLAGSREMOVE += -fno-stack-clash-protection
++# -mstack-protector-guard values from the 64-bit build are not valid for the
++# 32-bit one. clang validates the values passed to these arguments during
++# parsing, even when -fno-stack-protector is passed afterwards.
++CC32FLAGSREMOVE += -mstack-protector-guard%
+ endif
+ LD32FLAGS := -Wl,-soname=linux-vdso32.so.1
+ AS32FLAGS := -D__VDSO32__
+-- 
+2.43.0
+
diff --git a/queue-6.6/powerpc-vdso-refactor-cflags-for-cvdso-build.patch b/queue-6.6/powerpc-vdso-refactor-cflags-for-cvdso-build.patch
new file mode 100644 (file)
index 0000000..81c08a2
--- /dev/null
@@ -0,0 +1,92 @@
+From 580f29b4880f364c6559caf60237a743ad33fa19 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 21:17:20 +0200
+Subject: powerpc/vdso: Refactor CFLAGS for CVDSO build
+
+From: Christophe Leroy <christophe.leroy@csgroup.eu>
+
+[ Upstream commit a6b67eb09963af29991625862cbb4f56b85954ed ]
+
+In order to avoid two much duplication when we add new VDSO
+functionnalities in C like getrandom, refactor common CFLAGS.
+
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Acked-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Stable-dep-of: d677ce521334 ("powerpc/vdso: Drop -mstack-protector-guard flags in 32-bit files with clang")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/kernel/vdso/Makefile | 32 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 19 deletions(-)
+
+diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile
+index 0c7d82c270c37..5c7af93018865 100644
+--- a/arch/powerpc/kernel/vdso/Makefile
++++ b/arch/powerpc/kernel/vdso/Makefile
+@@ -10,28 +10,11 @@ obj-vdso64 = sigtramp64-64.o gettimeofday-64.o datapage-64.o cacheflush-64.o not
+ ifneq ($(c-gettimeofday-y),)
+   CFLAGS_vgettimeofday-32.o += -include $(c-gettimeofday-y)
+-  CFLAGS_vgettimeofday-32.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
+-  CFLAGS_vgettimeofday-32.o += $(call cc-option, -fno-stack-protector)
+-  CFLAGS_vgettimeofday-32.o += -DDISABLE_BRANCH_PROFILING
+-  CFLAGS_vgettimeofday-32.o += -ffreestanding -fasynchronous-unwind-tables
+-  CFLAGS_REMOVE_vgettimeofday-32.o = $(CC_FLAGS_FTRACE)
+-  CFLAGS_REMOVE_vgettimeofday-32.o += -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
+-  # This flag is supported by clang for 64-bit but not 32-bit so it will cause
+-  # an unused command line flag warning for this file.
+-  ifdef CONFIG_CC_IS_CLANG
+-  CFLAGS_REMOVE_vgettimeofday-32.o += -fno-stack-clash-protection
+-  endif
+-  CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y)
+-  CFLAGS_vgettimeofday-64.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
+-  CFLAGS_vgettimeofday-64.o += $(call cc-option, -fno-stack-protector)
+-  CFLAGS_vgettimeofday-64.o += -DDISABLE_BRANCH_PROFILING
+-  CFLAGS_vgettimeofday-64.o += -ffreestanding -fasynchronous-unwind-tables
+-  CFLAGS_REMOVE_vgettimeofday-64.o = $(CC_FLAGS_FTRACE)
+ # Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true
+ # by accident when the VDSO was hand-written asm code, but may not be now that the VDSO is
+ # compiler generated. To avoid breaking Go tell GCC not to use r30. Impact on code
+ # generation is minimal, it will just use r29 instead.
+-  CFLAGS_vgettimeofday-64.o += $(call cc-option, -ffixed-r30)
++  CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y) $(call cc-option, -ffixed-r30)
+ endif
+ # Build rules
+@@ -54,6 +37,11 @@ KASAN_SANITIZE := n
+ KCSAN_SANITIZE := n
+ ccflags-y := -fno-common -fno-builtin
++ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN)
++ccflags-y += $(call cc-option, -fno-stack-protector)
++ccflags-y += -DDISABLE_BRANCH_PROFILING
++ccflags-y += -ffreestanding -fasynchronous-unwind-tables
++ccflags-remove-y := $(CC_FLAGS_FTRACE)
+ ldflags-y := -Wl,--hash-style=both -nostdlib -shared -z noexecstack $(CLANG_FLAGS)
+ ldflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld)
+ ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL)
+@@ -62,6 +50,12 @@ ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WAR
+ ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CFLAGS))
+ CC32FLAGS := -m32
++CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
++  # This flag is supported by clang for 64-bit but not 32-bit so it will cause
++  # an unused command line flag warning for this file.
++ifdef CONFIG_CC_IS_CLANG
++CC32FLAGSREMOVE += -fno-stack-clash-protection
++endif
+ LD32FLAGS := -Wl,-soname=linux-vdso32.so.1
+ AS32FLAGS := -D__VDSO32__
+@@ -108,7 +102,7 @@ quiet_cmd_vdso32ld_and_check = VDSO32L $@
+ quiet_cmd_vdso32as = VDSO32A $@
+       cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) $(AS32FLAGS) -c -o $@ $<
+ quiet_cmd_vdso32cc = VDSO32C $@
+-      cmd_vdso32cc = $(VDSOCC) $(c_flags) $(CC32FLAGS) -c -o $@ $<
++      cmd_vdso32cc = $(VDSOCC) $(filter-out $(CC32FLAGSREMOVE), $(c_flags)) $(CC32FLAGS) -c -o $@ $<
+ quiet_cmd_vdso64ld_and_check = VDSO64L $@
+       cmd_vdso64ld_and_check = $(VDSOCC) $(ldflags-y) $(LD64FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check)
+-- 
+2.43.0
+
diff --git a/queue-6.6/ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch b/queue-6.6/ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch
new file mode 100644 (file)
index 0000000..5ebb523
--- /dev/null
@@ -0,0 +1,42 @@
+From b10746fc5c7428f78f631a4c8bdfc34ff4e40eb8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Nov 2024 10:59:54 +0000
+Subject: ptp: Add error handling for adjfine callback in ptp_clock_adjtime
+
+From: Ajay Kaher <ajay.kaher@broadcom.com>
+
+[ Upstream commit 98337d7c87577ded71114f6976edb70a163e27bc ]
+
+ptp_clock_adjtime sets ptp->dialed_frequency even when adjfine
+callback returns an error. This causes subsequent reads to return
+an incorrect value.
+
+Fix this by adding error check before ptp->dialed_frequency is set.
+
+Fixes: 39a8cbd9ca05 ("ptp: remember the adjusted frequency")
+Signed-off-by: Ajay Kaher <ajay.kaher@broadcom.com>
+Acked-by: Richard Cochran <richardcochran@gmail.com>
+Link: https://patch.msgid.link/20241125105954.1509971-1-ajay.kaher@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ptp/ptp_clock.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
+index 9a50bfb56453c..b586da2e30023 100644
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -133,7 +133,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
+               if (ppb > ops->max_adj || ppb < -ops->max_adj)
+                       return -ERANGE;
+               err = ops->adjfine(ops, tx->freq);
+-              ptp->dialed_frequency = tx->freq;
++              if (!err)
++                      ptp->dialed_frequency = tx->freq;
+       } else if (tx->modes & ADJ_OFFSET) {
+               if (ops->adjphase) {
+                       s32 max_phase_adj = ops->getmaxphase(ops);
+-- 
+2.43.0
+
diff --git a/queue-6.6/selftests-hid-fix-typo-and-exit-code.patch b/queue-6.6/selftests-hid-fix-typo-and-exit-code.patch
new file mode 100644 (file)
index 0000000..e6e3c1e
--- /dev/null
@@ -0,0 +1,61 @@
+From b5f3836091cad9646a40956d6904090e7979b797 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 26 Nov 2024 13:58:50 +0000
+Subject: selftests: hid: fix typo and exit code
+
+From: Maximilian Heyne <mheyne@amazon.de>
+
+[ Upstream commit e8f34747bddedaf3895e5d5066e0f71713fff811 ]
+
+The correct exit code to mark a test as skipped is 4.
+
+Fixes: ffb85d5c9e80 ("selftests: hid: import hid-tools hid-core tests")
+Signed-off-by: Maximilian Heyne <mheyne@amazon.de>
+Link: https://patch.msgid.link/20241126135850.76493-1-mheyne@amazon.de
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../testing/selftests/hid/run-hid-tools-tests.sh | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/tools/testing/selftests/hid/run-hid-tools-tests.sh b/tools/testing/selftests/hid/run-hid-tools-tests.sh
+index bdae8464da865..af1682a53c27e 100755
+--- a/tools/testing/selftests/hid/run-hid-tools-tests.sh
++++ b/tools/testing/selftests/hid/run-hid-tools-tests.sh
+@@ -2,24 +2,26 @@
+ # SPDX-License-Identifier: GPL-2.0
+ # Runs tests for the HID subsystem
++KSELFTEST_SKIP_TEST=4
++
+ if ! command -v python3 > /dev/null 2>&1; then
+       echo "hid-tools: [SKIP] python3 not installed"
+-      exit 77
++      exit $KSELFTEST_SKIP_TEST
+ fi
+ if ! python3 -c "import pytest" > /dev/null 2>&1; then
+-      echo "hid: [SKIP/ pytest module not installed"
+-      exit 77
++      echo "hid: [SKIP] pytest module not installed"
++      exit $KSELFTEST_SKIP_TEST
+ fi
+ if ! python3 -c "import pytest_tap" > /dev/null 2>&1; then
+-      echo "hid: [SKIP/ pytest_tap module not installed"
+-      exit 77
++      echo "hid: [SKIP] pytest_tap module not installed"
++      exit $KSELFTEST_SKIP_TEST
+ fi
+ if ! python3 -c "import hidtools" > /dev/null 2>&1; then
+-      echo "hid: [SKIP/ hid-tools module not installed"
+-      exit 77
++      echo "hid: [SKIP] hid-tools module not installed"
++      exit $KSELFTEST_SKIP_TEST
+ fi
+ TARGET=${TARGET:=.}
+-- 
+2.43.0
+
diff --git a/queue-6.6/serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch b/queue-6.6/serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch
new file mode 100644 (file)
index 0000000..5117b0e
--- /dev/null
@@ -0,0 +1,49 @@
+From 0479945f2554582f2418bd6efc486d28d831981a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Nov 2024 14:56:29 +0530
+Subject: serial: amba-pl011: Fix RX stall when DMA is used
+
+From: Kartik Rajput <kkartik@nvidia.com>
+
+[ Upstream commit 2bcacc1c87acf9a8ebc17de18cb2b3cfeca547cf ]
+
+Function pl011_throttle_rx() calls pl011_stop_rx() to disable RX, which
+also disables the RX DMA by clearing the RXDMAE bit of the DMACR
+register. However, to properly unthrottle RX when DMA is used, the
+function pl011_unthrottle_rx() is expected to set the RXDMAE bit of
+the DMACR register, which it currently lacks. This causes RX to stall
+after the throttle API is called.
+
+Set RXDMAE bit in the DMACR register while unthrottling RX if RX DMA is
+used.
+
+Fixes: 211565b10099 ("serial: pl011: UPSTAT_AUTORTS requires .throttle/unthrottle")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Link: https://lore.kernel.org/r/20241113092629.60226-1-kkartik@nvidia.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/amba-pl011.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index 16c7703110694..08f80188f73dd 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1837,6 +1837,11 @@ static void pl011_unthrottle_rx(struct uart_port *port)
+       pl011_write(uap->im, uap, REG_IMSC);
++      if (uap->using_rx_dma) {
++              uap->dmacr |= UART011_RXDMAE;
++              pl011_write(uap->dmacr, uap, REG_DMACR);
++      }
++
+       uart_port_unlock_irqrestore(&uap->port, flags);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/serial-amba-pl011-use-port-lock-wrappers.patch b/queue-6.6/serial-amba-pl011-use-port-lock-wrappers.patch
new file mode 100644 (file)
index 0000000..546f362
--- /dev/null
@@ -0,0 +1,337 @@
+From 329f90d25af129dbcf4fdfbc3c5a7ed85f76764b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Sep 2023 20:43:34 +0206
+Subject: serial: amba-pl011: Use port lock wrappers
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 68ca3e72d7463d79d29b6e4961d6028df2a88e25 ]
+
+When a serial port is used for kernel console output, then all
+modifications to the UART registers which are done from other contexts,
+e.g. getty, termios, are interference points for the kernel console.
+
+So far this has been ignored and the printk output is based on the
+principle of hope. The rework of the console infrastructure which aims to
+support threaded and atomic consoles, requires to mark sections which
+modify the UART registers as unsafe. This allows the atomic write function
+to make informed decisions and eventually to restore operational state. It
+also allows to prevent the regular UART code from modifying UART registers
+while printk output is in progress.
+
+All modifications of UART registers are guarded by the UART port lock,
+which provides an obvious synchronization point with the console
+infrastructure.
+
+To avoid adding this functionality to all UART drivers, wrap the
+spin_[un]lock*() invocations for uart_port::lock into helper functions
+which just contain the spin_[un]lock*() invocations for now. In a
+subsequent step these helpers will gain the console synchronization
+mechanisms.
+
+Converted with coccinelle. No functional change.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: John Ogness <john.ogness@linutronix.de>
+Link: https://lore.kernel.org/r/20230914183831.587273-18-john.ogness@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 2bcacc1c87ac ("serial: amba-pl011: Fix RX stall when DMA is used")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/amba-pl011.c | 72 ++++++++++++++++-----------------
+ 1 file changed, 36 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index 362bbcdece0d7..16c7703110694 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -347,9 +347,9 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
+                               flag = TTY_FRAME;
+               }
+-              spin_unlock(&uap->port.lock);
++              uart_port_unlock(&uap->port);
+               sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
+-              spin_lock(&uap->port.lock);
++              uart_port_lock(&uap->port);
+               if (!sysrq)
+                       uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+@@ -544,7 +544,7 @@ static void pl011_dma_tx_callback(void *data)
+       unsigned long flags;
+       u16 dmacr;
+-      spin_lock_irqsave(&uap->port.lock, flags);
++      uart_port_lock_irqsave(&uap->port, &flags);
+       if (uap->dmatx.queued)
+               dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
+                               dmatx->len, DMA_TO_DEVICE);
+@@ -565,7 +565,7 @@ static void pl011_dma_tx_callback(void *data)
+       if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
+           uart_circ_empty(&uap->port.state->xmit)) {
+               uap->dmatx.queued = false;
+-              spin_unlock_irqrestore(&uap->port.lock, flags);
++              uart_port_unlock_irqrestore(&uap->port, flags);
+               return;
+       }
+@@ -576,7 +576,7 @@ static void pl011_dma_tx_callback(void *data)
+                */
+               pl011_start_tx_pio(uap);
+-      spin_unlock_irqrestore(&uap->port.lock, flags);
++      uart_port_unlock_irqrestore(&uap->port, flags);
+ }
+ /*
+@@ -1004,7 +1004,7 @@ static void pl011_dma_rx_callback(void *data)
+        * routine to flush out the secondary DMA buffer while
+        * we immediately trigger the next DMA job.
+        */
+-      spin_lock_irq(&uap->port.lock);
++      uart_port_lock_irq(&uap->port);
+       /*
+        * Rx data can be taken by the UART interrupts during
+        * the DMA irq handler. So we check the residue here.
+@@ -1020,7 +1020,7 @@ static void pl011_dma_rx_callback(void *data)
+       ret = pl011_dma_rx_trigger_dma(uap);
+       pl011_dma_rx_chars(uap, pending, lastbuf, false);
+-      spin_unlock_irq(&uap->port.lock);
++      uart_port_unlock_irq(&uap->port);
+       /*
+        * Do this check after we picked the DMA chars so we don't
+        * get some IRQ immediately from RX.
+@@ -1086,11 +1086,11 @@ static void pl011_dma_rx_poll(struct timer_list *t)
+       if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
+                       > uap->dmarx.poll_timeout) {
+-              spin_lock_irqsave(&uap->port.lock, flags);
++              uart_port_lock_irqsave(&uap->port, &flags);
+               pl011_dma_rx_stop(uap);
+               uap->im |= UART011_RXIM;
+               pl011_write(uap->im, uap, REG_IMSC);
+-              spin_unlock_irqrestore(&uap->port.lock, flags);
++              uart_port_unlock_irqrestore(&uap->port, flags);
+               uap->dmarx.running = false;
+               dmaengine_terminate_all(rxchan);
+@@ -1186,10 +1186,10 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
+       while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
+               cpu_relax();
+-      spin_lock_irq(&uap->port.lock);
++      uart_port_lock_irq(&uap->port);
+       uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
+       pl011_write(uap->dmacr, uap, REG_DMACR);
+-      spin_unlock_irq(&uap->port.lock);
++      uart_port_unlock_irq(&uap->port);
+       if (uap->using_tx_dma) {
+               /* In theory, this should already be done by pl011_dma_flush_buffer */
+@@ -1400,9 +1400,9 @@ static void pl011_throttle_rx(struct uart_port *port)
+ {
+       unsigned long flags;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       pl011_stop_rx(port);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void pl011_enable_ms(struct uart_port *port)
+@@ -1420,7 +1420,7 @@ __acquires(&uap->port.lock)
+ {
+       pl011_fifo_to_tty(uap);
+-      spin_unlock(&uap->port.lock);
++      uart_port_unlock(&uap->port);
+       tty_flip_buffer_push(&uap->port.state->port);
+       /*
+        * If we were temporarily out of DMA mode for a while,
+@@ -1445,7 +1445,7 @@ __acquires(&uap->port.lock)
+ #endif
+               }
+       }
+-      spin_lock(&uap->port.lock);
++      uart_port_lock(&uap->port);
+ }
+ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
+@@ -1551,7 +1551,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
+       unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+       int handled = 0;
+-      spin_lock_irqsave(&uap->port.lock, flags);
++      uart_port_lock_irqsave(&uap->port, &flags);
+       status = pl011_read(uap, REG_RIS) & uap->im;
+       if (status) {
+               do {
+@@ -1581,7 +1581,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
+               handled = 1;
+       }
+-      spin_unlock_irqrestore(&uap->port.lock, flags);
++      uart_port_unlock_irqrestore(&uap->port, flags);
+       return IRQ_RETVAL(handled);
+ }
+@@ -1653,14 +1653,14 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
+       unsigned long flags;
+       unsigned int lcr_h;
+-      spin_lock_irqsave(&uap->port.lock, flags);
++      uart_port_lock_irqsave(&uap->port, &flags);
+       lcr_h = pl011_read(uap, REG_LCRH_TX);
+       if (break_state == -1)
+               lcr_h |= UART01x_LCRH_BRK;
+       else
+               lcr_h &= ~UART01x_LCRH_BRK;
+       pl011_write(lcr_h, uap, REG_LCRH_TX);
+-      spin_unlock_irqrestore(&uap->port.lock, flags);
++      uart_port_unlock_irqrestore(&uap->port, flags);
+ }
+ #ifdef CONFIG_CONSOLE_POLL
+@@ -1799,7 +1799,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
+       unsigned long flags;
+       unsigned int i;
+-      spin_lock_irqsave(&uap->port.lock, flags);
++      uart_port_lock_irqsave(&uap->port, &flags);
+       /* Clear out any spuriously appearing RX interrupts */
+       pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
+@@ -1821,7 +1821,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
+       if (!pl011_dma_rx_running(uap))
+               uap->im |= UART011_RXIM;
+       pl011_write(uap->im, uap, REG_IMSC);
+-      spin_unlock_irqrestore(&uap->port.lock, flags);
++      uart_port_unlock_irqrestore(&uap->port, flags);
+ }
+ static void pl011_unthrottle_rx(struct uart_port *port)
+@@ -1829,7 +1829,7 @@ static void pl011_unthrottle_rx(struct uart_port *port)
+       struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
+       unsigned long flags;
+-      spin_lock_irqsave(&uap->port.lock, flags);
++      uart_port_lock_irqsave(&uap->port, &flags);
+       uap->im = UART011_RTIM;
+       if (!pl011_dma_rx_running(uap))
+@@ -1837,7 +1837,7 @@ static void pl011_unthrottle_rx(struct uart_port *port)
+       pl011_write(uap->im, uap, REG_IMSC);
+-      spin_unlock_irqrestore(&uap->port.lock, flags);
++      uart_port_unlock_irqrestore(&uap->port, flags);
+ }
+ static int pl011_startup(struct uart_port *port)
+@@ -1857,7 +1857,7 @@ static int pl011_startup(struct uart_port *port)
+       pl011_write(uap->vendor->ifls, uap, REG_IFLS);
+-      spin_lock_irq(&uap->port.lock);
++      uart_port_lock_irq(&uap->port);
+       cr = pl011_read(uap, REG_CR);
+       cr &= UART011_CR_RTS | UART011_CR_DTR;
+@@ -1868,7 +1868,7 @@ static int pl011_startup(struct uart_port *port)
+       pl011_write(cr, uap, REG_CR);
+-      spin_unlock_irq(&uap->port.lock);
++      uart_port_unlock_irq(&uap->port);
+       /*
+        * initialise the old status of the modem signals
+@@ -1929,12 +1929,12 @@ static void pl011_disable_uart(struct uart_amba_port *uap)
+       unsigned int cr;
+       uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
+-      spin_lock_irq(&uap->port.lock);
++      uart_port_lock_irq(&uap->port);
+       cr = pl011_read(uap, REG_CR);
+       cr &= UART011_CR_RTS | UART011_CR_DTR;
+       cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
+       pl011_write(cr, uap, REG_CR);
+-      spin_unlock_irq(&uap->port.lock);
++      uart_port_unlock_irq(&uap->port);
+       /*
+        * disable break condition and fifos
+@@ -1946,14 +1946,14 @@ static void pl011_disable_uart(struct uart_amba_port *uap)
+ static void pl011_disable_interrupts(struct uart_amba_port *uap)
+ {
+-      spin_lock_irq(&uap->port.lock);
++      uart_port_lock_irq(&uap->port);
+       /* mask all interrupts and clear all pending ones */
+       uap->im = 0;
+       pl011_write(uap->im, uap, REG_IMSC);
+       pl011_write(0xffff, uap, REG_ICR);
+-      spin_unlock_irq(&uap->port.lock);
++      uart_port_unlock_irq(&uap->port);
+ }
+ static void pl011_shutdown(struct uart_port *port)
+@@ -2098,7 +2098,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+       bits = tty_get_frame_size(termios->c_cflag);
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       /*
+        * Update the per-port timeout.
+@@ -2172,7 +2172,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+       old_cr |= UART011_CR_RXE;
+       pl011_write(old_cr, uap, REG_CR);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void
+@@ -2190,10 +2190,10 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+       termios->c_cflag &= ~(CMSPAR | CRTSCTS);
+       termios->c_cflag |= CS8 | CLOCAL;
+-      spin_lock_irqsave(&port->lock, flags);
++      uart_port_lock_irqsave(port, &flags);
+       uart_update_timeout(port, CS8, uap->fixed_baud);
+       pl011_setup_status_masks(port, termios);
+-      spin_unlock_irqrestore(&port->lock, flags);
++      uart_port_unlock_irqrestore(port, flags);
+ }
+ static const char *pl011_type(struct uart_port *port)
+@@ -2332,9 +2332,9 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
+       if (uap->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+-              locked = spin_trylock(&uap->port.lock);
++              locked = uart_port_trylock(&uap->port);
+       else
+-              spin_lock(&uap->port.lock);
++              uart_port_lock(&uap->port);
+       /*
+        *      First save the CR then disable the interrupts
+@@ -2360,7 +2360,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
+               pl011_write(old_cr, uap, REG_CR);
+       if (locked)
+-              spin_unlock(&uap->port.lock);
++              uart_port_unlock(&uap->port);
+       local_irq_restore(flags);
+       clk_disable(uap->clk);
+-- 
+2.43.0
+
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5faf393c059f22eee7103bdf99abea2fca381453 100644 (file)
@@ -0,0 +1,120 @@
+itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch
+watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch
+watchdog-apple-actually-flush-writes-after-requestin.patch
+watchdog-mediatek-make-sure-system-reset-gets-assert.patch
+can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch
+can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch
+can-c_can-c_can_handle_bus_err-update-statistics-if-.patch
+can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch
+can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch
+can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch
+can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch
+can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch
+can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch
+can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch
+can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch
+can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch
+ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch
+netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch
+netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch
+selftests-hid-fix-typo-and-exit-code.patch
+net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch
+ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch
+net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch
+net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch
+can-j1939-j1939_session_new-fix-skb-reference-counti.patch
+platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch
+platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch
+platform-x86-asus-wmi-ignore-return-value-when-writi.patch
+net-timestamp-make-sk_tskey-more-predictable-in-erro.patch
+ipv6-introduce-dst_rt6_info-helper.patch
+net-ipv6-release-expired-exception-dst-cached-in-soc.patch
+dccp-fix-memory-leak-in-dccp_feat_change_recv.patch
+tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch
+net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch
+net-smc-introduce-sub-functions-for-smc_clc_send_con.patch
+net-smc-unify-the-structs-of-accept-or-confirm-messa.patch
+net-smc-define-a-reserved-chid-range-for-virtual-ism.patch
+net-smc-compatible-with-128-bits-extended-gid-of-vir.patch
+net-smc-mark-optional-smcd_ops-and-check-for-support.patch
+net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch
+net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch
+net-smc-refactoring-initialization-of-smc-sock.patch
+net-smc-initialize-close_work-early-to-avoid-warning.patch
+net-smc-fix-lgr-and-link-use-after-free-issue.patch
+net-qed-allow-old-cards-not-supporting-num_images-to.patch
+ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch
+ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch
+igb-fix-potential-invalid-memory-access-in-igb_init_.patch
+netfilter-nft_inner-incorrect-percpu-area-handling-u.patch
+net-sched-fix-erspan_opt-settings-in-cls_flower.patch
+netfilter-ipset-hold-module-reference-while-requesti.patch
+netfilter-nft_set_hash-skip-duplicated-elements-pend.patch
+ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch
+mlxsw-add-ipv4_5-flex-key.patch
+mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch
+mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch
+mlxsw-mark-high-entropy-key-blocks.patch
+mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch
+mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch
+geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch
+net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch
+net-avoid-potential-uaf-in-default_operstate.patch
+kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch
+kvm-arm64-don-t-retire-aborted-mmio-instruction.patch
+xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch
+xhci-remove-xhci_trust_tx_length-quirk.patch
+xhci-combine-two-if-statements-for-etron-xhci-host.patch
+xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch
+xhci-fix-control-transfer-error-on-etron-xhci-host.patch
+gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch
+gpio-grgpio-add-null-check-in-grgpio_probe.patch
+serial-amba-pl011-use-port-lock-wrappers.patch
+serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch
+soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch
+soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch
+soc-fsl-cpm1-qmc-re-order-probe-operations.patch
+soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch
+soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch
+soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch
+usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch
+usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch
+usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch
+mmc-mtk-sd-use-devm_mmc_alloc_host.patch
+mmc-mtk-sd-fix-error-handle-of-probe-function.patch
+mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch
+mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch
+zram-split-memory-tracking-and-ac-time-tracking.patch
+zram-do-not-mark-idle-slots-that-cannot-be-idle.patch
+zram-clear-idle-flag-in-mark_idle.patch
+iommu-add-iommu_ops-identity_domain.patch
+iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch
+iommu-clean-up-open-coded-ownership-checks.patch
+iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch
+powerpc-vdso-refactor-cflags-for-cvdso-build.patch
+powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch
+ntp-remove-unused-tick_nsec.patch
+ntp-make-tick_usec-static.patch
+ntp-clean-up-comments.patch
+ntp-cleanup-formatting-of-code.patch
+ntp-convert-functions-with-only-two-states-to-bool.patch
+ntp-read-reference-time-only-once.patch
+ntp-introduce-struct-ntp_data.patch
+ntp-move-tick_length-into-ntp_data.patch
+ntp-move-tick_stat-into-ntp_data.patch
+ntp-remove-invalid-cast-in-time-offset-math.patch
+driver-core-fw_devlink-improve-logs-for-cycle-detect.patch
+driver-core-add-fwlink_flag_ignore-to-completely-ign.patch
+driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch
+f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch
+i3c-master-add-enable-disable-hot-join-in-sys-entry.patch
+i3c-master-svc-add-hot-join-support.patch
+i3c-master-fix-kernel-doc-check-warning.patch
+i3c-master-support-to-adjust-first-broadcast-address.patch
+i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch
+i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch
+i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch
+i3c-master-extend-address-status-bit-to-4-and-add-i3.patch
+i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch
+drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch
+drm-bridge-it6505-fix-inverted-reset-polarity.patch
diff --git a/queue-6.6/soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch b/queue-6.6/soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch
new file mode 100644 (file)
index 0000000..7086f70
--- /dev/null
@@ -0,0 +1,67 @@
+From d918e1a9cde7abbf883db7d18903ba3c00b5f8fe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Sep 2023 11:54:57 +0200
+Subject: soc/fsl: cpm: qmc: Convert to platform remove callback returning void
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 14914a115e807aa2f8025e451133627a64120ac3 ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new() which already returns void. Eventually after all drivers
+are converted, .remove_new() will be renamed to .remove().
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Acked-by: Herve Codina <herve.codina@bootlin.com>
+Link: https://lore.kernel.org/r/20230925095532.1984344-7-u.kleine-koenig@pengutronix.de
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/fsl/qe/qmc.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
+index 8dc73cc1a83b1..2312152a44b3e 100644
+--- a/drivers/soc/fsl/qe/qmc.c
++++ b/drivers/soc/fsl/qe/qmc.c
+@@ -1414,7 +1414,7 @@ static int qmc_probe(struct platform_device *pdev)
+       return ret;
+ }
+-static int qmc_remove(struct platform_device *pdev)
++static void qmc_remove(struct platform_device *pdev)
+ {
+       struct qmc *qmc = platform_get_drvdata(pdev);
+@@ -1426,8 +1426,6 @@ static int qmc_remove(struct platform_device *pdev)
+       /* Disconnect the serial from TSA */
+       tsa_serial_disconnect(qmc->tsa_serial);
+-
+-      return 0;
+ }
+ static const struct of_device_id qmc_id_table[] = {
+@@ -1442,7 +1440,7 @@ static struct platform_driver qmc_driver = {
+               .of_match_table = of_match_ptr(qmc_id_table),
+       },
+       .probe = qmc_probe,
+-      .remove = qmc_remove,
++      .remove_new = qmc_remove,
+ };
+ module_platform_driver(qmc_driver);
+-- 
+2.43.0
+
diff --git a/queue-6.6/soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch b/queue-6.6/soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch
new file mode 100644 (file)
index 0000000..d7e1f3d
--- /dev/null
@@ -0,0 +1,84 @@
+From 0df2e58d2e560b5c9999925049895b663713d9ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 09:11:12 +0200
+Subject: soc: fsl: cpm1: qmc: Fix blank line and spaces
+
+From: Herve Codina <herve.codina@bootlin.com>
+
+[ Upstream commit f06ab938bcddcb3c3a0b458b03a827c701919c9e ]
+
+checkpatch.pl raises the following issues
+  CHECK: Please don't use multiple blank lines
+  CHECK: Alignment should match open parenthesis
+
+Fix them.
+
+Signed-off-by: Herve Codina <herve.codina@bootlin.com>
+Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Link: https://lore.kernel.org/r/20240808071132.149251-20-herve.codina@bootlin.com
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/fsl/qe/qmc.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
+index 2312152a44b3e..f22d1d85d1021 100644
+--- a/drivers/soc/fsl/qe/qmc.c
++++ b/drivers/soc/fsl/qe/qmc.c
+@@ -253,7 +253,6 @@ static inline void qmc_setbits32(void __iomem *addr, u32 set)
+       qmc_write32(addr, qmc_read32(addr) | set);
+ }
+-
+ int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
+ {
+       struct tsa_serial_info tsa_info;
+@@ -1093,7 +1092,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
+               qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+               qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
+               qmc_write16(chan->s_param + QMC_SPE_CHAMR,
+-                      QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
++                          QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
+       }
+       /* Do not enable interrupts now. They will be enabled later */
+@@ -1286,7 +1285,6 @@ static int qmc_probe(struct platform_device *pdev)
+       if (IS_ERR(qmc->scc_regs))
+               return PTR_ERR(qmc->scc_regs);
+-
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
+       if (!res)
+               return -EINVAL;
+@@ -1332,7 +1330,7 @@ static int qmc_probe(struct platform_device *pdev)
+        */
+       qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
+       qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
+-              &qmc->bd_dma_addr, GFP_KERNEL);
++                                          &qmc->bd_dma_addr, GFP_KERNEL);
+       if (!qmc->bd_table) {
+               dev_err(qmc->dev, "Failed to allocate bd table\n");
+               ret = -ENOMEM;
+@@ -1345,7 +1343,7 @@ static int qmc_probe(struct platform_device *pdev)
+       /* Allocate the interrupt table */
+       qmc->int_size = QMC_NB_INTS * sizeof(u16);
+       qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
+-              &qmc->int_dma_addr, GFP_KERNEL);
++                                           &qmc->int_dma_addr, GFP_KERNEL);
+       if (!qmc->int_table) {
+               dev_err(qmc->dev, "Failed to allocate interrupt table\n");
+               ret = -ENOMEM;
+@@ -1393,7 +1391,7 @@ static int qmc_probe(struct platform_device *pdev)
+       /* Enable interrupts */
+       qmc_write16(qmc->scc_regs + SCC_SCCM,
+-              SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
++                  SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
+       ret = qmc_finalize_chans(qmc);
+       if (ret < 0)
+-- 
+2.43.0
+
diff --git a/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch b/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch
new file mode 100644 (file)
index 0000000..8ea5fbe
--- /dev/null
@@ -0,0 +1,141 @@
+From ba2f18acd4f04784551e645d8809c27f0f0c0342 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 09:11:20 +0200
+Subject: soc: fsl: cpm1: qmc: Introduce qmc_{init,exit}_xcc() and their CPM1
+ version
+
+From: Herve Codina <herve.codina@bootlin.com>
+
+[ Upstream commit de5fdb7d14b34f7fea930f2d72cf0241ec679e72 ]
+
+Current code handles the CPM1 version of QMC and initialize the QMC used
+SCC. The QUICC Engine (QE) version uses an UCC (Unified Communication
+Controllers) instead of the SCC (Serial Communication Controllers) used
+in the CPM1 version. These controllers serve the same purpose and are
+used in the same way but their inializations are slightly different.
+
+In order to prepare the support for QE version of QMC, introduce
+qmc_init_xcc() to initialize theses controllers (UCC in QE and SCC in
+CPM1) and isolate the CPM1 specific SCC initialization in a specific
+function.
+
+Also introduce qmc_exit_xcc() for consistency to revert operations done
+in qmc_init_xcc().
+
+Signed-off-by: Herve Codina <herve.codina@bootlin.com>
+Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Link: https://lore.kernel.org/r/20240808071132.149251-28-herve.codina@bootlin.com
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/fsl/qe/qmc.c | 66 +++++++++++++++++++++++++++-------------
+ 1 file changed, 45 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
+index f2bda8658e034..9fa75effcfc06 100644
+--- a/drivers/soc/fsl/qe/qmc.c
++++ b/drivers/soc/fsl/qe/qmc.c
+@@ -1293,6 +1293,41 @@ static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev)
+       return qmc_cpm1_init_resources(qmc, pdev);
+ }
++static int qmc_cpm1_init_scc(struct qmc *qmc)
++{
++      u32 val;
++      int ret;
++
++      /* Connect the serial (SCC) to TSA */
++      ret = tsa_serial_connect(qmc->tsa_serial);
++      if (ret)
++              return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
++
++      /* Init GMSR_H and GMSR_L registers */
++      val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP;
++      qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
++
++      /* enable QMC mode */
++      qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
++
++      /* Disable and clear interrupts */
++      qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
++      qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
++
++      return 0;
++}
++
++static int qmc_init_xcc(struct qmc *qmc)
++{
++      return qmc_cpm1_init_scc(qmc);
++}
++
++static void qmc_exit_xcc(struct qmc *qmc)
++{
++      /* Disconnect the serial from TSA */
++      tsa_serial_disconnect(qmc->tsa_serial);
++}
++
+ static int qmc_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+@@ -1378,29 +1413,18 @@ static int qmc_probe(struct platform_device *pdev)
+       if (ret)
+               return ret;
+-      /* Connect the serial (SCC) to TSA */
+-      ret = tsa_serial_connect(qmc->tsa_serial);
+-      if (ret) {
+-              dev_err(qmc->dev, "Failed to connect TSA serial\n");
++      /* Init SCC */
++      ret = qmc_init_xcc(qmc);
++      if (ret)
+               return ret;
+-      }
+-      /* Init GMSR_H and GMSR_L registers */
+-      qmc_write32(qmc->scc_regs + SCC_GSMRH,
+-                  SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
+-
+-      /* enable QMC mode */
+-      qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
+-
+-      /* Disable and clear interrupts,  set the irq handler */
+-      qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+-      qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
++      /* Set the irq handler */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+-              goto err_tsa_serial_disconnect;
++              goto err_exit_xcc;
+       ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
+       if (ret < 0)
+-              goto err_tsa_serial_disconnect;
++              goto err_exit_xcc;
+       /* Enable interrupts */
+       qmc_write16(qmc->scc_regs + SCC_SCCM,
+@@ -1420,8 +1444,8 @@ static int qmc_probe(struct platform_device *pdev)
+ err_disable_intr:
+       qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+-err_tsa_serial_disconnect:
+-      tsa_serial_disconnect(qmc->tsa_serial);
++err_exit_xcc:
++      qmc_exit_xcc(qmc);
+       return ret;
+ }
+@@ -1435,8 +1459,8 @@ static void qmc_remove(struct platform_device *pdev)
+       /* Disable interrupts */
+       qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+-      /* Disconnect the serial from TSA */
+-      tsa_serial_disconnect(qmc->tsa_serial);
++      /* Exit SCC */
++      qmc_exit_xcc(qmc);
+ }
+ static const struct of_device_id qmc_id_table[] = {
+-- 
+2.43.0
+
diff --git a/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch b/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch
new file mode 100644 (file)
index 0000000..a2c1804
--- /dev/null
@@ -0,0 +1,102 @@
+From 91a5255d35bb3183a4467d42bece0c02ee1f9485 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 09:11:19 +0200
+Subject: soc: fsl: cpm1: qmc: Introduce qmc_init_resource() and its CPM1
+ version
+
+From: Herve Codina <herve.codina@bootlin.com>
+
+[ Upstream commit 727b3ab490a5f5e74fb3f246c9fdfb339d309950 ]
+
+Current code handles the CPM1 version of QMC. Resources initialisations
+(i.e. retrieving base addresses and offsets of different parts) will
+be slightly different in the QUICC Engine (QE) version. Indeed, in QE
+version, some resources need to be allocated and are no more "staticaly"
+defined.
+
+In order to prepare the support for QE version, introduce
+qmc_init_resource() to initialize those resources and isolate the CPM1
+specific operations in a specific function.
+
+Signed-off-by: Herve Codina <herve.codina@bootlin.com>
+Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Link: https://lore.kernel.org/r/20240808071132.149251-27-herve.codina@bootlin.com
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/fsl/qe/qmc.c | 47 ++++++++++++++++++++++++++--------------
+ 1 file changed, 31 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
+index a5c9cbb99600e..f2bda8658e034 100644
+--- a/drivers/soc/fsl/qe/qmc.c
++++ b/drivers/soc/fsl/qe/qmc.c
+@@ -1265,11 +1265,38 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv)
+       return IRQ_HANDLED;
+ }
++static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev)
++{
++      struct resource *res;
++
++      qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
++      if (IS_ERR(qmc->scc_regs))
++              return PTR_ERR(qmc->scc_regs);
++
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
++      if (!res)
++              return -EINVAL;
++      qmc->scc_pram_offset = res->start - get_immrbase();
++      qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
++      if (IS_ERR(qmc->scc_pram))
++              return PTR_ERR(qmc->scc_pram);
++
++      qmc->dpram  = devm_platform_ioremap_resource_byname(pdev, "dpram");
++      if (IS_ERR(qmc->dpram))
++              return PTR_ERR(qmc->dpram);
++
++      return 0;
++}
++
++static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev)
++{
++      return qmc_cpm1_init_resources(qmc, pdev);
++}
++
+ static int qmc_probe(struct platform_device *pdev)
+ {
+       struct device_node *np = pdev->dev.of_node;
+       unsigned int nb_chans;
+-      struct resource *res;
+       struct qmc *qmc;
+       int irq;
+       int ret;
+@@ -1287,21 +1314,9 @@ static int qmc_probe(struct platform_device *pdev)
+                                    "Failed to get TSA serial\n");
+       }
+-      qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
+-      if (IS_ERR(qmc->scc_regs))
+-              return PTR_ERR(qmc->scc_regs);
+-
+-      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
+-      if (!res)
+-              return -EINVAL;
+-      qmc->scc_pram_offset = res->start - get_immrbase();
+-      qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
+-      if (IS_ERR(qmc->scc_pram))
+-              return PTR_ERR(qmc->scc_pram);
+-
+-      qmc->dpram  = devm_platform_ioremap_resource_byname(pdev, "dpram");
+-      if (IS_ERR(qmc->dpram))
+-              return PTR_ERR(qmc->dpram);
++      ret = qmc_init_resources(qmc, pdev);
++      if (ret)
++              return ret;
+       /* Parse channels informationss */
+       ret = qmc_of_parse_chans(qmc, np);
+-- 
+2.43.0
+
diff --git a/queue-6.6/soc-fsl-cpm1-qmc-re-order-probe-operations.patch b/queue-6.6/soc-fsl-cpm1-qmc-re-order-probe-operations.patch
new file mode 100644 (file)
index 0000000..1ba792f
--- /dev/null
@@ -0,0 +1,143 @@
+From e9e959b27f87d7d92548a561e93742159d86bab8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 09:11:18 +0200
+Subject: soc: fsl: cpm1: qmc: Re-order probe() operations
+
+From: Herve Codina <herve.codina@bootlin.com>
+
+[ Upstream commit a13bf605342ea9df492b8159cadaa41862b53e15 ]
+
+Current code handles CPM1 version of QMC. In the QUICC Engine (QE)
+version, some operations done at probe() need to be done in a different
+order.
+
+In order to prepare the support for the QE version, changed the sequence
+of operation done at probe():
+- Retrieve the tsa_serial earlier, before initializing resources.
+- Group SCC initialisation and do this initialization when it is really
+  needed in the probe() sequence.
+
+Having the QE compatible sequence in the CPM1 version does not lead to
+any issue and works correctly without any regressions.
+
+Signed-off-by: Herve Codina <herve.codina@bootlin.com>
+Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Link: https://lore.kernel.org/r/20240808071132.149251-26-herve.codina@bootlin.com
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/fsl/qe/qmc.c | 54 +++++++++++++++++++---------------------
+ 1 file changed, 26 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
+index f22d1d85d1021..a5c9cbb99600e 100644
+--- a/drivers/soc/fsl/qe/qmc.c
++++ b/drivers/soc/fsl/qe/qmc.c
+@@ -1281,6 +1281,12 @@ static int qmc_probe(struct platform_device *pdev)
+       qmc->dev = &pdev->dev;
+       INIT_LIST_HEAD(&qmc->chan_head);
++      qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial");
++      if (IS_ERR(qmc->tsa_serial)) {
++              return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial),
++                                   "Failed to get TSA serial\n");
++      }
++
+       qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
+       if (IS_ERR(qmc->scc_regs))
+               return PTR_ERR(qmc->scc_regs);
+@@ -1297,33 +1303,13 @@ static int qmc_probe(struct platform_device *pdev)
+       if (IS_ERR(qmc->dpram))
+               return PTR_ERR(qmc->dpram);
+-      qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial");
+-      if (IS_ERR(qmc->tsa_serial)) {
+-              return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial),
+-                                   "Failed to get TSA serial\n");
+-      }
+-
+-      /* Connect the serial (SCC) to TSA */
+-      ret = tsa_serial_connect(qmc->tsa_serial);
+-      if (ret) {
+-              dev_err(qmc->dev, "Failed to connect TSA serial\n");
+-              return ret;
+-      }
+-
+       /* Parse channels informationss */
+       ret = qmc_of_parse_chans(qmc, np);
+       if (ret)
+-              goto err_tsa_serial_disconnect;
++              return ret;
+       nb_chans = qmc_nb_chans(qmc);
+-      /* Init GMSR_H and GMSR_L registers */
+-      qmc_write32(qmc->scc_regs + SCC_GSMRH,
+-                  SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
+-
+-      /* enable QMC mode */
+-      qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
+-
+       /*
+        * Allocate the buffer descriptor table
+        * 8 rx and 8 tx descriptors per channel
+@@ -1333,8 +1319,7 @@ static int qmc_probe(struct platform_device *pdev)
+                                           &qmc->bd_dma_addr, GFP_KERNEL);
+       if (!qmc->bd_table) {
+               dev_err(qmc->dev, "Failed to allocate bd table\n");
+-              ret = -ENOMEM;
+-              goto err_tsa_serial_disconnect;
++              return -ENOMEM;
+       }
+       memset(qmc->bd_table, 0, qmc->bd_size);
+@@ -1346,8 +1331,7 @@ static int qmc_probe(struct platform_device *pdev)
+                                            &qmc->int_dma_addr, GFP_KERNEL);
+       if (!qmc->int_table) {
+               dev_err(qmc->dev, "Failed to allocate interrupt table\n");
+-              ret = -ENOMEM;
+-              goto err_tsa_serial_disconnect;
++              return -ENOMEM;
+       }
+       memset(qmc->int_table, 0, qmc->int_size);
+@@ -1366,18 +1350,32 @@ static int qmc_probe(struct platform_device *pdev)
+       ret = qmc_setup_tsa(qmc);
+       if (ret)
+-              goto err_tsa_serial_disconnect;
++              return ret;
+       qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
+       ret = qmc_setup_chans(qmc);
+       if (ret)
+-              goto err_tsa_serial_disconnect;
++              return ret;
+       /* Init interrupts table */
+       ret = qmc_setup_ints(qmc);
+       if (ret)
+-              goto err_tsa_serial_disconnect;
++              return ret;
++
++      /* Connect the serial (SCC) to TSA */
++      ret = tsa_serial_connect(qmc->tsa_serial);
++      if (ret) {
++              dev_err(qmc->dev, "Failed to connect TSA serial\n");
++              return ret;
++      }
++
++      /* Init GMSR_H and GMSR_L registers */
++      qmc_write32(qmc->scc_regs + SCC_GSMRH,
++                  SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
++
++      /* enable QMC mode */
++      qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
+       /* Disable and clear interrupts,  set the irq handler */
+       qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+-- 
+2.43.0
+
diff --git a/queue-6.6/soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch b/queue-6.6/soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch
new file mode 100644 (file)
index 0000000..63e2bc8
--- /dev/null
@@ -0,0 +1,51 @@
+From 36ba7e5a0bbdd15fe5778e1b1b4ddd555930e0f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2024 15:56:23 +0100
+Subject: soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq()
+ failure
+
+From: Herve Codina <herve.codina@bootlin.com>
+
+[ Upstream commit cb3daa51db819a172e9524e96e2ed96b4237e51a ]
+
+A kernel test robot detected a missing error code:
+   qmc.c:1942 qmc_probe() warn: missing error code 'ret'
+
+Indeed, the error returned by platform_get_irq() is checked and the
+operation is aborted in case of failure but the ret error code is
+not set in that case.
+
+Set the ret error code.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/r/202411051350.KNy6ZIWA-lkp@intel.com/
+Fixes: 3178d58e0b97 ("soc: fsl: cpm1: Add support for QMC")
+Cc: stable@vger.kernel.org
+Signed-off-by: Herve Codina <herve.codina@bootlin.com>
+Link: https://lore.kernel.org/r/20241105145623.401528-1-herve.codina@bootlin.com
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/fsl/qe/qmc.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
+index 9fa75effcfc06..f1720c7cbe063 100644
+--- a/drivers/soc/fsl/qe/qmc.c
++++ b/drivers/soc/fsl/qe/qmc.c
+@@ -1420,8 +1420,10 @@ static int qmc_probe(struct platform_device *pdev)
+       /* Set the irq handler */
+       irq = platform_get_irq(pdev, 0);
+-      if (irq < 0)
++      if (irq < 0) {
++              ret = irq;
+               goto err_exit_xcc;
++      }
+       ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
+       if (ret < 0)
+               goto err_exit_xcc;
+-- 
+2.43.0
+
diff --git a/queue-6.6/tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch b/queue-6.6/tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch
new file mode 100644 (file)
index 0000000..1541445
--- /dev/null
@@ -0,0 +1,107 @@
+From 8a129f26bc6fb44f8555a1d094e5c1a1071363da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Nov 2024 14:05:12 +0900
+Subject: tipc: Fix use-after-free of kernel socket in cleanup_bearer().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit 6a2fa13312e51a621f652d522d7e2df7066330b6 ]
+
+syzkaller reported a use-after-free of UDP kernel socket
+in cleanup_bearer() without repro. [0][1]
+
+When bearer_disable() calls tipc_udp_disable(), cleanup
+of the UDP kernel socket is deferred by work calling
+cleanup_bearer().
+
+tipc_net_stop() waits for such works to finish by checking
+tipc_net(net)->wq_count.  However, the work decrements the
+count too early before releasing the kernel socket,
+unblocking cleanup_net() and resulting in use-after-free.
+
+Let's move the decrement after releasing the socket in
+cleanup_bearer().
+
+[0]:
+ref_tracker: net notrefcnt@000000009b3d1faf has 1/1 users at
+     sk_alloc+0x438/0x608
+     inet_create+0x4c8/0xcb0
+     __sock_create+0x350/0x6b8
+     sock_create_kern+0x58/0x78
+     udp_sock_create4+0x68/0x398
+     udp_sock_create+0x88/0xc8
+     tipc_udp_enable+0x5e8/0x848
+     __tipc_nl_bearer_enable+0x84c/0xed8
+     tipc_nl_bearer_enable+0x38/0x60
+     genl_family_rcv_msg_doit+0x170/0x248
+     genl_rcv_msg+0x400/0x5b0
+     netlink_rcv_skb+0x1dc/0x398
+     genl_rcv+0x44/0x68
+     netlink_unicast+0x678/0x8b0
+     netlink_sendmsg+0x5e4/0x898
+     ____sys_sendmsg+0x500/0x830
+
+[1]:
+BUG: KMSAN: use-after-free in udp_hashslot include/net/udp.h:85 [inline]
+BUG: KMSAN: use-after-free in udp_lib_unhash+0x3b8/0x930 net/ipv4/udp.c:1979
+ udp_hashslot include/net/udp.h:85 [inline]
+ udp_lib_unhash+0x3b8/0x930 net/ipv4/udp.c:1979
+ sk_common_release+0xaf/0x3f0 net/core/sock.c:3820
+ inet_release+0x1e0/0x260 net/ipv4/af_inet.c:437
+ inet6_release+0x6f/0xd0 net/ipv6/af_inet6.c:489
+ __sock_release net/socket.c:658 [inline]
+ sock_release+0xa0/0x210 net/socket.c:686
+ cleanup_bearer+0x42d/0x4c0 net/tipc/udp_media.c:819
+ process_one_work kernel/workqueue.c:3229 [inline]
+ process_scheduled_works+0xcaf/0x1c90 kernel/workqueue.c:3310
+ worker_thread+0xf6c/0x1510 kernel/workqueue.c:3391
+ kthread+0x531/0x6b0 kernel/kthread.c:389
+ ret_from_fork+0x60/0x80 arch/x86/kernel/process.c:147
+ ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:244
+
+Uninit was created at:
+ slab_free_hook mm/slub.c:2269 [inline]
+ slab_free mm/slub.c:4580 [inline]
+ kmem_cache_free+0x207/0xc40 mm/slub.c:4682
+ net_free net/core/net_namespace.c:454 [inline]
+ cleanup_net+0x16f2/0x19d0 net/core/net_namespace.c:647
+ process_one_work kernel/workqueue.c:3229 [inline]
+ process_scheduled_works+0xcaf/0x1c90 kernel/workqueue.c:3310
+ worker_thread+0xf6c/0x1510 kernel/workqueue.c:3391
+ kthread+0x531/0x6b0 kernel/kthread.c:389
+ ret_from_fork+0x60/0x80 arch/x86/kernel/process.c:147
+ ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:244
+
+CPU: 0 UID: 0 PID: 54 Comm: kworker/0:2 Not tainted 6.12.0-rc1-00131-gf66ebf37d69c #7 91723d6f74857f70725e1583cba3cf4adc716cfa
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+Workqueue: events cleanup_bearer
+
+Fixes: 26abe14379f8 ("net: Modify sk_alloc to not reference count the netns of kernel sockets.")
+Reported-by: syzkaller <syzkaller@googlegroups.com>
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20241127050512.28438-1-kuniyu@amazon.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/udp_media.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
+index cdc8378261ec3..70a39e29a6352 100644
+--- a/net/tipc/udp_media.c
++++ b/net/tipc/udp_media.c
+@@ -814,10 +814,10 @@ static void cleanup_bearer(struct work_struct *work)
+               kfree_rcu(rcast, rcu);
+       }
+-      atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count);
+       dst_cache_destroy(&ub->rcast.dst_cache);
+       udp_tunnel_sock_release(ub->ubsock);
+       synchronize_net();
++      atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count);
+       kfree(ub);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch b/queue-6.6/usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch
new file mode 100644 (file)
index 0000000..ae1b03a
--- /dev/null
@@ -0,0 +1,41 @@
+From b74dd461bfdb305ec3643cf668669c7ea887cbf9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Nov 2024 01:02:06 +0000
+Subject: usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+[ Upstream commit 5d2fb074dea289c41f5aaf2c3f68286bee370634 ]
+
+The driver cannot issue the End Transfer command to the SETUP transfer.
+Don't clear DWC3_EP_TRANSFER_STARTED flag to make sure that the driver
+won't send Start Transfer command again, which can cause no-resource
+error. For example this can occur if the host issues a reset to the
+device.
+
+Cc: stable@vger.kernel.org
+Fixes: 76cb323f80ac ("usb: dwc3: ep0: clear all EP0 flags")
+Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Link: https://lore.kernel.org/r/d3d618185fd614bb7426352a9fc1199641d3b5f5.1731545781.git.Thinh.Nguyen@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/dwc3/ep0.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
+index 371662a552538..69d98f1938edd 100644
+--- a/drivers/usb/dwc3/ep0.c
++++ b/drivers/usb/dwc3/ep0.c
+@@ -231,7 +231,7 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+       /* stall is always issued on EP0 */
+       dep = dwc->eps[0];
+       __dwc3_gadget_ep_set_halt(dep, 1, false);
+-      dep->flags &= DWC3_EP_RESOURCE_ALLOCATED;
++      dep->flags &= DWC3_EP_RESOURCE_ALLOCATED | DWC3_EP_TRANSFER_STARTED;
+       dep->flags |= DWC3_EP_ENABLED;
+       dwc->delayed_status = false;
+-- 
+2.43.0
+
diff --git a/queue-6.6/usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch b/queue-6.6/usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch
new file mode 100644 (file)
index 0000000..1eec2f8
--- /dev/null
@@ -0,0 +1,49 @@
+From 268a50b29795e5a00c8fd9f91ac8dabcae35fc9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 15 Aug 2024 08:40:29 +0200
+Subject: usb: dwc3: ep0: Don't reset resource alloc flag (including ep0)
+
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+[ Upstream commit 72fca8371f205d654f95b09cd023a71fd5307041 ]
+
+The DWC3_EP_RESOURCE_ALLOCATED flag ensures that the resource of an
+endpoint is only assigned once. Unless the endpoint is reset, don't
+clear this flag. Otherwise we may set endpoint resource again, which
+prevents the driver from initiate transfer after handling a STALL or
+endpoint halt to the control endpoint.
+
+Commit f2e0eee47038 ("usb: dwc3: ep0: Don't reset resource alloc flag")
+was fixing the initial issue, but did this only for physical ep1. Since
+the function dwc3_ep0_stall_and_restart is resetting the flags for both
+physical endpoints, this also has to be done for ep0.
+
+Cc: stable@vger.kernel.org
+Fixes: b311048c174d ("usb: dwc3: gadget: Rewrite endpoint allocation flow")
+Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Link: https://lore.kernel.org/r/20240814-dwc3hwep0reset-v2-1-29e1d7d923ea@pengutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 5d2fb074dea2 ("usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/dwc3/ep0.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
+index 72bb722da2f25..371662a552538 100644
+--- a/drivers/usb/dwc3/ep0.c
++++ b/drivers/usb/dwc3/ep0.c
+@@ -231,7 +231,8 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+       /* stall is always issued on EP0 */
+       dep = dwc->eps[0];
+       __dwc3_gadget_ep_set_halt(dep, 1, false);
+-      dep->flags = DWC3_EP_ENABLED;
++      dep->flags &= DWC3_EP_RESOURCE_ALLOCATED;
++      dep->flags |= DWC3_EP_ENABLED;
+       dwc->delayed_status = false;
+       if (!list_empty(&dep->pending_list)) {
+-- 
+2.43.0
+
diff --git a/queue-6.6/usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch b/queue-6.6/usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch
new file mode 100644 (file)
index 0000000..057e32b
--- /dev/null
@@ -0,0 +1,250 @@
+From e0d934364c00ad0339e2ed1bd437bfaf65ebcafa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Feb 2024 02:26:53 +0000
+Subject: usb: dwc3: gadget: Rewrite endpoint allocation flow
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+[ Upstream commit b311048c174da893f47fc09439bc1f6fa2a29589 ]
+
+The driver dwc3 deviates from the programming guide in regard to
+endpoint configuration. It does this command sequence:
+
+DEPSTARTCFG -> DEPXFERCFG -> DEPCFG
+
+Instead of the suggested flow:
+
+DEPSTARTCFG -> DEPCFG -> DEPXFERCFG
+
+The reasons for this deviation were as follow, quoted:
+
+       1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every
+          %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE
+          (8.1.5). This is incorrect in the scenario of multiple
+          interfaces.
+
+       2) The databook does not mention doing more
+          %DWC3_DEPCMD_DEPXFERCFG for new endpoint on alt setting
+          (8.1.6).
+
+Regarding 1), DEPSTARTCFG resets the endpoints' resource and can be a
+problem if used with SET_INTERFACE request of a multiple interface
+configuration. But we can still satisfy the programming guide
+requirement by assigning the endpoint resource as part of
+usb_ep_enable(). We will only reset endpoint resources on controller
+initialization and SET_CONFIGURATION request.
+
+Regarding 2), the later versions of the programming guide were updated
+to clarify this flow (see "Alternate Initialization on SetInterface
+Request" of the programming guide). As long as the platform has enough
+physical endpoints, we can assign resource to a new endpoint.
+
+The order of the command sequence will not be a problem to most
+platforms for the current implementation of the dwc3 driver. However,
+this order is required in different scenarios (such as initialization
+during controller's hibernation restore). Let's keep the flow consistent
+and follow the programming guide.
+
+Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Link: https://lore.kernel.org/r/c143583a5afb087deb8c3aa5eb227ee23515f272.1706754219.git.Thinh.Nguyen@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 5d2fb074dea2 ("usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/dwc3/core.h   |  1 +
+ drivers/usb/dwc3/ep0.c    |  1 +
+ drivers/usb/dwc3/gadget.c | 89 +++++++++++++++++----------------------
+ drivers/usb/dwc3/gadget.h |  1 +
+ 4 files changed, 41 insertions(+), 51 deletions(-)
+
+diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
+index 3325796f3cb45..b118f4aab1898 100644
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -751,6 +751,7 @@ struct dwc3_ep {
+ #define DWC3_EP_PENDING_CLEAR_STALL   BIT(11)
+ #define DWC3_EP_TXFIFO_RESIZED                BIT(12)
+ #define DWC3_EP_DELAY_STOP             BIT(13)
++#define DWC3_EP_RESOURCE_ALLOCATED    BIT(14)
+       /* This last one is specific to EP0 */
+ #define DWC3_EP0_DIR_IN                       BIT(31)
+diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
+index 6ae8a36f21cf6..72bb722da2f25 100644
+--- a/drivers/usb/dwc3/ep0.c
++++ b/drivers/usb/dwc3/ep0.c
+@@ -646,6 +646,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+               return -EINVAL;
+       case USB_STATE_ADDRESS:
++              dwc3_gadget_start_config(dwc, 2);
+               dwc3_gadget_clear_tx_fifos(dwc);
+               ret = dwc3_ep0_delegate_req(dwc, ctrl);
+diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
+index 9971076c31de6..b560996bd4218 100644
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -516,77 +516,56 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+ static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep)
+ {
+       struct dwc3_gadget_ep_cmd_params params;
++      int ret;
++
++      if (dep->flags & DWC3_EP_RESOURCE_ALLOCATED)
++              return 0;
+       memset(&params, 0x00, sizeof(params));
+       params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
+-      return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
++      ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
+                       &params);
++      if (ret)
++              return ret;
++
++      dep->flags |= DWC3_EP_RESOURCE_ALLOCATED;
++      return 0;
+ }
+ /**
+- * dwc3_gadget_start_config - configure ep resources
+- * @dep: endpoint that is being enabled
+- *
+- * Issue a %DWC3_DEPCMD_DEPSTARTCFG command to @dep. After the command's
+- * completion, it will set Transfer Resource for all available endpoints.
+- *
+- * The assignment of transfer resources cannot perfectly follow the data book
+- * due to the fact that the controller driver does not have all knowledge of the
+- * configuration in advance. It is given this information piecemeal by the
+- * composite gadget framework after every SET_CONFIGURATION and
+- * SET_INTERFACE. Trying to follow the databook programming model in this
+- * scenario can cause errors. For two reasons:
+- *
+- * 1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every
+- * %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE (8.1.5). This is
+- * incorrect in the scenario of multiple interfaces.
+- *
+- * 2) The databook does not mention doing more %DWC3_DEPCMD_DEPXFERCFG for new
+- * endpoint on alt setting (8.1.6).
+- *
+- * The following simplified method is used instead:
++ * dwc3_gadget_start_config - reset endpoint resources
++ * @dwc: pointer to the DWC3 context
++ * @resource_index: DEPSTARTCFG.XferRscIdx value (must be 0 or 2)
+  *
+- * All hardware endpoints can be assigned a transfer resource and this setting
+- * will stay persistent until either a core reset or hibernation. So whenever we
+- * do a %DWC3_DEPCMD_DEPSTARTCFG(0) we can go ahead and do
+- * %DWC3_DEPCMD_DEPXFERCFG for every hardware endpoint as well. We are
+- * guaranteed that there are as many transfer resources as endpoints.
++ * Set resource_index=0 to reset all endpoints' resources allocation. Do this as
++ * part of the power-on/soft-reset initialization.
+  *
+- * This function is called for each endpoint when it is being enabled but is
+- * triggered only when called for EP0-out, which always happens first, and which
+- * should only happen in one of the above conditions.
++ * Set resource_index=2 to reset only non-control endpoints' resources. Do this
++ * on receiving the SET_CONFIGURATION request or hibernation resume.
+  */
+-static int dwc3_gadget_start_config(struct dwc3_ep *dep)
++int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index)
+ {
+       struct dwc3_gadget_ep_cmd_params params;
+-      struct dwc3             *dwc;
+       u32                     cmd;
+       int                     i;
+       int                     ret;
+-      if (dep->number)
+-              return 0;
++      if (resource_index != 0 && resource_index != 2)
++              return -EINVAL;
+       memset(&params, 0x00, sizeof(params));
+       cmd = DWC3_DEPCMD_DEPSTARTCFG;
+-      dwc = dep->dwc;
++      cmd |= DWC3_DEPCMD_PARAM(resource_index);
+-      ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
++      ret = dwc3_send_gadget_ep_cmd(dwc->eps[0], cmd, &params);
+       if (ret)
+               return ret;
+-      for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+-              struct dwc3_ep *dep = dwc->eps[i];
+-
+-              if (!dep)
+-                      continue;
+-
+-              ret = dwc3_gadget_set_xfer_resource(dep);
+-              if (ret)
+-                      return ret;
+-      }
++      /* Reset resource allocation flags */
++      for (i = resource_index; i < dwc->num_eps && dwc->eps[i]; i++)
++              dwc->eps[i]->flags &= ~DWC3_EP_RESOURCE_ALLOCATED;
+       return 0;
+ }
+@@ -881,16 +860,18 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
+               ret = dwc3_gadget_resize_tx_fifos(dep);
+               if (ret)
+                       return ret;
+-
+-              ret = dwc3_gadget_start_config(dep);
+-              if (ret)
+-                      return ret;
+       }
+       ret = dwc3_gadget_set_ep_config(dep, action);
+       if (ret)
+               return ret;
++      if (!(dep->flags & DWC3_EP_RESOURCE_ALLOCATED)) {
++              ret = dwc3_gadget_set_xfer_resource(dep);
++              if (ret)
++                      return ret;
++      }
++
+       if (!(dep->flags & DWC3_EP_ENABLED)) {
+               struct dwc3_trb *trb_st_hw;
+               struct dwc3_trb *trb_link;
+@@ -1044,7 +1025,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+       dep->stream_capable = false;
+       dep->type = 0;
+-      mask = DWC3_EP_TXFIFO_RESIZED;
++      mask = DWC3_EP_TXFIFO_RESIZED | DWC3_EP_RESOURCE_ALLOCATED;
+       /*
+        * dwc3_remove_requests() can exit early if DWC3 EP delayed stop is
+        * set.  Do not clear DEP flags, so that the end transfer command will
+@@ -2909,6 +2890,12 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
+       /* Start with SuperSpeed Default */
+       dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
++      ret = dwc3_gadget_start_config(dwc, 0);
++      if (ret) {
++              dev_err(dwc->dev, "failed to config endpoints\n");
++              return ret;
++      }
++
+       dep = dwc->eps[0];
+       dep->flags = 0;
+       ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
+diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
+index 55a56cf67d736..d73e735e40810 100644
+--- a/drivers/usb/dwc3/gadget.h
++++ b/drivers/usb/dwc3/gadget.h
+@@ -119,6 +119,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
+ void dwc3_ep0_send_delayed_status(struct dwc3 *dwc);
+ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt);
++int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index);
+ /**
+  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+-- 
+2.43.0
+
diff --git a/queue-6.6/watchdog-apple-actually-flush-writes-after-requestin.patch b/queue-6.6/watchdog-apple-actually-flush-writes-after-requestin.patch
new file mode 100644 (file)
index 0000000..ca2f8f9
--- /dev/null
@@ -0,0 +1,43 @@
+From 0b2bdc364c30fe866bf8f1dc9bc73a781c6724e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Oct 2024 00:59:51 +0800
+Subject: watchdog: apple: Actually flush writes after requesting watchdog
+ restart
+
+From: Nick Chan <towinchenmi@gmail.com>
+
+[ Upstream commit 51dfe714c03c066aabc815a2bb2adcc998dfcb30 ]
+
+Although there is an existing code comment about flushing the writes,
+writes were not actually being flushed.
+
+Actually flush the writes by changing readl_relaxed() to readl().
+
+Fixes: 4ed224aeaf661 ("watchdog: Add Apple SoC watchdog driver")
+Suggested-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Nick Chan <towinchenmi@gmail.com>
+Reviewed-by: Guenter Roeck  <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20241001170018.20139-2-towinchenmi@gmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/apple_wdt.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
+index eddeb0fede896..24e457b695662 100644
+--- a/drivers/watchdog/apple_wdt.c
++++ b/drivers/watchdog/apple_wdt.c
+@@ -130,7 +130,7 @@ static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
+        * can take up to ~20-25ms until the SoC is actually reset. Just wait
+        * 50ms here to be safe.
+        */
+-      (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
++      (void)readl(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+       mdelay(50);
+       return 0;
+-- 
+2.43.0
+
diff --git a/queue-6.6/watchdog-mediatek-make-sure-system-reset-gets-assert.patch b/queue-6.6/watchdog-mediatek-make-sure-system-reset-gets-assert.patch
new file mode 100644 (file)
index 0000000..a17ee60
--- /dev/null
@@ -0,0 +1,48 @@
+From 109028ab1ac2f6361eecfe849de522c4e5a93816 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Nov 2024 10:47:51 +0000
+Subject: watchdog: mediatek: Make sure system reset gets asserted in
+ mtk_wdt_restart()
+
+From: Yassine Oudjana <y.oudjana@protonmail.com>
+
+[ Upstream commit a1495a21e0b8aad92132dfcf9c6fffc1bde9d5b2 ]
+
+Clear the IRQ enable bit of WDT_MODE before asserting software reset
+in order to make TOPRGU issue a system reset signal instead of an IRQ.
+
+Fixes: a44a45536f7b ("watchdog: Add driver for Mediatek watchdog")
+Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20241106104738.195968-2-y.oudjana@protonmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/mtk_wdt.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
+index b2330b16b497a..0559d9f2d97b3 100644
+--- a/drivers/watchdog/mtk_wdt.c
++++ b/drivers/watchdog/mtk_wdt.c
+@@ -186,9 +186,15 @@ static int mtk_wdt_restart(struct watchdog_device *wdt_dev,
+ {
+       struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+       void __iomem *wdt_base;
++      u32 reg;
+       wdt_base = mtk_wdt->wdt_base;
++      /* Enable reset in order to issue a system reset instead of an IRQ */
++      reg = readl(wdt_base + WDT_MODE);
++      reg &= ~WDT_MODE_IRQ_EN;
++      writel(reg | WDT_MODE_KEY, wdt_base + WDT_MODE);
++
+       while (1) {
+               writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST);
+               mdelay(5);
+-- 
+2.43.0
+
diff --git a/queue-6.6/watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch b/queue-6.6/watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch
new file mode 100644 (file)
index 0000000..495f9d4
--- /dev/null
@@ -0,0 +1,181 @@
+From b3444c96274736eed37d47541d1efea47372d4d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Sep 2024 17:02:30 +0530
+Subject: watchdog: xilinx_wwdt: Calculate max_hw_heartbeat_ms using clock
+ frequency
+
+From: Harini T <harini.t@amd.com>
+
+[ Upstream commit 006778844c2c132c28cfa90e3570560351e01b9a ]
+
+In the current implementation, the value of max_hw_heartbeat_ms is set
+to the timeout period expressed in milliseconds and fails to verify if
+the close window percentage exceeds the maximum value that the hardware
+supports.
+
+1. Calculate max_hw_heartbeat_ms based on input clock frequency.
+2. Update frequency check to require a minimum frequency of 1Mhz.
+3. Limit the close and open window percent to hardware supported value
+to avoid truncation.
+4. If the user input timeout exceeds the maximum timeout supported, use
+only open window and the framework supports the higher timeouts.
+
+Fixes: 12984cea1b8c ("watchdog: xilinx_wwdt: Add Versal window watchdog support")
+Signed-off-by: Harini T <harini.t@amd.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20240913113230.1939373-1-harini.t@amd.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/watchdog/xilinx_wwdt.c | 75 ++++++++++++++++++++++++++++------
+ 1 file changed, 63 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c
+index d271e2e8d6e27..3d2a156f71800 100644
+--- a/drivers/watchdog/xilinx_wwdt.c
++++ b/drivers/watchdog/xilinx_wwdt.c
+@@ -2,7 +2,7 @@
+ /*
+  * Window watchdog device driver for Xilinx Versal WWDT
+  *
+- * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
++ * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
+  */
+ #include <linux/clk.h>
+@@ -36,6 +36,12 @@
+ #define XWWDT_CLOSE_WINDOW_PERCENT    50
++/* Maximum count value of each 32 bit window */
++#define XWWDT_MAX_COUNT_WINDOW                GENMASK(31, 0)
++
++/* Maximum count value of closed and open window combined */
++#define XWWDT_MAX_COUNT_WINDOW_COMBINED       GENMASK_ULL(32, 1)
++
+ static int wwdt_timeout;
+ static int closed_window_percent;
+@@ -54,6 +60,8 @@ MODULE_PARM_DESC(closed_window_percent,
+  * @xilinx_wwdt_wdd: watchdog device structure
+  * @freq: source clock frequency of WWDT
+  * @close_percent: Closed window percent
++ * @closed_timeout: Closed window timeout in ticks
++ * @open_timeout: Open window timeout in ticks
+  */
+ struct xwwdt_device {
+       void __iomem *base;
+@@ -61,27 +69,22 @@ struct xwwdt_device {
+       struct watchdog_device xilinx_wwdt_wdd;
+       unsigned long freq;
+       u32 close_percent;
++      u64 closed_timeout;
++      u64 open_timeout;
+ };
+ static int xilinx_wwdt_start(struct watchdog_device *wdd)
+ {
+       struct xwwdt_device *xdev = watchdog_get_drvdata(wdd);
+       struct watchdog_device *xilinx_wwdt_wdd = &xdev->xilinx_wwdt_wdd;
+-      u64 time_out, closed_timeout, open_timeout;
+       u32 control_status_reg;
+-      /* Calculate timeout count */
+-      time_out = xdev->freq * wdd->timeout;
+-      closed_timeout = div_u64(time_out * xdev->close_percent, 100);
+-      open_timeout = time_out - closed_timeout;
+-      wdd->min_hw_heartbeat_ms = xdev->close_percent * 10 * wdd->timeout;
+-
+       spin_lock(&xdev->spinlock);
+       iowrite32(XWWDT_MWR_MASK, xdev->base + XWWDT_MWR_OFFSET);
+       iowrite32(~(u32)XWWDT_ESR_WEN_MASK, xdev->base + XWWDT_ESR_OFFSET);
+-      iowrite32((u32)closed_timeout, xdev->base + XWWDT_FWR_OFFSET);
+-      iowrite32((u32)open_timeout, xdev->base + XWWDT_SWR_OFFSET);
++      iowrite32((u32)xdev->closed_timeout, xdev->base + XWWDT_FWR_OFFSET);
++      iowrite32((u32)xdev->open_timeout, xdev->base + XWWDT_SWR_OFFSET);
+       /* Enable the window watchdog timer */
+       control_status_reg = ioread32(xdev->base + XWWDT_ESR_OFFSET);
+@@ -133,7 +136,12 @@ static int xwwdt_probe(struct platform_device *pdev)
+       struct watchdog_device *xilinx_wwdt_wdd;
+       struct device *dev = &pdev->dev;
+       struct xwwdt_device *xdev;
++      u64 max_per_window_ms;
++      u64 min_per_window_ms;
++      u64 timeout_count;
+       struct clk *clk;
++      u32 timeout_ms;
++      u64 ms_count;
+       int ret;
+       xdev = devm_kzalloc(dev, sizeof(*xdev), GFP_KERNEL);
+@@ -154,12 +162,13 @@ static int xwwdt_probe(struct platform_device *pdev)
+               return PTR_ERR(clk);
+       xdev->freq = clk_get_rate(clk);
+-      if (!xdev->freq)
++      if (xdev->freq < 1000000)
+               return -EINVAL;
+       xilinx_wwdt_wdd->min_timeout = XWWDT_MIN_TIMEOUT;
+       xilinx_wwdt_wdd->timeout = XWWDT_DEFAULT_TIMEOUT;
+-      xilinx_wwdt_wdd->max_hw_heartbeat_ms = 1000 * xilinx_wwdt_wdd->timeout;
++      xilinx_wwdt_wdd->max_hw_heartbeat_ms =
++              div64_u64(XWWDT_MAX_COUNT_WINDOW_COMBINED, xdev->freq) * 1000;
+       if (closed_window_percent == 0 || closed_window_percent >= 100)
+               xdev->close_percent = XWWDT_CLOSE_WINDOW_PERCENT;
+@@ -167,6 +176,48 @@ static int xwwdt_probe(struct platform_device *pdev)
+               xdev->close_percent = closed_window_percent;
+       watchdog_init_timeout(xilinx_wwdt_wdd, wwdt_timeout, &pdev->dev);
++
++      /* Calculate ticks for 1 milli-second */
++      ms_count = div_u64(xdev->freq, 1000);
++      timeout_ms = xilinx_wwdt_wdd->timeout * 1000;
++      timeout_count = timeout_ms * ms_count;
++
++      if (timeout_ms > xilinx_wwdt_wdd->max_hw_heartbeat_ms) {
++              /*
++               * To avoid ping restrictions until the minimum hardware heartbeat,
++               * we will solely rely on the open window and
++               * adjust the minimum hardware heartbeat to 0.
++               */
++              xdev->closed_timeout = 0;
++              xdev->open_timeout = XWWDT_MAX_COUNT_WINDOW;
++              xilinx_wwdt_wdd->min_hw_heartbeat_ms = 0;
++              xilinx_wwdt_wdd->max_hw_heartbeat_ms = xilinx_wwdt_wdd->max_hw_heartbeat_ms / 2;
++      } else {
++              xdev->closed_timeout  = div64_u64(timeout_count * xdev->close_percent, 100);
++              xilinx_wwdt_wdd->min_hw_heartbeat_ms =
++                      div64_u64(timeout_ms * xdev->close_percent, 100);
++
++              if (timeout_ms > xilinx_wwdt_wdd->max_hw_heartbeat_ms / 2) {
++                      max_per_window_ms = xilinx_wwdt_wdd->max_hw_heartbeat_ms / 2;
++                      min_per_window_ms = timeout_ms - max_per_window_ms;
++
++                      if (xilinx_wwdt_wdd->min_hw_heartbeat_ms > max_per_window_ms) {
++                              dev_info(xilinx_wwdt_wdd->parent,
++                                       "Closed window cannot be set to %d%%. Using maximum supported value.\n",
++                                      xdev->close_percent);
++                              xdev->closed_timeout = max_per_window_ms * ms_count;
++                              xilinx_wwdt_wdd->min_hw_heartbeat_ms = max_per_window_ms;
++                      } else if (xilinx_wwdt_wdd->min_hw_heartbeat_ms < min_per_window_ms) {
++                              dev_info(xilinx_wwdt_wdd->parent,
++                                       "Closed window cannot be set to %d%%. Using minimum supported value.\n",
++                                      xdev->close_percent);
++                              xdev->closed_timeout = min_per_window_ms * ms_count;
++                              xilinx_wwdt_wdd->min_hw_heartbeat_ms = min_per_window_ms;
++                      }
++              }
++              xdev->open_timeout = timeout_count - xdev->closed_timeout;
++      }
++
+       spin_lock_init(&xdev->spinlock);
+       watchdog_set_drvdata(xilinx_wwdt_wdd, xdev);
+       watchdog_set_nowayout(xilinx_wwdt_wdd, 1);
+-- 
+2.43.0
+
diff --git a/queue-6.6/xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch b/queue-6.6/xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch
new file mode 100644 (file)
index 0000000..365e6f5
--- /dev/null
@@ -0,0 +1,46 @@
+From f07924407175a977a3460fba35cb0c9d74cc0237 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Mar 2024 11:13:27 +0530
+Subject: xhci: Allow RPM on the USB controller (1022:43f7) by default
+
+From: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
+
+[ Upstream commit 28cbed496059fe1868203b76e9e0ef285733524d ]
+
+Enable runtime PM by default for older AMD 1022:43f7 xHCI 1.1 host as it
+is proven to work.
+Driver enables runtime PM by default for newer xHCI 1.2 host.
+
+Link: https://lore.kernel.org/all/12335218.O9o76ZdvQC@natalenko.name/
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
+Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
+Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20240304054327.2564500-1-Basavaraj.Natikar@amd.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: d7b11fe57902 ("xhci: Combine two if statements for Etron xHCI host")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-pci.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index c2b37aa2cdfca..3a2a0d8f7af86 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -374,8 +374,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+               xhci->quirks |= XHCI_RESET_ON_RESUME;
+       }
+-      if (pdev->vendor == PCI_VENDOR_ID_AMD)
++      if (pdev->vendor == PCI_VENDOR_ID_AMD) {
+               xhci->quirks |= XHCI_TRUST_TX_LENGTH;
++              if (pdev->device == 0x43f7)
++                      xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
++      }
+       if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+               ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+-- 
+2.43.0
+
diff --git a/queue-6.6/xhci-combine-two-if-statements-for-etron-xhci-host.patch b/queue-6.6/xhci-combine-two-if-statements-for-etron-xhci-host.patch
new file mode 100644 (file)
index 0000000..08f7f16
--- /dev/null
@@ -0,0 +1,47 @@
+From 2f8bd2b786e2a2745fe78cdd493c9fb2660b4a0e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Nov 2024 12:14:43 +0200
+Subject: xhci: Combine two if statements for Etron xHCI host
+
+From: Kuangyi Chiang <ki.chiang65@gmail.com>
+
+[ Upstream commit d7b11fe5790203fcc0db182249d7bfd945e44ccb ]
+
+Combine two if statements, because these hosts have the same
+quirk flags applied.
+
+[Mathias: has stable tag because other fixes in series depend on this]
+
+Fixes: 91f7a1524a92 ("xhci: Apply broken streams quirk to Etron EJ188 xHCI host")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kuangyi Chiang <ki.chiang65@gmail.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20241106101459.775897-18-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-pci.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index f74c067b54587..d36158df83afc 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -456,12 +456,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+               xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
+-                      pdev->device == PCI_DEVICE_ID_EJ168) {
+-              xhci->quirks |= XHCI_RESET_ON_RESUME;
+-              xhci->quirks |= XHCI_BROKEN_STREAMS;
+-      }
+-      if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
+-                      pdev->device == PCI_DEVICE_ID_EJ188) {
++          (pdev->device == PCI_DEVICE_ID_EJ168 ||
++           pdev->device == PCI_DEVICE_ID_EJ188)) {
+               xhci->quirks |= XHCI_RESET_ON_RESUME;
+               xhci->quirks |= XHCI_BROKEN_STREAMS;
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch b/queue-6.6/xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch
new file mode 100644 (file)
index 0000000..3cc5ef7
--- /dev/null
@@ -0,0 +1,107 @@
+From fabff60c0a2041a9ddaa9dadc1974668923838a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Nov 2024 12:14:44 +0200
+Subject: xhci: Don't issue Reset Device command to Etron xHCI host
+
+From: Kuangyi Chiang <ki.chiang65@gmail.com>
+
+[ Upstream commit 76d98856b1c6d06ce18f32c20527a4f9d283e660 ]
+
+Sometimes the hub driver does not recognize the USB device connected
+to the external USB2.0 hub when the system resumes from S4.
+
+After the SetPortFeature(PORT_RESET) request is completed, the hub
+driver calls the HCD reset_device callback, which will issue a Reset
+Device command and free all structures associated with endpoints
+that were disabled.
+
+This happens when the xHCI driver issue a Reset Device command to
+inform the Etron xHCI host that the USB device associated with a
+device slot has been reset. Seems that the Etron xHCI host can not
+perform this command correctly, affecting the USB device.
+
+To work around this, the xHCI driver should obtain a new device slot
+with reference to commit 651aaf36a7d7 ("usb: xhci: Handle USB transaction
+error on address command"), which is another way to inform the Etron
+xHCI host that the USB device has been reset.
+
+Add a new XHCI_ETRON_HOST quirk flag to invoke the workaround in
+xhci_discover_or_reset_device().
+
+Fixes: 2a8f82c4ceaf ("USB: xhci: Notify the xHC when a device is reset.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kuangyi Chiang <ki.chiang65@gmail.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20241106101459.775897-19-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-pci.c |  1 +
+ drivers/usb/host/xhci.c     | 19 +++++++++++++++++++
+ drivers/usb/host/xhci.h     |  1 +
+ 3 files changed, 21 insertions(+)
+
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index d36158df83afc..340d9597d1ab0 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -458,6 +458,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
+           (pdev->device == PCI_DEVICE_ID_EJ168 ||
+            pdev->device == PCI_DEVICE_ID_EJ188)) {
++              xhci->quirks |= XHCI_ETRON_HOST;
+               xhci->quirks |= XHCI_RESET_ON_RESUME;
+               xhci->quirks |= XHCI_BROKEN_STREAMS;
+       }
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index f005ce1f91ca2..3bd70e6ad64ba 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -3642,6 +3642,8 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
+                               xhci->num_active_eps);
+ }
++static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
++
+ /*
+  * This submits a Reset Device Command, which will set the device state to 0,
+  * set the device address to 0, and disable all the endpoints except the default
+@@ -3712,6 +3714,23 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
+                                               SLOT_STATE_DISABLED)
+               return 0;
++      if (xhci->quirks & XHCI_ETRON_HOST) {
++              /*
++               * Obtaining a new device slot to inform the xHCI host that
++               * the USB device has been reset.
++               */
++              ret = xhci_disable_slot(xhci, udev->slot_id);
++              xhci_free_virt_device(xhci, udev->slot_id);
++              if (!ret) {
++                      ret = xhci_alloc_dev(hcd, udev);
++                      if (ret == 1)
++                              ret = 0;
++                      else
++                              ret = -EINVAL;
++              }
++              return ret;
++      }
++
+       trace_xhci_discover_or_reset_device(slot_ctx);
+       xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index a0005a1124938..4bbd12db7239a 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1660,6 +1660,7 @@ struct xhci_hcd {
+ #define XHCI_ZHAOXIN_HOST     BIT_ULL(46)
+ #define XHCI_WRITE_64_HI_LO   BIT_ULL(47)
+ #define XHCI_CDNS_SCTX_QUIRK  BIT_ULL(48)
++#define XHCI_ETRON_HOST       BIT_ULL(49)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+-- 
+2.43.0
+
diff --git a/queue-6.6/xhci-fix-control-transfer-error-on-etron-xhci-host.patch b/queue-6.6/xhci-fix-control-transfer-error-on-etron-xhci-host.patch
new file mode 100644 (file)
index 0000000..3c643df
--- /dev/null
@@ -0,0 +1,88 @@
+From a9a30ba698f399159bd9210f15f94e7f3ca2ab68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Nov 2024 12:14:45 +0200
+Subject: xhci: Fix control transfer error on Etron xHCI host
+
+From: Kuangyi Chiang <ki.chiang65@gmail.com>
+
+[ Upstream commit 5e1c67abc9301d05130b7e267c204e7005503b33 ]
+
+Performing a stability stress test on a USB3.0 2.5G ethernet adapter
+results in errors like this:
+
+[   91.441469] r8152 2-3:1.0 eth3: get_registers -71
+[   91.458659] r8152 2-3:1.0 eth3: get_registers -71
+[   91.475911] r8152 2-3:1.0 eth3: get_registers -71
+[   91.493203] r8152 2-3:1.0 eth3: get_registers -71
+[   91.510421] r8152 2-3:1.0 eth3: get_registers -71
+
+The r8152 driver will periodically issue lots of control-IN requests
+to access the status of ethernet adapter hardware registers during
+the test.
+
+This happens when the xHCI driver enqueue a control TD (which cross
+over the Link TRB between two ring segments, as shown) in the endpoint
+zero's transfer ring. Seems the Etron xHCI host can not perform this
+TD correctly, causing the USB transfer error occurred, maybe the upper
+driver retry that control-IN request can solve problem, but not all
+drivers do this.
+
+|     |
+-------
+| TRB | Setup Stage
+-------
+| TRB | Link
+-------
+-------
+| TRB | Data Stage
+-------
+| TRB | Status Stage
+-------
+|     |
+
+To work around this, the xHCI driver should enqueue a No Op TRB if
+next available TRB is the Link TRB in the ring segment, this can
+prevent the Setup and Data Stage TRB to be breaked by the Link TRB.
+
+Check if the XHCI_ETRON_HOST quirk flag is set before invoking the
+workaround in xhci_queue_ctrl_tx().
+
+Fixes: d0e96f5a71a0 ("USB: xhci: Control transfer support.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kuangyi Chiang <ki.chiang65@gmail.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20241106101459.775897-20-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-ring.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 99759926daac6..50f5880114004 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -3828,6 +3828,20 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+       if (!urb->setup_packet)
+               return -EINVAL;
++      if ((xhci->quirks & XHCI_ETRON_HOST) &&
++          urb->dev->speed >= USB_SPEED_SUPER) {
++              /*
++               * If next available TRB is the Link TRB in the ring segment then
++               * enqueue a No Op TRB, this can prevent the Setup and Data Stage
++               * TRB to be breaked by the Link TRB.
++               */
++              if (trb_is_link(ep_ring->enqueue + 1)) {
++                      field = TRB_TYPE(TRB_TR_NOOP) | ep_ring->cycle_state;
++                      queue_trb(xhci, ep_ring, false, 0, 0,
++                                      TRB_INTR_TARGET(0), field);
++              }
++      }
++
+       /* 1 TRB for setup, 1 for status */
+       num_trbs = 2;
+       /*
+-- 
+2.43.0
+
diff --git a/queue-6.6/xhci-remove-xhci_trust_tx_length-quirk.patch b/queue-6.6/xhci-remove-xhci_trust_tx_length-quirk.patch
new file mode 100644 (file)
index 0000000..c74eb3c
--- /dev/null
@@ -0,0 +1,190 @@
+From 30d708e9769b50f6990568b5c15841a6dd49a780 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Apr 2024 17:02:36 +0300
+Subject: xhci: remove XHCI_TRUST_TX_LENGTH quirk
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 34b67198244f2d7d8409fa4eb76204c409c0c97e ]
+
+If this quirk was set then driver would treat transfer events with
+'Success' completion code as 'Short packet' if there were untransferred
+bytes left.
+
+This is so common that turn it into default behavior.
+
+xhci_warn_ratelimited() is no longer used after this, so remove it.
+
+A success event with untransferred bytes left doesn't always mean a
+misbehaving controller. If there was an error mid a multi-TRB TD it's
+allowed to issue a success event for the last TRB in that TD.
+
+See xhci 1.2 spec 4.9.1 Transfer Descriptors
+
+"Note: If an error is detected while processing a multi-TRB TD, the xHC
+ shall generate a Transfer Event for the TRB that the error was detected
+ on with the appropriate error Condition Code, then may advance to the
+ next TD. If in the process of advancing to the next TD, a Transfer TRB
+ is encountered with its IOC flag set, then the Condition Code of the
+ Transfer Event generated for that Transfer TRB should be Success,
+ because there was no error actually associated with the TRB that
+ generated the Event. However, an xHC implementation may redundantly
+ assert the original error Condition Code."
+
+Co-developed-by: Niklas Neronin <niklas.neronin@linux.intel.com>
+Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20240429140245.3955523-10-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: d7b11fe57902 ("xhci: Combine two if statements for Etron xHCI host")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-pci.c  | 15 ++-------------
+ drivers/usb/host/xhci-rcar.c |  6 ++----
+ drivers/usb/host/xhci-ring.c | 15 +++++----------
+ drivers/usb/host/xhci.h      |  4 +---
+ 4 files changed, 10 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index 3a2a0d8f7af86..f74c067b54587 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -337,17 +337,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+                               "QUIRK: Fresco Logic revision %u "
+                               "has broken MSI implementation",
+                               pdev->revision);
+-              xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+       }
+       if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+                       pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
+               xhci->quirks |= XHCI_BROKEN_STREAMS;
+-      if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
+-                      pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100)
+-              xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+-
+       if (pdev->vendor == PCI_VENDOR_ID_NEC)
+               xhci->quirks |= XHCI_NEC_HOST;
+@@ -374,11 +369,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+               xhci->quirks |= XHCI_RESET_ON_RESUME;
+       }
+-      if (pdev->vendor == PCI_VENDOR_ID_AMD) {
+-              xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+-              if (pdev->device == 0x43f7)
+-                      xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+-      }
++      if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43f7)
++              xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+       if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+               ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+@@ -466,7 +458,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
+                       pdev->device == PCI_DEVICE_ID_EJ168) {
+               xhci->quirks |= XHCI_RESET_ON_RESUME;
+-              xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+               xhci->quirks |= XHCI_BROKEN_STREAMS;
+       }
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
+@@ -477,7 +468,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+       if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
+           pdev->device == 0x0014) {
+-              xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+               xhci->quirks |= XHCI_ZERO_64B_REGS;
+       }
+       if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
+@@ -507,7 +497,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+       }
+       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+               pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) {
+-              xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+               xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
+       }
+       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
+index ab9c5969e4624..8b357647728c2 100644
+--- a/drivers/usb/host/xhci-rcar.c
++++ b/drivers/usb/host/xhci-rcar.c
+@@ -214,8 +214,7 @@ static int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
+  */
+ #define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware)                         \
+       .firmware_name = firmware,                                      \
+-      .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH |        \
+-                XHCI_SLOW_SUSPEND,                                    \
++      .quirks = XHCI_NO_64BIT_SUPPORT |  XHCI_SLOW_SUSPEND,           \
+       .init_quirk = xhci_rcar_init_quirk,                             \
+       .plat_start = xhci_rcar_start,                                  \
+       .resume_quirk = xhci_rcar_resume_quirk,
+@@ -229,8 +228,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
+ };
+ static const struct xhci_plat_priv xhci_plat_renesas_rzv2m = {
+-      .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH |
+-                XHCI_SLOW_SUSPEND,
++      .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND,
+       .init_quirk = xhci_rzv2m_init_quirk,
+       .plat_start = xhci_rzv2m_start,
+ };
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 258e64d6522c6..99759926daac6 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2443,8 +2443,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+                       break;
+               if (remaining) {
+                       frame->status = short_framestatus;
+-                      if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
+-                              sum_trbs_for_length = true;
++                      sum_trbs_for_length = true;
+                       break;
+               }
+               frame->status = 0;
+@@ -2693,15 +2692,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+        * transfer type
+        */
+       case COMP_SUCCESS:
+-              if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+-                      break;
+-              if (xhci->quirks & XHCI_TRUST_TX_LENGTH ||
+-                  ep_ring->last_td_was_short)
++              if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
+                       trb_comp_code = COMP_SHORT_PACKET;
+-              else
+-                      xhci_warn_ratelimited(xhci,
+-                                            "WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n",
+-                                            slot_id, ep_index);
++                      xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n",
++                               slot_id, ep_index, ep_ring->last_td_was_short);
++              }
+               break;
+       case COMP_SHORT_PACKET:
+               break;
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index f2190d121233b..a0005a1124938 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1619,7 +1619,7 @@ struct xhci_hcd {
+ #define XHCI_RESET_ON_RESUME  BIT_ULL(7)
+ #define       XHCI_SW_BW_CHECKING     BIT_ULL(8)
+ #define XHCI_AMD_0x96_HOST    BIT_ULL(9)
+-#define XHCI_TRUST_TX_LENGTH  BIT_ULL(10)
++#define XHCI_TRUST_TX_LENGTH  BIT_ULL(10) /* Deprecated */
+ #define XHCI_LPM_SUPPORT      BIT_ULL(11)
+ #define XHCI_INTEL_HOST               BIT_ULL(12)
+ #define XHCI_SPURIOUS_REBOOT  BIT_ULL(13)
+@@ -1761,8 +1761,6 @@ static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci)
+       dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+ #define xhci_warn(xhci, fmt, args...) \
+       dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+-#define xhci_warn_ratelimited(xhci, fmt, args...) \
+-      dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+ #define xhci_info(xhci, fmt, args...) \
+       dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+-- 
+2.43.0
+
diff --git a/queue-6.6/zram-clear-idle-flag-in-mark_idle.patch b/queue-6.6/zram-clear-idle-flag-in-mark_idle.patch
new file mode 100644 (file)
index 0000000..8524f33
--- /dev/null
@@ -0,0 +1,50 @@
+From 178d758702e06a3b8f11c5b61839c900d0ac1356 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Oct 2024 00:36:15 +0900
+Subject: zram: clear IDLE flag in mark_idle()
+
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+
+[ Upstream commit d37da422edb0664a2037e6d7d42fe6d339aae78a ]
+
+If entry does not fulfill current mark_idle() parameters, e.g.  cutoff
+time, then we should clear its ZRAM_IDLE from previous mark_idle()
+invocations.
+
+Consider the following case:
+- mark_idle() cutoff time 8h
+- mark_idle() cutoff time 4h
+- writeback() idle - will writeback entries with cutoff time 8h,
+  while it should only pick entries with cutoff time 4h
+
+The bug was reported by Shin Kawamura.
+
+Link: https://lkml.kernel.org/r/20241028153629.1479791-3-senozhatsky@chromium.org
+Fixes: 755804d16965 ("zram: introduce an aged idle interface")
+Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reported-by: Shin Kawamura <kawasin@google.com>
+Acked-by: Brian Geffon <bgeffon@google.com>
+Cc: Minchan Kim <minchan@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/zram/zram_drv.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
+index e05eace18cc47..27f9ae16a7282 100644
+--- a/drivers/block/zram/zram_drv.c
++++ b/drivers/block/zram/zram_drv.c
+@@ -319,6 +319,8 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
+ #endif
+               if (is_idle)
+                       zram_set_flag(zram, index, ZRAM_IDLE);
++              else
++                      zram_clear_flag(zram, index, ZRAM_IDLE);
+               zram_slot_unlock(zram, index);
+       }
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/zram-do-not-mark-idle-slots-that-cannot-be-idle.patch b/queue-6.6/zram-do-not-mark-idle-slots-that-cannot-be-idle.patch
new file mode 100644 (file)
index 0000000..bb5ba0e
--- /dev/null
@@ -0,0 +1,66 @@
+From 130f4c81955837169f55c2fb03ee5bf84c03a2b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Sep 2024 11:09:10 +0900
+Subject: zram: do not mark idle slots that cannot be idle
+
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+
+[ Upstream commit b967fa1ba72b5da2b6d9bf95f0b13420a59e0701 ]
+
+ZRAM_SAME slots cannot be post-processed (writeback or recompress) so do
+not mark them ZRAM_IDLE.  Same with ZRAM_WB slots, they cannot be
+ZRAM_IDLE because they are not in zsmalloc pool anymore.
+
+Link: https://lkml.kernel.org/r/20240917021020.883356-6-senozhatsky@chromium.org
+Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Cc: Minchan Kim <minchan@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: d37da422edb0 ("zram: clear IDLE flag in mark_idle()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/zram/zram_drv.c | 25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
+index 582df13bfde94..e05eace18cc47 100644
+--- a/drivers/block/zram/zram_drv.c
++++ b/drivers/block/zram/zram_drv.c
+@@ -297,17 +297,28 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
+               /*
+                * Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race.
+                * See the comment in writeback_store.
++               *
++               * Also do not mark ZRAM_SAME slots as ZRAM_IDLE, because no
++               * post-processing (recompress, writeback) happens to the
++               * ZRAM_SAME slot.
++               *
++               * And ZRAM_WB slots simply cannot be ZRAM_IDLE.
+                */
+               zram_slot_lock(zram, index);
+-              if (zram_allocated(zram, index) &&
+-                              !zram_test_flag(zram, index, ZRAM_UNDER_WB)) {
++              if (!zram_allocated(zram, index) ||
++                  zram_test_flag(zram, index, ZRAM_WB) ||
++                  zram_test_flag(zram, index, ZRAM_UNDER_WB) ||
++                  zram_test_flag(zram, index, ZRAM_SAME)) {
++                      zram_slot_unlock(zram, index);
++                      continue;
++              }
++
+ #ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
+-                      is_idle = !cutoff || ktime_after(cutoff,
+-                                                       zram->table[index].ac_time);
++              is_idle = !cutoff ||
++                      ktime_after(cutoff, zram->table[index].ac_time);
+ #endif
+-                      if (is_idle)
+-                              zram_set_flag(zram, index, ZRAM_IDLE);
+-              }
++              if (is_idle)
++                      zram_set_flag(zram, index, ZRAM_IDLE);
+               zram_slot_unlock(zram, index);
+       }
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/zram-split-memory-tracking-and-ac-time-tracking.patch b/queue-6.6/zram-split-memory-tracking-and-ac-time-tracking.patch
new file mode 100644 (file)
index 0000000..ade6854
--- /dev/null
@@ -0,0 +1,167 @@
+From 6437f33a1071d6aa2a505dcb4c8e743d856add19 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Nov 2023 11:42:12 +0900
+Subject: zram: split memory-tracking and ac-time tracking
+
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+
+[ Upstream commit a7a0350583ba51d8cde6180bb51d704b89a3b29e ]
+
+ZRAM_MEMORY_TRACKING enables two features:
+- per-entry ac-time tracking
+- debugfs interface
+
+The latter one is the reason why memory-tracking depends on DEBUG_FS,
+while the former one is used far beyond debugging these days.  Namely
+ac-time is used for fine grained writeback of idle entries (pages).
+
+Move ac-time tracking under its own config option so that it can be
+enabled (along with writeback) on systems without DEBUG_FS.
+
+[senozhatsky@chromium.org: ifdef fixup, per Dmytro]
+  Link: https://lkml.kernel.org/r/20231117013543.540280-1-senozhatsky@chromium.org
+Link: https://lkml.kernel.org/r/20231115024223.4133148-1-senozhatsky@chromium.org
+Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Cc: Minchan Kim <minchan@kernel.org>
+Cc: Dmytro Maluka <dmaluka@chromium.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: d37da422edb0 ("zram: clear IDLE flag in mark_idle()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/admin-guide/blockdev/zram.rst |  2 +-
+ drivers/block/zram/Kconfig                  | 11 ++++++++-
+ drivers/block/zram/zram_drv.c               | 27 ++++++++++-----------
+ drivers/block/zram/zram_drv.h               |  2 +-
+ 4 files changed, 25 insertions(+), 17 deletions(-)
+
+diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
+index e4551579cb128..ee2b0030d4168 100644
+--- a/Documentation/admin-guide/blockdev/zram.rst
++++ b/Documentation/admin-guide/blockdev/zram.rst
+@@ -328,7 +328,7 @@ as idle::
+ From now on, any pages on zram are idle pages. The idle mark
+ will be removed until someone requests access of the block.
+ IOW, unless there is access request, those pages are still idle pages.
+-Additionally, when CONFIG_ZRAM_MEMORY_TRACKING is enabled pages can be
++Additionally, when CONFIG_ZRAM_TRACK_ENTRY_ACTIME is enabled pages can be
+ marked as idle based on how long (in seconds) it's been since they were
+ last accessed::
+diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
+index 0386b7da02aa3..af201392ed52c 100644
+--- a/drivers/block/zram/Kconfig
++++ b/drivers/block/zram/Kconfig
+@@ -69,9 +69,18 @@ config ZRAM_WRITEBACK
+        See Documentation/admin-guide/blockdev/zram.rst for more information.
++config ZRAM_TRACK_ENTRY_ACTIME
++      bool "Track access time of zram entries"
++      depends on ZRAM
++      help
++        With this feature zram tracks access time of every stored
++        entry (page), which can be used for a more fine grained IDLE
++        pages writeback.
++
+ config ZRAM_MEMORY_TRACKING
+       bool "Track zRam block status"
+       depends on ZRAM && DEBUG_FS
++      select ZRAM_TRACK_ENTRY_ACTIME
+       help
+         With this feature, admin can track the state of allocated blocks
+         of zRAM. Admin could see the information via
+@@ -86,4 +95,4 @@ config ZRAM_MULTI_COMP
+         This will enable multi-compression streams, so that ZRAM can
+         re-compress pages using a potentially slower but more effective
+         compression algorithm. Note, that IDLE page recompression
+-        requires ZRAM_MEMORY_TRACKING.
++        requires ZRAM_TRACK_ENTRY_ACTIME.
+diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
+index c29c471b6a182..582df13bfde94 100644
+--- a/drivers/block/zram/zram_drv.c
++++ b/drivers/block/zram/zram_drv.c
+@@ -174,6 +174,14 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index)
+       return prio & ZRAM_COMP_PRIORITY_MASK;
+ }
++static void zram_accessed(struct zram *zram, u32 index)
++{
++      zram_clear_flag(zram, index, ZRAM_IDLE);
++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
++      zram->table[index].ac_time = ktime_get_boottime();
++#endif
++}
++
+ static inline void update_used_max(struct zram *zram,
+                                       const unsigned long pages)
+ {
+@@ -293,8 +301,9 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
+               zram_slot_lock(zram, index);
+               if (zram_allocated(zram, index) &&
+                               !zram_test_flag(zram, index, ZRAM_UNDER_WB)) {
+-#ifdef CONFIG_ZRAM_MEMORY_TRACKING
+-                      is_idle = !cutoff || ktime_after(cutoff, zram->table[index].ac_time);
++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
++                      is_idle = !cutoff || ktime_after(cutoff,
++                                                       zram->table[index].ac_time);
+ #endif
+                       if (is_idle)
+                               zram_set_flag(zram, index, ZRAM_IDLE);
+@@ -317,7 +326,7 @@ static ssize_t idle_store(struct device *dev,
+                */
+               u64 age_sec;
+-              if (IS_ENABLED(CONFIG_ZRAM_MEMORY_TRACKING) && !kstrtoull(buf, 0, &age_sec))
++              if (IS_ENABLED(CONFIG_ZRAM_TRACK_ENTRY_ACTIME) && !kstrtoull(buf, 0, &age_sec))
+                       cutoff_time = ktime_sub(ktime_get_boottime(),
+                                       ns_to_ktime(age_sec * NSEC_PER_SEC));
+               else
+@@ -844,12 +853,6 @@ static void zram_debugfs_destroy(void)
+       debugfs_remove_recursive(zram_debugfs_root);
+ }
+-static void zram_accessed(struct zram *zram, u32 index)
+-{
+-      zram_clear_flag(zram, index, ZRAM_IDLE);
+-      zram->table[index].ac_time = ktime_get_boottime();
+-}
+-
+ static ssize_t read_block_state(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+ {
+@@ -933,10 +936,6 @@ static void zram_debugfs_unregister(struct zram *zram)
+ #else
+ static void zram_debugfs_create(void) {};
+ static void zram_debugfs_destroy(void) {};
+-static void zram_accessed(struct zram *zram, u32 index)
+-{
+-      zram_clear_flag(zram, index, ZRAM_IDLE);
+-};
+ static void zram_debugfs_register(struct zram *zram) {};
+ static void zram_debugfs_unregister(struct zram *zram) {};
+ #endif
+@@ -1257,7 +1256,7 @@ static void zram_free_page(struct zram *zram, size_t index)
+ {
+       unsigned long handle;
+-#ifdef CONFIG_ZRAM_MEMORY_TRACKING
++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
+       zram->table[index].ac_time = 0;
+ #endif
+       if (zram_test_flag(zram, index, ZRAM_IDLE))
+diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
+index ca7a15bd48456..35e3221446292 100644
+--- a/drivers/block/zram/zram_drv.h
++++ b/drivers/block/zram/zram_drv.h
+@@ -69,7 +69,7 @@ struct zram_table_entry {
+               unsigned long element;
+       };
+       unsigned long flags;
+-#ifdef CONFIG_ZRAM_MEMORY_TRACKING
++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
+       ktime_t ac_time;
+ #endif
+ };
+-- 
+2.43.0
+