From 36c7b568101824ecfec0b2bba37a1a814c32b37e Mon Sep 17 00:00:00 2001 From: almalinux-bot-kernel Date: Wed, 24 Jun 2026 05:25:55 +0000 Subject: [PATCH] Import of kernel-5.14.0-687.17.1.el9_8 --- ...87.15.1.el9 => COPYING-5.14.0-687.17.1.el9 | 0 Documentation/driver-api/dpll.rst | 58 +++++-- Documentation/netlink/specs/dpll.yaml | 59 +++++-- arch/s390/mm/fault.c | 12 +- drivers/block/rbd.c | 20 +-- drivers/dpll/dpll_core.c | 3 +- drivers/dpll/dpll_netlink.c | 65 ++++++-- drivers/dpll/dpll_nl.c | 5 +- drivers/dpll/dpll_nl.h | 2 +- drivers/dpll/zl3073x/chan.c | 31 +++- drivers/dpll/zl3073x/chan.h | 14 ++ drivers/dpll/zl3073x/core.c | 45 ------ drivers/dpll/zl3073x/dpll.c | 148 +++++++++++------- drivers/dpll/zl3073x/ref.h | 14 -- drivers/dpll/zl3073x/regs.h | 24 ++- drivers/infiniband/hw/mana/cq.c | 5 +- drivers/infiniband/hw/mana/qp.c | 3 + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 +- drivers/net/ethernet/ibm/ibmveth.c | 22 +++ drivers/net/ethernet/ibm/ibmveth.h | 1 + drivers/net/ethernet/intel/ice/ice_lib.c | 10 +- .../net/ethernet/mellanox/mlx5/core/dpll.c | 6 +- drivers/nvme/target/tcp.c | 30 +++- drivers/s390/crypto/ap_bus.c | 10 ++ drivers/scsi/qla2xxx/qla_iocb.c | 2 - drivers/xen/privcmd.c | 7 + fs/gfs2/bmap.c | 21 ++- include/linux/dpll.h | 33 +++- include/net/tc_act/tc_pedit.h | 1 - include/uapi/linux/dpll.h | 23 +++ kernel.sbat | 4 +- kernel/exit.c | 1 + net/bluetooth/hci_event.c | 18 ++- net/bluetooth/hci_sync.c | 3 +- net/can/isotp.c | 24 ++- net/mac80211/mlme.c | 9 +- net/mac80211/rx.c | 2 +- net/mac80211/util.c | 4 +- net/mptcp/protocol.c | 2 + net/mptcp/protocol.h | 1 + net/mptcp/subflow.c | 15 +- net/sched/act_pedit.c | 77 ++++----- sound/usb/endpoint.c | 37 +++-- 43 files changed, 601 insertions(+), 280 deletions(-) rename COPYING-5.14.0-687.15.1.el9 => COPYING-5.14.0-687.17.1.el9 (100%) diff --git a/COPYING-5.14.0-687.15.1.el9 b/COPYING-5.14.0-687.17.1.el9 similarity index 100% rename from COPYING-5.14.0-687.15.1.el9 rename to COPYING-5.14.0-687.17.1.el9 diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst index 93c191b2d0..bae14766d4 100644 --- a/Documentation/driver-api/dpll.rst +++ b/Documentation/driver-api/dpll.rst @@ -65,35 +65,43 @@ request, where user provides attributes that result in single pin match. Pin selection ============= -In general, selected pin (the one which signal is driving the dpll -device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only -one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll -device. +Pin state (``DPLL_A_PIN_STATE``) reflects the administrative intent set +by the user. Pin operational state (``DPLL_A_PIN_OPERSTATE``) reflects +what the hardware is actually doing with the pin. Pin selection can be done either manually or automatically, depending on hardware capabilities and active dpll device work mode (``DPLL_A_MODE`` attribute). The consequence is that there are -differences for each mode in terms of available pin states, as well as -for the states the user can request for a dpll device. +differences for each mode in terms of available pin states the user can +request for a dpll device. -In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive -one of following pin states: +In manual mode (``DPLL_MODE_MANUAL``) the user can request one of +following pin states: -- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device -- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll +- ``DPLL_PIN_STATE_CONNECTED`` - the pin is selected to drive dpll device +- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not selected to drive + dpll device -In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or -receive one of following pin states: +In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request one of +following pin states: - ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid input for automatic selection algorithm - ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as a valid input for automatic selection algorithm -In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive -pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection -algorithm locks a dpll device with one of the inputs. +The actual hardware status of a pin is reported via the operational +state (``DPLL_A_PIN_OPERSTATE``) attribute nested under the parent +device: + +- ``DPLL_PIN_OPERSTATE_ACTIVE`` - pin is qualified and actively used + by the DPLL +- ``DPLL_PIN_OPERSTATE_STANDBY`` - pin is qualified but not actively + used by the DPLL +- ``DPLL_PIN_OPERSTATE_NO_SIGNAL`` - pin does not have a valid signal +- ``DPLL_PIN_OPERSTATE_QUAL_FAILED`` - pin signal failed qualification + checks Shared pins =========== @@ -250,6 +258,26 @@ in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute. ``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature =============================== ======================== +Fractional frequency offset +=========================== + +The fractional frequency offset (FFO) is reported through two attributes +that carry the same measurement at different precisions: + +- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET`` in PPM (parts per million) +- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT`` in PPT (parts per trillion) + +Both attributes appear at the top level of a pin and inside each +``pin-parent-device`` nest. Two FFO types are defined: + +- ``DPLL_FFO_PORT_RXTX_RATE`` - RX vs TX symbol rate offset (top-level) +- ``DPLL_FFO_PIN_DEVICE`` - pin vs parent DPLL offset (per-parent) + +The driver declares which types it supports via the ``supported_ffo`` +bitmask in ``struct dpll_pin_ops``. The core only calls the ``ffo_get`` +callback for types the driver has opted into. The requested type is +passed to the driver in the ``struct dpll_ffo_param``. + Frequency monitor ================= diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index cb5da356bb..4ba8adcf82 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -212,6 +212,27 @@ definitions: name: selectable doc: pin enabled for automatic input selection render-max: true + - + type: enum + name: pin-operstate + doc: | + defines possible operational states of a pin with respect to its + parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE attribute + entries: + - + name: active + doc: pin is qualified and actively used by the DPLL + value: 1 + - + name: standby + doc: pin is qualified but not actively used by the DPLL + - + name: no-signal + doc: pin does not have a valid signal + - + name: qual-failed + doc: pin signal failed qualification (e.g. frequency or phase monitor) + render-max: true - type: flags name: pin-capabilities @@ -427,12 +448,14 @@ attribute-sets: name: fractional-frequency-offset type: sint doc: | - The FFO (Fractional Frequency Offset) between the RX and TX - symbol rate on the media associated with the pin: - (rx_frequency-tx_frequency)/rx_frequency + The FFO (Fractional Frequency Offset) of the pin. + At top level this represents the RX vs TX symbol rate + offset on the media associated with the pin. Inside + the pin-parent-device nest it represents the frequency + offset between the pin and its parent DPLL device. Value is in PPM (parts per million). - This may be implemented for example for pin of type - PIN_TYPE_SYNCE_ETH_PORT. + This is a lower-precision version of + fractional-frequency-offset-ppt. - name: esync-frequency type: u64 @@ -471,12 +494,14 @@ attribute-sets: name: fractional-frequency-offset-ppt type: sint doc: | - The FFO (Fractional Frequency Offset) of the pin with respect to - the nominal frequency. - Value = (frequency_measured - frequency_nominal) / frequency_nominal + The FFO (Fractional Frequency Offset) of the pin. + At top level this represents the RX vs TX symbol rate + offset on the media associated with the pin. Inside + the pin-parent-device nest it represents the frequency + offset between the pin and its parent DPLL device. Value is in PPT (parts per trillion, 10^-12). - Note: This attribute provides higher resolution than the standard - fractional-frequency-offset (which is in PPM). + This is a higher-precision version of + fractional-frequency-offset. - name: measured-frequency type: u64 @@ -488,6 +513,14 @@ attribute-sets: Value of (DPLL_A_PIN_MEASURED_FREQUENCY % DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part of a measured frequency value. + - + name: operstate + type: u32 + enum: pin-operstate + doc: | + Operational state of the pin with respect to its parent DPLL + device. Unlike state (which reflects the administrative intent), + operstate reflects the actual hardware status. - name: pin-parent-device @@ -501,8 +534,14 @@ attribute-sets: name: prio - name: state + - + name: operstate - name: phase-offset + - + name: fractional-frequency-offset + - + name: fractional-frequency-offset-ppt - name: pin-parent-pin subset-of: pin diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 78adfecc9b..1fb58159c7 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -547,10 +547,18 @@ void do_secure_storage_access(struct pt_regs *regs) page = phys_to_page(addr); if (unlikely(!try_get_page(page))) break; - rc = arch_make_page_accessible(page); + + rc = uv_convert_from_secure(addr); + if (!rc) + clear_bit(PG_arch_1, &page->flags); put_page(page); + /* + * There are some valid fixup types for kernel + * accesses to donated secure memory. zeropad is one + * of them. + */ if (rc) - BUG(); + return handle_fault_error_nolock(regs, 0); break; default: unreachable(); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index c82ec465c5..bfa3bae3b4 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4547,24 +4547,12 @@ out: return ret; } -static void cancel_tasks_sync(struct rbd_device *rbd_dev) -{ - dout("%s rbd_dev %p\n", __func__, rbd_dev); - - cancel_work_sync(&rbd_dev->acquired_lock_work); - cancel_work_sync(&rbd_dev->released_lock_work); - cancel_delayed_work_sync(&rbd_dev->lock_dwork); - cancel_work_sync(&rbd_dev->unlock_work); -} - /* * header_rwsem must not be held to avoid a deadlock with * rbd_dev_refresh() when flushing notifies. */ static void rbd_unregister_watch(struct rbd_device *rbd_dev) { - cancel_tasks_sync(rbd_dev); - mutex_lock(&rbd_dev->watch_mutex); if (rbd_dev->watch_state == RBD_WATCH_STATE_REGISTERED) __rbd_unregister_watch(rbd_dev); @@ -6541,10 +6529,18 @@ out_err: static void rbd_dev_image_unlock(struct rbd_device *rbd_dev) { + dout("%s rbd_dev %p\n", __func__, rbd_dev); + + disable_delayed_work_sync(&rbd_dev->lock_dwork); + disable_work_sync(&rbd_dev->unlock_work); + down_write(&rbd_dev->lock_rwsem); if (__rbd_is_lock_owner(rbd_dev)) __rbd_release_lock(rbd_dev); up_write(&rbd_dev->lock_rwsem); + + flush_work(&rbd_dev->acquired_lock_work); + flush_work(&rbd_dev->released_lock_work); } /* diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 84e1b637b4..8b260a31aa 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -883,7 +883,8 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, WARN_ON(!ops->direction_get) || WARN_ON(ops->measured_freq_get && (!dpll_device_ops(dpll)->freq_monitor_get || - !dpll_device_ops(dpll)->freq_monitor_set))) + !dpll_device_ops(dpll)->freq_monitor_set)) || + WARN_ON(ops->supported_ffo && !ops->ffo_get)) return -EINVAL; mutex_lock(&dpll_lock); diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 0ff1658c2d..6a4ddd746c 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -324,6 +324,30 @@ dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin, return 0; } +static int +dpll_msg_add_pin_operstate(struct sk_buff *msg, struct dpll_pin *pin, + struct dpll_pin_ref *ref, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + struct dpll_device *dpll = ref->dpll; + enum dpll_pin_operstate operstate; + int ret; + + if (!ops->operstate_on_dpll_get) + return 0; + ret = ops->operstate_on_dpll_get(pin, + dpll_pin_on_dpll_priv(dpll, pin), + dpll, dpll_priv(dpll), + &operstate, extack); + if (ret) + return ret; + if (nla_put_u32(msg, DPLL_A_PIN_OPERSTATE, operstate)) + return -EMSGSIZE; + + return 0; +} + static int dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, @@ -393,31 +417,34 @@ dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin, static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, + enum dpll_ffo_type type, struct netlink_ext_ack *extack) { const struct dpll_pin_ops *ops = dpll_pin_ops(ref); - struct dpll_device *dpll = ref->dpll; - s64 ffo; + struct dpll_ffo_param ffo = { .type = type }; int ret; - if (!ops->ffo_get) - return 0; - ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin), - dpll, dpll_priv(dpll), &ffo, extack); + /* RHEL: To maintain backward compatibility with older binary modules, + * we must accept a value of zero for .supported_ffo when the type is + * DPLL_FFO_PORT_RXTX_RATE. + */ + if (!ops->ffo_get || + !((ops->supported_ffo & BIT(type)) || + (!ops->supported_ffo && type == DPLL_FFO_PORT_RXTX_RATE))) + return 0; + ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(ref->dpll, pin), + ref->dpll, dpll_priv(ref->dpll), &ffo, extack); if (ret) { if (ret == -ENODATA) return 0; return ret; } - /* Put the FFO value in PPM to preserve compatibility with older - * programs. - */ - ret = nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, - div_s64(ffo, 1000000)); - if (ret) + if (nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, + div_s64(ffo.ffo, 1000000))) return -EMSGSIZE; - return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, - ffo); + return nla_put_sint(msg, + DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, + ffo.ffo); } static int dpll_msg_add_measured_freq(struct sk_buff *msg, struct dpll_pin *pin, @@ -650,6 +677,9 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, if (ret) goto nest_cancel; ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack); + if (ret) + goto nest_cancel; + ret = dpll_msg_add_pin_operstate(msg, pin, ref, extack); if (ret) goto nest_cancel; ret = dpll_msg_add_pin_prio(msg, pin, ref, extack); @@ -659,6 +689,10 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, if (ret) goto nest_cancel; ret = dpll_msg_add_phase_offset(msg, pin, ref, extack); + if (ret) + goto nest_cancel; + ret = dpll_msg_add_ffo(msg, pin, ref, + DPLL_FFO_PIN_DEVICE, extack); if (ret) goto nest_cancel; nla_nest_end(msg, attr); @@ -721,7 +755,8 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack); if (ret) return ret; - ret = dpll_msg_add_ffo(msg, pin, ref, extack); + ret = dpll_msg_add_ffo(msg, pin, ref, + DPLL_FFO_PORT_RXTX_RATE, extack); if (ret) return ret; ret = dpll_msg_add_measured_freq(msg, pin, ref, extack); diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index da92aa8f9b..268999ddbc 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -11,12 +11,15 @@ #include /* Common nested types */ -const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1] = { +const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1] = { [DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, }, [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), + [DPLL_A_PIN_OPERSTATE] = NLA_POLICY_RANGE(NLA_U32, 1, 4), [DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, }, + [DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET] = { .type = NLA_SINT, }, + [DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT] = { .type = NLA_SINT, }, }; const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = { diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h index 3da10cfe9a..8cf3b73c20 100644 --- a/drivers/dpll/dpll_nl.h +++ b/drivers/dpll/dpll_nl.h @@ -12,7 +12,7 @@ #include /* Common nested types */ -extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1]; +extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1]; extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1]; extern const struct nla_policy dpll_reference_sync_nl_policy[DPLL_A_PIN_STATE + 1]; diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c index 2f48ca2391..2fe3c3da84 100644 --- a/drivers/dpll/zl3073x/chan.c +++ b/drivers/dpll/zl3073x/chan.c @@ -18,6 +18,7 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index) { struct zl3073x_chan *chan = &zldev->chan[index]; + u64 val; int rc; rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index), @@ -25,8 +26,34 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index) if (rc) return rc; - return zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index), - &chan->refsel_status); + rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index), + &chan->refsel_status); + if (rc) + return rc; + + /* Read df_offset vs tracked reference */ + rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index), + ZL_DPLL_DF_READ_SEM); + if (rc) + return rc; + + rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index), + ZL_DPLL_DF_READ_SEM | ZL_DPLL_DF_READ_REF_OFST); + if (rc) + return rc; + + rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index), + ZL_DPLL_DF_READ_SEM); + if (rc) + return rc; + + rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val); + if (rc) + return rc; + + chan->df_offset = sign_extend64(val, 47); + + return 0; } /** diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h index 481da21332..4353809c69 100644 --- a/drivers/dpll/zl3073x/chan.h +++ b/drivers/dpll/zl3073x/chan.h @@ -17,6 +17,7 @@ struct zl3073x_dev; * @ref_prio: reference priority registers (4 bits per ref, P/N packed) * @mon_status: monitor status register value * @refsel_status: reference selection status register value + * @df_offset: frequency offset vs tracked reference in 2^-48 steps */ struct zl3073x_chan { struct_group(cfg, @@ -26,6 +27,7 @@ struct zl3073x_chan { struct_group(stat, u8 mon_status; u8 refsel_status; + s64 df_offset; ); }; @@ -37,6 +39,18 @@ int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index); +/** + * zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference + * @chan: pointer to channel state + * + * Return: frequency offset in 2^-48 steps + */ +static inline s64 +zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan) +{ + return chan->df_offset; +} + /** * zl3073x_chan_mode_get - get DPLL channel operating mode * @chan: pointer to channel state diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c index 024f0a27d2..7d2ad4b43a 100644 --- a/drivers/dpll/zl3073x/core.c +++ b/drivers/dpll/zl3073x/core.c @@ -704,44 +704,6 @@ zl3073x_ref_freq_meas_update(struct zl3073x_dev *zldev) return 0; } -/** - * zl3073x_ref_ffo_update - update reference fractional frequency offsets - * @zldev: pointer to zl3073x_dev structure - * - * The function asks device to latch the latest measured fractional - * frequency offset values, reads and stores them into the ref state. - * - * Return: 0 on success, <0 on error - */ -static int -zl3073x_ref_ffo_update(struct zl3073x_dev *zldev) -{ - int i, rc; - - rc = zl3073x_ref_freq_meas_latch(zldev, - ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF); - if (rc) - return rc; - - /* Read DPLL-to-REFx frequency offset measurements */ - for (i = 0; i < ZL3073X_NUM_REFS; i++) { - s32 value; - - /* Read value stored in units of 2^-32 signed */ - rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value); - if (rc) - return rc; - - /* Convert to ppt - * ffo = (10^12 * value) / 2^32 - * ffo = ( 5^12 * value) / 2^20 - */ - zldev->ref[i].ffo = mul_s64_u64_shr(value, 244140625, 20); - } - - return 0; -} - static void zl3073x_dev_periodic_work(struct kthread_work *work) { @@ -776,13 +738,6 @@ zl3073x_dev_periodic_work(struct kthread_work *work) } } - /* Update references' fractional frequency offsets */ - rc = zl3073x_ref_ffo_update(zldev); - if (rc) - dev_warn(zldev->dev, - "Failed to update fractional frequency offsets: %pe\n", - ERR_PTR(rc)); - list_for_each_entry(zldpll, &zldev->dplls, list) zl3073x_dpll_changes_check(zldpll); diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index 55195dcd21..6b714ec3b3 100644 --- a/drivers/dpll/zl3073x/dpll.c +++ b/drivers/dpll/zl3073x/dpll.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include #include @@ -38,7 +39,7 @@ * @prio: pin priority <0, 14> * @esync_control: embedded sync is controllable * @phase_gran: phase adjustment granularity - * @pin_state: last saved pin state + * @operstate: last saved operational state * @phase_offset: last saved pin phase offset * @freq_offset: last saved fractional frequency offset * @measured_freq: last saved measured frequency @@ -55,9 +56,9 @@ struct zl3073x_dpll_pin { u8 prio; bool esync_control; s32 phase_gran; - enum dpll_pin_state pin_state; + enum dpll_pin_operstate operstate; s64 phase_offset; - s64 freq_offset; + atomic64_t freq_offset; u32 measured_freq; }; @@ -295,11 +296,15 @@ zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin, static int zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, - s64 *ffo, struct netlink_ext_ack *extack) + struct dpll_ffo_param *ffo, + struct netlink_ext_ack *extack) { struct zl3073x_dpll_pin *pin = pin_priv; - *ffo = pin->freq_offset; + if (pin->operstate != DPLL_PIN_OPERSTATE_ACTIVE) + return -ENODATA; + + ffo->ffo = atomic64_read(&pin->freq_offset); return 0; } @@ -500,46 +505,41 @@ zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin, } /** - * zl3073x_dpll_ref_state_get - get status for given input pin + * zl3073x_dpll_ref_operstate_get - get operational state for input pin * @pin: pointer to pin - * @state: place to store status + * @operstate: place to store operational state * - * Checks current status for the given input pin and stores the value - * to @state. + * Returns the actual hardware state of the pin: whether it is actively + * used by the DPLL, has no signal, failed qualification, or is simply + * not in use. * * Return: 0 on success, <0 on error */ static int -zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin, - enum dpll_pin_state *state) +zl3073x_dpll_ref_operstate_get(struct zl3073x_dpll_pin *pin, + enum dpll_pin_operstate *operstate) { struct zl3073x_dpll *zldpll = pin->dpll; struct zl3073x_dev *zldev = zldpll->dev; - const struct zl3073x_chan *chan; - u8 ref; + const struct zl3073x_ref *ref; + u8 ref_id; - chan = zl3073x_chan_state_get(zldev, zldpll->id); - ref = zl3073x_input_pin_ref_get(pin->id); + ref_id = zl3073x_input_pin_ref_get(pin->id); - /* Check if the pin reference is connected */ - if (ref == zl3073x_dpll_connected_ref_get(zldpll)) { - *state = DPLL_PIN_STATE_CONNECTED; + /* Check if this pin is the currently locked reference */ + if (ref_id == zl3073x_dpll_connected_ref_get(zldpll)) { + *operstate = DPLL_PIN_OPERSTATE_ACTIVE; return 0; } - /* If the DPLL is running in automatic mode and the reference is - * selectable and its monitor does not report any error then report - * pin as selectable. - */ - if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO && - zl3073x_dev_ref_is_status_ok(zldev, ref) && - zl3073x_chan_ref_is_selectable(chan, ref)) { - *state = DPLL_PIN_STATE_SELECTABLE; - return 0; - } - - /* Otherwise report the pin as disconnected */ - *state = DPLL_PIN_STATE_DISCONNECTED; + /* Check reference monitor status */ + ref = zl3073x_ref_state_get(zldev, ref_id); + if (ref->mon_status & ZL_REF_MON_STATUS_LOS) + *operstate = DPLL_PIN_OPERSTATE_NO_SIGNAL; + else if (!zl3073x_ref_is_status_ok(ref)) + *operstate = DPLL_PIN_OPERSTATE_QUAL_FAILED; + else + *operstate = DPLL_PIN_OPERSTATE_STANDBY; return 0; } @@ -551,10 +551,48 @@ zl3073x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *dpll_pin, void *dpll_priv, enum dpll_pin_state *state, struct netlink_ext_ack *extack) +{ + struct zl3073x_dpll *zldpll = dpll_priv; + struct zl3073x_dpll_pin *pin = pin_priv; + const struct zl3073x_chan *chan; + u8 mode, ref; + + chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); + ref = zl3073x_input_pin_ref_get(pin->id); + mode = zl3073x_chan_mode_get(chan); + + switch (mode) { + case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: + if (ref == zl3073x_chan_ref_get(chan)) + *state = DPLL_PIN_STATE_CONNECTED; + else + *state = DPLL_PIN_STATE_DISCONNECTED; + break; + case ZL_DPLL_MODE_REFSEL_MODE_AUTO: + if (zl3073x_chan_ref_is_selectable(chan, ref)) + *state = DPLL_PIN_STATE_SELECTABLE; + else + *state = DPLL_PIN_STATE_DISCONNECTED; + break; + default: + *state = DPLL_PIN_STATE_DISCONNECTED; + break; + } + + return 0; +} + +static int +zl3073x_dpll_input_pin_operstate_on_dpll_get(const struct dpll_pin *dpll_pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_operstate *operstate, + struct netlink_ext_ack *extack) { struct zl3073x_dpll_pin *pin = pin_priv; - return zl3073x_dpll_ref_state_get(pin, state); + return zl3073x_dpll_ref_operstate_get(pin, operstate); } static int @@ -1241,6 +1279,7 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll, } static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { + .supported_ffo = BIT(DPLL_FFO_PIN_DEVICE), .direction_get = zl3073x_dpll_pin_direction_get, .esync_get = zl3073x_dpll_input_pin_esync_get, .esync_set = zl3073x_dpll_input_pin_esync_set, @@ -1248,6 +1287,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { .frequency_get = zl3073x_dpll_input_pin_frequency_get, .frequency_set = zl3073x_dpll_input_pin_frequency_set, .measured_freq_get = zl3073x_dpll_input_pin_measured_freq_get, + .operstate_on_dpll_get = zl3073x_dpll_input_pin_operstate_on_dpll_get, .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, .phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get, .phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set, @@ -1663,7 +1703,7 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin) * 2) For other pins use appropriate ref_phase register if the phase * monitor feature is enabled. */ - if (pin->pin_state == DPLL_PIN_STATE_CONNECTED) + if (pin->operstate == DPLL_PIN_OPERSTATE_ACTIVE) reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id); else if (zldpll->phase_monitor) reg = ZL_REG_REF_PHASE(ref_id); @@ -1695,37 +1735,29 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin) } /** - * zl3073x_dpll_pin_ffo_check - check for pin fractional frequency offset change + * zl3073x_dpll_pin_ffo_check - check for FFO change on active pin * @pin: pin to check * - * Check for the given pin's fractional frequency change. - * - * Return: true on fractional frequency offset change, false otherwise + * Return: true on change, false otherwise */ static bool zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin) { struct zl3073x_dpll *zldpll = pin->dpll; struct zl3073x_dev *zldev = zldpll->dev; - const struct zl3073x_ref *ref; - u8 ref_id; + const struct zl3073x_chan *chan; s64 ffo; - /* Get reference monitor status */ - ref_id = zl3073x_input_pin_ref_get(pin->id); - ref = zl3073x_ref_state_get(zldev, ref_id); - - /* Do not report ffo changes if the reference monitor report errors */ - if (!zl3073x_ref_is_status_ok(ref)) + if (pin->operstate != DPLL_PIN_OPERSTATE_ACTIVE) return false; - /* Compare with previous value */ - ffo = zl3073x_ref_ffo_get(ref); - if (pin->freq_offset != ffo) { - dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n", - pin->label, pin->freq_offset, ffo); - pin->freq_offset = ffo; + chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); + ffo = mul_s64_u64_shr(zl3073x_chan_df_offset_get(chan), + 244140625, 36); + if (atomic64_xchg(&pin->freq_offset, ffo) != ffo) { + dev_dbg(zldev->dev, "%s freq offset changed to: %lld\n", + pin->label, ffo); return true; } @@ -1828,7 +1860,7 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll) } list_for_each_entry(pin, &zldpll->pins, list) { - enum dpll_pin_state state; + enum dpll_pin_operstate operstate; bool pin_changed = false; /* Output pins change checks are not necessary because output @@ -1837,18 +1869,18 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll) if (!zl3073x_dpll_is_input_pin(pin)) continue; - rc = zl3073x_dpll_ref_state_get(pin, &state); + rc = zl3073x_dpll_ref_operstate_get(pin, &operstate); if (rc) { dev_err(dev, - "Failed to get %s on DPLL%u state: %pe\n", + "Failed to get %s on DPLL%u oper state: %pe\n", pin->label, zldpll->id, ERR_PTR(rc)); return; } - if (state != pin->pin_state) { - dev_dbg(dev, "%s state changed: %u->%u\n", pin->label, - pin->pin_state, state); - pin->pin_state = state; + if (operstate != pin->operstate) { + dev_dbg(dev, "%s oper state changed: %u->%u\n", + pin->label, pin->operstate, operstate); + pin->operstate = operstate; pin_changed = true; } diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h index 55e80e4f08..e140ca3ea1 100644 --- a/drivers/dpll/zl3073x/ref.h +++ b/drivers/dpll/zl3073x/ref.h @@ -22,7 +22,6 @@ struct zl3073x_dev; * @freq_ratio_n: FEC mode divisor * @sync_ctrl: reference sync control * @config: reference config - * @ffo: current fractional frequency offset * @meas_freq: measured input frequency in Hz * @mon_status: reference monitor status */ @@ -40,7 +39,6 @@ struct zl3073x_ref { u8 config; ); struct_group(stat, /* Status */ - s64 ffo; u32 meas_freq; u8 mon_status; ); @@ -58,18 +56,6 @@ int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index); int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult); -/** - * zl3073x_ref_ffo_get - get current fractional frequency offset - * @ref: pointer to ref state - * - * Return: the latest measured fractional frequency offset - */ -static inline s64 -zl3073x_ref_ffo_get(const struct zl3073x_ref *ref) -{ - return ref->ffo; -} - /** * zl3073x_ref_meas_freq_get - get measured input frequency * @ref: pointer to ref state diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h index d425dc6725..9578f00095 100644 --- a/drivers/dpll/zl3073x/regs.h +++ b/drivers/dpll/zl3073x/regs.h @@ -98,7 +98,14 @@ #define ZL_REG_REF_MON_STATUS(_idx) \ ZL_REG_IDX(_idx, 2, 0x02, 1, ZL3073X_NUM_REFS, 1) -#define ZL_REF_MON_STATUS_OK 0 /* all bits zeroed */ +#define ZL_REF_MON_STATUS_OK 0 +#define ZL_REF_MON_STATUS_LOS BIT(0) +#define ZL_REF_MON_STATUS_SCM BIT(1) +#define ZL_REF_MON_STATUS_CFM BIT(2) +#define ZL_REF_MON_STATUS_GST BIT(3) +#define ZL_REF_MON_STATUS_PFM BIT(4) +#define ZL_REF_MON_STATUS_ESYNC BIT(6) +#define ZL_REF_MON_STATUS_SPLIT_XO BIT(7) #define ZL_REG_DPLL_MON_STATUS(_idx) \ ZL_REG_IDX(_idx, 2, 0x10, 1, ZL3073X_MAX_CHANNELS, 1) @@ -157,6 +164,11 @@ #define ZL_DPLL_MODE_REFSEL_MODE_NCO 4 #define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4) +#define ZL_REG_DPLL_DF_READ(_idx) \ + ZL_REG_IDX(_idx, 5, 0x28, 1, ZL3073X_MAX_CHANNELS, 1) +#define ZL_DPLL_DF_READ_SEM BIT(4) +#define ZL_DPLL_DF_READ_REF_OFST BIT(3) + #define ZL_REG_DPLL_MEAS_CTRL ZL_REG(5, 0x50, 1) #define ZL_DPLL_MEAS_CTRL_EN BIT(0) #define ZL_DPLL_MEAS_CTRL_AVG_FACTOR GENMASK(7, 4) @@ -169,6 +181,16 @@ #define ZL_REG_DPLL_PHASE_ERR_DATA(_idx) \ ZL_REG_IDX(_idx, 5, 0x55, 6, ZL3073X_MAX_CHANNELS, 6) +/******************************* + * Register Pages 6-7, DPLL Data + *******************************/ + +#define ZL_REG_DPLL_DF_OFFSET_03(_idx) \ + ZL_REG_IDX(_idx, 6, 0x00, 6, 4, 0x20) +#define ZL_REG_DPLL_DF_OFFSET_4 ZL_REG(7, 0x00, 6) +#define ZL_REG_DPLL_DF_OFFSET(_idx) \ + ((_idx) < 4 ? ZL_REG_DPLL_DF_OFFSET_03(_idx) : ZL_REG_DPLL_DF_OFFSET_4) + /*********************************** * Register Page 9, Synth and Output ***********************************/ diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c index 1becc87791..e3c3c7edae 100644 --- a/drivers/infiniband/hw/mana/cq.c +++ b/drivers/infiniband/hw/mana/cq.c @@ -140,8 +140,9 @@ int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq) if (cq->queue.id >= gc->max_num_cqs) return -EINVAL; - /* Create CQ table entry */ - WARN_ON(gc->cq_table[cq->queue.id]); + /* Create CQ table entry, sharing a CQ between WQs is not supported */ + if (gc->cq_table[cq->queue.id]) + return -EINVAL; if (cq->queue.kmem) gdma_cq = cq->queue.kmem; else diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c index 48c1f4977f..8eb956ea43 100644 --- a/drivers/infiniband/hw/mana/qp.c +++ b/drivers/infiniband/hw/mana/qp.c @@ -21,6 +21,9 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, gc = mdev_to_gc(dev); + if (rx_hash_key_len > sizeof(req->hashkey)) + return -EINVAL; + req_buf_size = struct_size(req, indir_tab, MANA_INDIRECT_TABLE_DEF_SIZE); req = kzalloc(req_buf_size, GFP_KERNEL); if (!req) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 3177d4b9e3..a1785783b3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10731,12 +10731,10 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx, struct bnxt_ntuple_filter *ntp_fltr; int i; - if (netif_running(bp->dev)) { - bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic); - for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) { - if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID) - bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i); - } + bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic); + for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) { + if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID) + bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i); } if (!all) return; diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 7f94e84d09..02a95cf57b 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1756,6 +1756,27 @@ static int ibmveth_set_mac_addr(struct net_device *dev, void *p) return 0; } +static netdev_features_t ibmveth_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + /* Some physical adapters do not support segmentation offload with + * MSS < 224. Disable GSO for such packets to avoid adapter freeze. + * Note: Single-segment packets (gso_segs == 1) don't need this check + * as they bypass the LSO path and are transmitted without segmentation. + */ + if (skb_is_gso(skb)) { + if (skb_shinfo(skb)->gso_size < IBMVETH_MIN_LSO_MSS) { + netdev_warn_once(dev, + "MSS %u too small for LSO, disabling GSO\n", + skb_shinfo(skb)->gso_size); + features &= ~NETIF_F_GSO_MASK; + } + } + + return vlan_features_check(skb, features); +} + static const struct net_device_ops ibmveth_netdev_ops = { .ndo_open = ibmveth_open, .ndo_stop = ibmveth_close, @@ -1767,6 +1788,7 @@ static const struct net_device_ops ibmveth_netdev_ops = { .ndo_set_features = ibmveth_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = ibmveth_set_mac_addr, + .ndo_features_check = ibmveth_features_check, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ibmveth_poll_controller, #endif diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index dc8aae1309..059ca498b2 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -37,6 +37,7 @@ #define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL #define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL +#define IBMVETH_MIN_LSO_MSS 224 /* Minimum MSS for LSO */ /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 72c91bd174..60b32b4683 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2789,12 +2789,14 @@ void ice_vsi_set_napi_queues(struct ice_vsi *vsi) ASSERT_RTNL(); ice_for_each_rxq(vsi, q_idx) - netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX, - &vsi->rx_rings[q_idx]->q_vector->napi); + if (vsi->rx_rings[q_idx] && vsi->rx_rings[q_idx]->q_vector) + netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_RX, + &vsi->rx_rings[q_idx]->q_vector->napi); ice_for_each_txq(vsi, q_idx) - netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_TX, - &vsi->tx_rings[q_idx]->q_vector->napi); + if (vsi->tx_rings[q_idx] && vsi->tx_rings[q_idx]->q_vector) + netif_queue_set_napi(netdev, q_idx, NETDEV_QUEUE_TYPE_TX, + &vsi->tx_rings[q_idx]->q_vector->napi); /* Also set the interrupt number for the NAPI */ ice_for_each_q_vector(vsi, v_idx) { struct ice_q_vector *q_vector = vsi->q_vectors[v_idx]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 3981dd81d4..3756c02781 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -300,7 +300,8 @@ static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin, static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, - s64 *ffo, struct netlink_ext_ack *extack) + struct dpll_ffo_param *ffo, + struct netlink_ext_ack *extack) { struct mlx5_dpll_synce_status synce_status; struct mlx5_dpll *mdpll = pin_priv; @@ -309,10 +310,11 @@ static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv, err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status); if (err) return err; - return mlx5_dpll_pin_ffo_get(&synce_status, ffo); + return mlx5_dpll_pin_ffo_get(&synce_status, &ffo->ffo); } static const struct dpll_pin_ops mlx5_dpll_pins_ops = { + .supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE), .direction_get = mlx5_dpll_pin_direction_get, .state_on_dpll_get = mlx5_dpll_state_on_dpll_get, .state_on_dpll_set = mlx5_dpll_state_on_dpll_set, diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index f899bf692e..515df0012c 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -390,6 +390,19 @@ static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) { + /* + * Keep rcv_state at RECV_ERR even for the internal -ESHUTDOWN path. + * nvmet_tcp_handle_icreq() can return -ESHUTDOWN after the ICReq has + * already been consumed and queue teardown has started. + * + * If nvmet_tcp_data_ready() or nvmet_tcp_write_space() queues + * nvmet_tcp_io_work() again before nvmet_tcp_release_queue_work() + * cancels it, the queue must not keep that old receive state. + * Otherwise the next nvmet_tcp_io_work() run can reach + * nvmet_tcp_done_recv_pdu() and try to handle the same ICReq again. + * + * That is why queue->rcv_state needs to be updated before we return. + */ queue->rcv_state = NVMET_TCP_RECV_ERR; if (status == -EPIPE || status == -ECONNRESET) kernel_sock_shutdown(queue->sock, SHUT_RDWR); @@ -893,10 +906,25 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) iov.iov_base = icresp; iov.iov_len = sizeof(*icresp); ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); - if (ret < 0) + if (ret < 0) { + spin_lock_bh(&queue->state_lock); + if (queue->state == NVMET_TCP_Q_DISCONNECTING) { + spin_unlock_bh(&queue->state_lock); + return -ESHUTDOWN; + } + queue->state = NVMET_TCP_Q_FAILED; + spin_unlock_bh(&queue->state_lock); return ret; /* queue removal will cleanup */ + } + spin_lock_bh(&queue->state_lock); + if (queue->state == NVMET_TCP_Q_DISCONNECTING) { + spin_unlock_bh(&queue->state_lock); + /* Tell nvmet_tcp_socket_error() teardown is in progress. */ + return -ESHUTDOWN; + } queue->state = NVMET_TCP_Q_LIVE; + spin_unlock_bh(&queue->state_lock); nvmet_prepare_receive_pdu(queue); return 0; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index de8a250735..48ffeafa6b 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1585,6 +1585,15 @@ static ssize_t bindings_show(const struct bus_type *bus, char *buf) static BUS_ATTR_RO(bindings); +static ssize_t bindings_complete_count_show(const struct bus_type *bus, + char *buf) +{ + return sysfs_emit(buf, "%llu\n", + atomic64_read(&ap_bindings_complete_count)); +} + +static BUS_ATTR_RO(bindings_complete_count); + static ssize_t features_show(const struct bus_type *bus, char *buf) { int n = 0; @@ -1625,6 +1634,7 @@ static struct attribute *ap_bus_attrs[] = { &bus_attr_aqmask.attr, &bus_attr_scans.attr, &bus_attr_bindings.attr, + &bus_attr_bindings_complete_count.attr, &bus_attr_features.attr, NULL, }; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 0b41e8a066..faec66bd19 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2751,7 +2751,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, if (!elsio->u.els_logo.els_logo_pyld) { /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); - qla2x00_free_fcport(fcport); return QLA_FUNCTION_FAILED; } @@ -2776,7 +2775,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, if (rval != QLA_SUCCESS) { /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); - qla2x00_free_fcport(fcport); return QLA_FUNCTION_FAILED; } diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 8d0f4f2e96..a867792677 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -914,6 +914,12 @@ static void privcmd_close(struct vm_area_struct *vma) kfree(pages); } +static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr) +{ + /* Forbid splitting, avoids double free via privcmd_close(). */ + return -EINVAL; +} + static vm_fault_t privcmd_fault(struct vm_fault *vmf) { printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", @@ -925,6 +931,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf) static const struct vm_operations_struct privcmd_vm_ops = { .close = privcmd_close, + .may_split = privcmd_may_split, .fault = privcmd_fault }; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 66e5fd07e4..05f348c3b6 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -317,6 +317,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end) } } +static inline struct buffer_head * +metapath_dibh(struct metapath *mp) +{ + return mp->mp_bh[0]; +} + static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, unsigned int x, unsigned int h) { @@ -661,7 +667,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - struct buffer_head *dibh = mp->mp_bh[0]; + struct buffer_head *dibh = metapath_dibh(mp); u64 bn; unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; size_t dblks = iomap->length >> inode->i_blkbits; @@ -1116,10 +1122,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, goto out_unlock; break; default: - goto out_unlock; + goto out; } ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); + if (ret) + goto out_unlock; + +out: + if (iomap->type == IOMAP_INLINE) { + iomap->private = metapath_dibh(&mp); + get_bh(iomap->private); + } out_unlock: release_metapath(&mp); @@ -1133,6 +1147,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); + if (iomap->private) + brelse(iomap->private); + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { case IOMAP_WRITE: if (flags & IOMAP_DIRECT) diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 7f8fa58662..4a8854a645 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -71,6 +71,22 @@ struct dpll_device_ops { RH_KABI_RESERVE(10) }; +enum dpll_ffo_type { + DPLL_FFO_PORT_RXTX_RATE, + DPLL_FFO_PIN_DEVICE, + + __DPLL_FFO_TYPE_MAX, +}; + +/* RHEL: we have to keep 'ffo' field to be first to preserve compatibility + * with older .ffo_get() callbacks that accepts 's64 *' as parameter instead + * of 'struct dpll_ffo_param *' + */ +struct dpll_ffo_param { + s64 ffo; + enum dpll_ffo_type type; +}; + struct dpll_pin_ops { int (*frequency_set)(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, @@ -124,9 +140,13 @@ struct dpll_pin_ops { const struct dpll_device *dpll, void *dpll_priv, const s32 phase_adjust, struct netlink_ext_ack *extack); - int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv, + RH_KABI_REPLACE(int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, - s64 *ffo, struct netlink_ext_ack *extack); + s64 *ffo, struct netlink_ext_ack *extack), + int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + struct dpll_ffo_param *ffo, + struct netlink_ext_ack *extack)) int (*esync_set)(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 freq, struct netlink_ext_ack *extack); @@ -149,8 +169,13 @@ struct dpll_pin_ops { const struct dpll_device *dpll, void *dpll_priv, u64 *measured_freq, struct netlink_ext_ack *extack)) - RH_KABI_RESERVE(2) - RH_KABI_RESERVE(3) + RH_KABI_USE(2, int (*operstate_on_dpll_get)(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_operstate *operstate, + struct netlink_ext_ack *extack)) + RH_KABI_USE(3, unsigned long supported_ffo) RH_KABI_RESERVE(4) RH_KABI_RESERVE(5) RH_KABI_RESERVE(6) diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h index 83fe399317..a26d4cd3b8 100644 --- a/include/net/tc_act/tc_pedit.h +++ b/include/net/tc_act/tc_pedit.h @@ -14,7 +14,6 @@ struct tcf_pedit_key_ex { struct tcf_pedit_parms { struct tc_pedit_key *tcfp_keys; struct tcf_pedit_key_ex *tcfp_keys_ex; - u32 tcfp_off_max_hint; unsigned char tcfp_nkeys; unsigned char tcfp_flags; struct rcu_head rcu; diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 93614ccd8a..aa45b79473 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -177,6 +177,28 @@ enum dpll_pin_state { DPLL_PIN_STATE_MAX = (__DPLL_PIN_STATE_MAX - 1) }; +/** + * enum dpll_pin_operstate - defines possible operational states of a pin with + * respect to its parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE + * attribute + * @DPLL_PIN_OPERSTATE_ACTIVE: pin is qualified and actively used by the DPLL + * @DPLL_PIN_OPERSTATE_STANDBY: pin is qualified but not actively used by the + * DPLL + * @DPLL_PIN_OPERSTATE_NO_SIGNAL: pin does not have a valid signal + * @DPLL_PIN_OPERSTATE_QUAL_FAILED: pin signal failed qualification (e.g. + * frequency or phase monitor) + */ +enum dpll_pin_operstate { + DPLL_PIN_OPERSTATE_ACTIVE = 1, + DPLL_PIN_OPERSTATE_STANDBY, + DPLL_PIN_OPERSTATE_NO_SIGNAL, + DPLL_PIN_OPERSTATE_QUAL_FAILED, + + /* private: */ + __DPLL_PIN_OPERSTATE_MAX, + DPLL_PIN_OPERSTATE_MAX = (__DPLL_PIN_OPERSTATE_MAX - 1) +}; + /** * enum dpll_pin_capabilities - defines possible capabilities of a pin, valid * flags on DPLL_A_PIN_CAPABILITIES attribute @@ -256,6 +278,7 @@ enum dpll_a_pin { DPLL_A_PIN_PHASE_ADJUST_GRAN, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, DPLL_A_PIN_MEASURED_FREQUENCY, + DPLL_A_PIN_OPERSTATE, __DPLL_A_PIN_MAX, DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) diff --git a/kernel.sbat b/kernel.sbat index 9319e0785b..3432f3e0b5 100644 --- a/kernel.sbat +++ b/kernel.sbat @@ -1,3 +1,3 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.15.1.el9.x86_64,mailto:secalert@redhat.com -kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.15.1.el9.x86_64,mailto:security@almalinux.org +kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.17.1.el9.x86_64,mailto:secalert@redhat.com +kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.17.1.el9.x86_64,mailto:security@almalinux.org diff --git a/kernel/exit.c b/kernel/exit.c index aa08b46879..6a1081a7b5 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -959,6 +959,7 @@ void __noreturn make_task_dead(int signr) futex_exit_recursive(tsk); tsk->exit_state = EXIT_DEAD; refcount_inc(&tsk->rcu_users); + preempt_disable(); do_task_dead(); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f5054bb9eb..262a918288 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5418,9 +5418,11 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev, void *data, bt_dev_dbg(hdev, ""); + hci_dev_lock(hdev); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (!conn) - return; + goto unlock; conn->passkey_notify = __le32_to_cpu(ev->passkey); conn->passkey_entered = 0; @@ -5429,6 +5431,9 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev, void *data, mgmt_user_passkey_notify(hdev, &conn->dst, conn->type, conn->dst_type, conn->passkey_notify, conn->passkey_entered); + +unlock: + hci_dev_unlock(hdev); } static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data, @@ -5439,14 +5444,16 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data, bt_dev_dbg(hdev, ""); + hci_dev_lock(hdev); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (!conn) - return; + goto unlock; switch (ev->type) { case HCI_KEYPRESS_STARTED: conn->passkey_entered = 0; - return; + goto unlock; case HCI_KEYPRESS_ENTERED: conn->passkey_entered++; @@ -5461,13 +5468,16 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data, break; case HCI_KEYPRESS_COMPLETED: - return; + goto unlock; } if (hci_dev_test_flag(hdev, HCI_MGMT)) mgmt_user_passkey_notify(hdev, &conn->dst, conn->type, conn->dst_type, conn->passkey_notify, conn->passkey_entered); + +unlock: + hci_dev_unlock(hdev); } static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data, diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index e302afc781..b5712789e9 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -7126,7 +7126,8 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) static int hci_le_big_create_sync(struct hci_dev *hdev, void *data) { - DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis, 0x11); + DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis, + HCI_MAX_ISO_BIS); struct hci_conn *conn = data; struct bt_iso_qos *qos = &conn->iso_qos; int err; diff --git a/net/can/isotp.c b/net/can/isotp.c index 7363470473..311f0af498 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1229,12 +1229,6 @@ static int isotp_release(struct socket *sock) so->ifindex = 0; so->bound = 0; - if (so->rx.buf != so->rx.sbuf) - kfree(so->rx.buf); - - if (so->tx.buf != so->tx.sbuf) - kfree(so->tx.buf); - sock_orphan(sk); sock->sk = NULL; @@ -1602,6 +1596,21 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg, return NOTIFY_DONE; } +static void isotp_sock_destruct(struct sock *sk) +{ + struct isotp_sock *so = isotp_sk(sk); + + /* do the standard CAN sock destruct work */ + can_sock_destruct(sk); + + /* free potential extended PDU buffers */ + if (so->rx.buf != so->rx.sbuf) + kfree(so->rx.buf); + + if (so->tx.buf != so->tx.sbuf) + kfree(so->tx.buf); +} + static int isotp_init(struct sock *sk) { struct isotp_sock *so = isotp_sk(sk); @@ -1648,6 +1657,9 @@ static int isotp_init(struct sock *sk) list_add_tail(&so->notifier, &isotp_notifier_list); spin_unlock(&isotp_notifier_lock); + /* re-assign default can_sock_destruct() reference */ + sk->sk_destruct = isotp_sock_destruct; + return 0; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e185f2a39a..7ba68a0982 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8890,7 +8890,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss = (void *)cbss->priv; struct sta_info *new_sta = NULL; struct ieee80211_link_data *link; - bool have_sta = false; + struct sta_info *have_sta = NULL; bool mlo; int err; u16 new_links; @@ -8909,11 +8909,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, mlo = false; } - if (assoc) { - rcu_read_lock(); + if (assoc) have_sta = sta_info_get(sdata, ap_mld_addr); - rcu_read_unlock(); - } if (mlo && !have_sta && WARN_ON(sdata->vif.valid_links || sdata->vif.active_links)) @@ -9072,6 +9069,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, out_release_chan: ieee80211_link_release_channel(link); out_err: + if (mlo && have_sta) + WARN_ON(__sta_info_destroy(have_sta)); ieee80211_vif_set_links(sdata, 0, 0); return err; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4e34435f33..02f131563d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -4819,7 +4819,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, struct sk_buff *skb = rx->skb; struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - static ieee80211_rx_result res; + ieee80211_rx_result res; int orig_len = skb->len; int hdrlen = ieee80211_hdrlen(hdr->frame_control); int snap_offs = hdrlen; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c9931537f9..62e1a37849 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3565,11 +3565,11 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy, struct ieee80211_local *local = container_of(work, struct ieee80211_local, radar_detected_work); struct cfg80211_chan_def chandef; - struct ieee80211_chanctx *ctx; + struct ieee80211_chanctx *ctx, *tmp; lockdep_assert_wiphy(local->hw.wiphy); - list_for_each_entry(ctx, &local->chanctx_list, list) { + list_for_each_entry_safe(ctx, tmp, &local->chanctx_list, list) { if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) continue; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index fae51f3fc1..a8d345c85c 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -4248,6 +4248,8 @@ int __init mptcp_proto_v6_init(void) { int err; + mptcp_subflow_v6_init(); + mptcp_v6_prot = mptcp_prot; strscpy(mptcp_v6_prot.name, "MPTCPv6", sizeof(mptcp_v6_prot.name)); mptcp_v6_prot.slab = NULL; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index fc9ad562cf..161ed3cf1f 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -794,6 +794,7 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk, void __init mptcp_proto_init(void); #if IS_ENABLED(CONFIG_MPTCP_IPV6) int __init mptcp_proto_v6_init(void); +void __init mptcp_subflow_v6_init(void); #endif struct sock *mptcp_sk_clone_init(const struct sock *sk, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index a37c9cb456..b6cd4d5d35 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -2103,7 +2103,15 @@ void __init mptcp_subflow_init(void) tcp_prot_override.release_cb = tcp_release_cb_override; tcp_prot_override.diag_destroy = tcp_abort_override; + mptcp_diag_subflow_init(&subflow_ulp_ops); + + if (tcp_register_ulp(&subflow_ulp_ops) != 0) + panic("MPTCP: failed to register subflows to ULP\n"); +} + #if IS_ENABLED(CONFIG_MPTCP_IPV6) +void __init mptcp_subflow_v6_init(void) +{ /* In struct mptcp_subflow_request_sock, we assume the TCP request sock * structures for v4 and v6 have the same size. It should not changed in * the future but better to make sure to be warned if it is no longer @@ -2139,10 +2147,5 @@ void __init mptcp_subflow_init(void) tcpv6_prot_override = tcpv6_prot; tcpv6_prot_override.release_cb = tcp_release_cb_override; tcpv6_prot_override.diag_destroy = tcp_abort_override; -#endif - - mptcp_diag_subflow_init(&subflow_ulp_ops); - - if (tcp_register_ulp(&subflow_ulp_ops) != 0) - panic("MPTCP: failed to register subflows to ULP\n"); } +#endif diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index fc0a35a7b6..495cc56c3a 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include static struct tc_action_ops act_pedit_ops; @@ -242,7 +244,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, goto out_free_ex; } - nparms->tcfp_off_max_hint = 0; nparms->tcfp_flags = parm->flags; nparms->tcfp_nkeys = parm->nkeys; @@ -268,14 +269,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, BITS_PER_TYPE(int) - 1, nparms->tcfp_keys[i].shift); - /* The AT option can read a single byte, we can bound the actual - * value with uchar max. - */ - cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift; - - /* Each key touches 4 bytes starting from the computed offset */ - nparms->tcfp_off_max_hint = - max(nparms->tcfp_off_max_hint, cur + 4); } p = to_pedit(*a); @@ -318,15 +311,12 @@ static void tcf_pedit_cleanup(struct tc_action *a) call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); } -static bool offset_valid(struct sk_buff *skb, int offset) +static bool offset_valid(struct sk_buff *skb, int offset, int len) { - if (offset > 0 && offset > skb->len) + if (offset < -(int)skb_headroom(skb)) return false; - if (offset < 0 && -offset > skb_headroom(skb)) - return false; - - return true; + return offset <= (int)skb->len - len; } static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type) @@ -393,18 +383,10 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, struct tcf_pedit_key_ex *tkey_ex; struct tcf_pedit_parms *parms; struct tc_pedit_key *tkey; - u32 max_offset; int i; parms = rcu_dereference_bh(p->parms); - max_offset = (skb_transport_header_was_set(skb) ? - skb_transport_offset(skb) : - skb_network_offset(skb)) + - parms->tcfp_off_max_hint; - if (skb_ensure_writable(skb, min(skb->len, max_offset))) - goto done; - tcf_lastuse_update(&p->tcf_tm); tcf_action_update_bstats(&p->common, skb); @@ -412,10 +394,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, tkey_ex = parms->tcfp_keys_ex; for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { + int write_offset, write_len; int offset = tkey->off; int hoffset = 0; - u32 *ptr, hdata; - u32 val; + u32 cur_val, val; + u32 *ptr; int rc; if (tkey_ex) { @@ -433,13 +416,15 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, if (tkey->offmask) { u8 *d, _d; + int at_offset; - if (!offset_valid(skb, hoffset + tkey->at)) { + if (check_add_overflow(hoffset, (int)tkey->at, &at_offset) || + !offset_valid(skb, at_offset, sizeof(_d))) { pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n", hoffset + tkey->at); goto bad; } - d = skb_header_pointer(skb, hoffset + tkey->at, + d = skb_header_pointer(skb, at_offset, sizeof(_d), &_d); if (!d) goto bad; @@ -451,31 +436,51 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, } } - if (!offset_valid(skb, hoffset + offset)) { - pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset); + if (check_add_overflow(hoffset, offset, &write_offset)) { + pr_info_ratelimited("tc action pedit offset overflow\n"); goto bad; } - ptr = skb_header_pointer(skb, hoffset + offset, - sizeof(hdata), &hdata); - if (!ptr) + if (!offset_valid(skb, write_offset, sizeof(*ptr))) { + pr_info_ratelimited("tc action pedit offset %d out of bounds\n", + write_offset); goto bad; + } + + if (write_offset < 0) { + if (skb_cow(skb, -write_offset)) + goto bad; + if (write_offset + (int)sizeof(*ptr) > 0) { + if (skb_ensure_writable(skb, + min_t(int, skb->len, + write_offset + (int)sizeof(*ptr)))) + goto bad; + } + } else { + if (check_add_overflow(write_offset, (int)sizeof(*ptr), + &write_len)) + goto bad; + if (skb_ensure_writable(skb, min_t(int, skb->len, + write_len))) + goto bad; + } + + ptr = (u32 *)(skb->data + write_offset); + cur_val = get_unaligned(ptr); /* just do it, baby */ switch (cmd) { case TCA_PEDIT_KEY_EX_CMD_SET: val = tkey->val; break; case TCA_PEDIT_KEY_EX_CMD_ADD: - val = (*ptr + tkey->val) & ~tkey->mask; + val = (cur_val + tkey->val) & ~tkey->mask; break; default: pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd); goto bad; } - *ptr = ((*ptr & tkey->mask) ^ val); - if (ptr == &hdata) - skb_store_bits(skb, hoffset + offset, ptr, 4); + put_unaligned((cur_val & tkey->mask) ^ val, ptr); } goto done; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index fc6c0cce5f..d30d1d49dc 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -275,8 +275,8 @@ static inline bool has_tx_length_quirk(struct snd_usb_audio *chip) return chip->quirk_flags & QUIRK_FLAG_TX_LENGTH; } -static void prepare_silent_urb(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *ctx) +static int prepare_silent_urb(struct snd_usb_endpoint *ep, + struct snd_urb_ctx *ctx) { struct urb *urb = ctx->urb; unsigned int offs = 0; @@ -289,28 +289,34 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep, extra = sizeof(packet_length); for (i = 0; i < ctx->packets; ++i) { - unsigned int offset; - unsigned int length; - int counts; + int length; - counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0); - length = counts * ep->stride; /* number of silent bytes */ - offset = offs * ep->stride + extra * i; - urb->iso_frame_desc[i].offset = offset; + length = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0); + if (length < 0) + return length; + length *= ep->stride; /* number of silent bytes */ + if (offs + length + extra > ctx->buffer_size) + break; + urb->iso_frame_desc[i].offset = offs; urb->iso_frame_desc[i].length = length + extra; if (extra) { packet_length = cpu_to_le32(length); - memcpy(urb->transfer_buffer + offset, + memcpy(urb->transfer_buffer + offs, &packet_length, sizeof(packet_length)); + offs += extra; } - memset(urb->transfer_buffer + offset + extra, + memset(urb->transfer_buffer + offs, ep->silence_value, length); - offs += counts; + offs += length; } - urb->number_of_packets = ctx->packets; - urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra; + if (!offs) + return -EPIPE; + + urb->number_of_packets = i; + urb->transfer_buffer_length = offs; ctx->queued = 0; + return 0; } /* @@ -332,8 +338,7 @@ static int prepare_outbound_urb(struct snd_usb_endpoint *ep, if (data_subs && ep->prepare_data_urb) return ep->prepare_data_urb(data_subs, urb, in_stream_lock); /* no data provider, so send silence */ - prepare_silent_urb(ep, ctx); - break; + return prepare_silent_urb(ep, ctx); case SND_USB_ENDPOINT_TYPE_SYNC: if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {