6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 806/1376 wifi: mt76: mt7996: fix capability of EHT-MCS 15 in MRU
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shayne Chen <[email protected]>
[ Upstream commit 29e889c4ada83c69d10a3937f5ae2934306e2e3d ]
According to the definition in IEEE Std 802.11be-2024, Table 9-417r:
- If 80 MHz is not supported, bit 1-3 are set to 0.
- If 160 MHz is not supported, bit 2-3 are set to 0.
- If 320 MHz is not supported, bit 3 is set to 0.
--- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/init.c +10 -6
@@ -1181,7 +1181,6 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap;struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;struct ieee80211_eht_mcs_nss_supp *eht_nss = &eht_cap->eht_mcs_nss_supp; -enum nl80211_chan_width width = phy->mt76->chandef.width;int nss =hweight8 (phy->mt76->antenna_mask);int sts =hweight16 (phy->mt76->chainmask);u8 val;
@@ -1250,11 +1249,16 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,u8_encode_bits (u8_get_bits (1 ,GENMASK (1 ,0 )),IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK ); - val = width ==NL80211_CHAN_WIDTH_320 ?0xf : - width ==NL80211_CHAN_WIDTH_160 ?0x7 : - width ==NL80211_CHAN_WIDTH_80 ?0x3 :0x1 ; - eht_cap_elem->phy_cap_info[6 ] = -u8_encode_bits (val,IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK ); + eht_cap_elem->phy_cap_info[6 ] =IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK ; +if (band !=NL80211_BAND_6GHZ ) { + eht_cap_elem->phy_cap_info[6 ] &= + ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ ; + +if (band !=NL80211_BAND_5GHZ ) + eht_cap_elem->phy_cap_info[6 ] &= + ~(IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ | +IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ ); + } val =u8_encode_bits (nss,IEEE80211_EHT_MCS_NSS_RX ) |u8_encode_bits (nss,IEEE80211_EHT_MCS_NSS_TX );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 807/1376 wifi: mt76: fix non-AQL packet accounting for MLO stations
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael-CY Lee <[email protected]>
[ Upstream commit 8ae659743ba936b22ecb4620815887728e2820d6 ]
__mt76_tx_queue_skb() overrides the wcid passed by the driver with sta->drv_priv, so the wcid might incorrectly be changed after TX, causing wcid->non_aql_packets to be counted on the wrong wcid. For example, on the AP side, if a station's setup link is the 5G link and the station uses 2G to transmit a frame, the value of non_aql_packets is increased on the 5G wcid but decreased on the 2G wcid. Once the inflated counter exceeds MT_MAX_NON_AQL_PKT, the TX scheduler permanently refuses to service the station.
Drop the reassignment and account on the wcid used for transmission. This also records the actual wcid in the queue entry.
--- drivers/net/wireless/mediatek/mt76/tx.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/net/wireless/mediatek/mt76/tx.c +0 -4
@@ -313,10 +313,6 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,if (idx <0 || !sta)return idx; - wcid = (struct mt76_wcid *)sta->drv_priv; -if (!wcid->sta) -return idx; - q->entry[idx].wcid = wcid->idx;if (!non_aql)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 808/1376 wifi: mt76: mt7996: validate RX band_idx before dereferencing phys[]
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 2243778a5fae8329ab5f18e7adcd7e03b911a1b7 ]
band_idx comes from a 2-bit descriptor field (0-3) and was used directly to index dev->mt76.phys[] (size __MT_MAX_BAND == 3) and dereference the result. A corrupt or reserved descriptor value could index out of bounds or hit a NULL phy on parts with fewer bands. Reject invalid band indices, mirroring mt7996_rx_get_wcid().
--- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +6 -0
@@ -454,7 +454,13 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,memset (status,0 ,sizeof (*status)); band_idx =FIELD_GET (MT_RXD1_NORMAL_BAND_IDX , rxd1); +if (!mt7996_band_valid (dev, band_idx)) +return -EINVAL ; + mphy = dev->mt76.phys[band_idx]; +if (!mphy) +return -EINVAL ; + phy = mphy->priv; status->phy_idx = mphy->band_idx;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 809/1376 wifi: mt76: mt7996: set MT76_MCU_RESET before waking MCU waiters on full reset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 6469ae71e7e5d0132c934972f628f346ad0379cd ]
mt7996_mac_full_reset() called wake_up(&dev->mt76.mcu.wait) without first setting MT76_MCU_RESET. The MCU response wait condition only checks the response queue and that bit, so the wake-up released nobody: a thread blocked in an MCU command against the dead firmware (typically holding dev->mt76.mutex) stayed asleep until its multi-second timeout, stalling recovery. Set the bit before the wake-up, as mt7915 does.
--- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/mediatek/mt76/mt7996/mac.c +1 -0
@@ -1798,6 +1798,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) phy3 =mt7996_phy3 (dev); dev->recovery.hw_full_reset = true; +set_bit (MT76_MCU_RESET , &dev->mphy.state);wake_up (&dev->mt76.mcu.wait);ieee80211_stop_queues (mt76_hw (dev));if (phy2)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 810/1376 wifi: mt76: mt7915: clear wcid mask under mutex after RCU pointer clear
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 6486e11a6e2f679597af2d5bb48c3b07a2b2a7ba ]
mt7915_remove_interface() cleared the wcid mask bit with no lock held and before clearing the RCU wcid pointer. The mask is a non-atomic RMW shared with the allocators, which all run under dev->mt76.mutex; on DBDC the two wiphys share one mt76_dev, so this raced add_interface/sta_add on the other band and could leak or double-hand-out a wcid. Clearing the bit before the RCU pointer also let a concurrent allocation reuse the index and publish its wcid, which the subsequent NULL assignment then wiped. Move the clear into the existing mutex section, after the RCU pointer is cleared.
--- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/main.c +1 -1
@@ -296,7 +296,6 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,mt7915_mcu_add_bss_info (phy, vif, false);mt7915_mcu_add_sta (dev, vif,NULL ,CONN_STATE_DISCONNECT , false); -mt76_wcid_mask_clear (dev->mt76.wcid_mask, mvif->sta.wcid.idx);mutex_lock (&dev->mt76.mutex);mt76_testmode_reset (phy->mt76, true);
@@ -312,6 +311,7 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,mutex_lock (&dev->mt76.mutex); dev->mt76.vif_mask &= ~BIT_ULL (mvif->mt76.idx); phy->omac_mask &= ~BIT_ULL (mvif->mt76.omac_idx); +mt76_wcid_mask_clear (dev->mt76.wcid_mask, mvif->sta.wcid.idx);mutex_unlock (&dev->mt76.mutex);spin_lock_bh (&dev->mt76.sta_poll_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 811/1376 wifi: mt76: mt7915: avoid nss underflow in mt7915_mcu_get_sta_nss
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 4a2f4be532e3ea4e2b536e411793a05aaa51af25 ]
If a peer's VHT/HE MCS map has no supported spatial stream (all fields 0x3), the loop exits with nss == 0 and the function returned (u8)-1 (255), which was then written into the firmware sta_rec_bf beamforming fields. Clamp the result to 0.
--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +1 -1
@@ -51,7 +51,7 @@ mt7915_mcu_get_sta_nss(u16 mcs_map)break ; } -return nss -1 ; +return nss ? nss -1 :0 ; } static void
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 812/1376 wifi: mt76: mt7996: dont report a zero TX bitrate
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit d4d92ccded678c92c390003926097ddbb6516bc7 ]
mt7996_sta_statistics() set NL80211_STA_INFO_TX_BITRATE unconditionally after the block that already sets it, so a station with no rate info yet was reported to userspace with a valid-but-zero TX rate. Drop the redundant unconditional assignments; the in-block ones are sufficient.
--- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 -- 1 file changed, 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/main.c +0 -2
@@ -1014,8 +1014,6 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.flags = txrate->flags; sinfo->filled |=BIT_ULL (NL80211_STA_INFO_TX_BITRATE ); } - sinfo->txrate.flags = txrate->flags; - sinfo->filled |=BIT_ULL (NL80211_STA_INFO_TX_BITRATE ); sinfo->tx_failed = msta->wcid.stats.tx_failed; sinfo->filled |=BIT_ULL (NL80211_STA_INFO_TX_FAILED );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 813/1376 wifi: mt76: mt7915: write RX header translation bit to the correct register
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 236145737480c4c0c515e09061d0d5f77cf52d3f ]
MT_MDP_DCR0_RX_HDR_TRANS_EN is a field of MT_MDP_DCR0, but monitor-mode handling applied it to the per-band MT_DMA_DCR0 register instead. As a result RX header translation was never disabled in the MDP when entering monitor mode, and an undocumented bit of MT_DMA_DCR0 was toggled. Target MT_MDP_DCR0, matching the mt7996 driver.
--- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/main.c +1 -1
@@ -490,7 +490,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)mt76_rmw_field (dev,MT_DMA_DCR0 (band),MT_DMA_DCR0_RXD_G5_EN , enabled); -mt76_rmw_field (dev,MT_DMA_DCR0 (band),MT_MDP_DCR0_RX_HDR_TRANS_EN , +mt76_rmw_field (dev,MT_MDP_DCR0 ,MT_MDP_DCR0_RX_HDR_TRANS_EN , !dev->monitor_mask);mt76_testmode_reset (phy->mt76, true);mt76_wr (dev,MT_WF_RFCR (band), rxfilter);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 814/1376 wifi: mt76: fix stranded frames in mt76_txq_schedule_pending
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 422dd2db28ae27c35a586acd9ad482f30000c090 ]
A wcid is added to phy->tx_list whenever either tx_pending or tx_offchannel becomes non-empty, but the requeue check after a partial schedule required BOTH queues to be non-empty. When mt76_txq_schedule_pending_wcid() returns -1 (queue stopped or MT76_RESET) it leaves frames in tx_pending while tx_offchannel is empty, so the wcid is dropped from every scheduling list and its frames stall until the next mt76_tx() for that wcid or wcid cleanup. This strands EAPOL/mgmt/nullfunc frames under momentary queue-full or across scan/channel-switch, causing association and 4-way-handshake timeouts.
Requeue when either queue still holds frames, matching the enqueue condition.
--- drivers/net/wireless/mediatek/mt76/tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/tx.c +2 -2
@@ -664,8 +664,8 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) ret =mt76_txq_schedule_pending_wcid (phy, wcid, &wcid->tx_pending);spin_lock (&phy->tx_lock); -if (!skb_queue_empty (&wcid->tx_pending) && - !skb_queue_empty (&wcid->tx_offchannel) && +if ((!skb_queue_empty (&wcid->tx_pending) || + !skb_queue_empty (&wcid->tx_offchannel)) &&list_empty (&wcid->tx_list))list_add_tail (&wcid->tx_list, &phy->tx_list); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 815/1376 wifi: mt76: mt7915: poll the correct SLP CTRL register for the second adie
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit dd59a6126a8f1bd52bf6bd057bf0c8307f76a74b ]
The clock enable path for the second adie sets MT_ADIE_SLP_CTRL_CK0(1) but polled the busy bit of MT_ADIE_SLP_CTRL_CK0(0), so dual-adie bring-up could proceed before the adie1 clock was stable.
--- drivers/net/wireless/mediatek/mt76/mt7915/soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/soc.c +1 -1
@@ -913,7 +913,7 @@ static void mt7986_wmac_clock_enable(struct mt7915_dev *dev, u32 adie_type)read_poll_timeout (mt76_rr, cur, !(cur &MT_SLP_CTRL_BSY_MASK ),USEC_PER_MSEC ,50 *USEC_PER_MSEC , false, - dev,MT_ADIE_SLP_CTRL_CK0 (0 )); + dev,MT_ADIE_SLP_CTRL_CK0 (1 )); }mt76_wmac_spi_unlock (dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 816/1376 wifi: mt76: check txfree done event on the WED hw path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rex Lu <[email protected]>
[ Upstream commit 3310e71a74b176d3613dfb42b6bc630d99e90cbb ]
Check the txfree done event DW1 bit 15 when WED is enabled, to avoid the driver reading a txfree done event before WED has finished reading it. No need to check this flag on WED v2, otherwise SER will occur.
The bit position was previously defined as MT_DMA_CTL_BURST, which is unused; rename it to match its function on the txfree ring.
--- drivers/net/wireless/mediatek/mt76/dma.c | 9 +++++++++ drivers/net/wireless/mediatek/mt76/dma.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/dma.c +9 -0
@@ -490,6 +490,15 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, q->desc[idx].ctrl |=cpu_to_le32 (MT_DMA_CTL_DMA_DONE ); else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE)))return NULL ; +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +/* on WED v3 the M_DONE bit signals that WED is done reading +* the txfree descriptor; WED v2 does not set it +*/ + else if (dev->mmio.wed.version > 2 && + mt76_queue_is_wed_tx_free(q) && + !(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_M_DONE))) +return NULL ; +#endif } q->tail = (q->tail +1 ) % q->ndesc;
drivers/net/wireless/mediatek/mt76/dma.h +1 -1
@@ -11,7 +11,7 @@#define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0)#define MT_DMA_CTL_LAST_SEC1 BIT(14) -#define MT_DMA_CTL_BURST BIT(15) +#define MT_DMA_CTL_M_DONE BIT(15)#define MT_DMA_CTL_SD_LEN0 GENMASK(29, 16)#define MT_DMA_CTL_LAST_SEC0 BIT(30)#define MT_DMA_CTL_DMA_DONE BIT(31)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 817/1376 wifi: mt76: mt7996: bound TLV walk in mt7996_mcu_get_chip_config
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 44af52467e72094351a362bf69effd52f1d9c186 ]
The response TLV loop advanced by tlv->len without a minimum, so a theoretical firmware response containing a zero-length TLV could spin forever, hanging the CPU during device probe.
The u32 payload was also read without bounds checking. Reject a short fixed field, stop on a TLV whose length underruns the header or overruns the skb.
--- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +13 -3
@@ -3651,21 +3651,31 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap)return ret;/* fixed field */ +if (skb->len <4 ) { +dev_kfree_skb (skb); +return -EINVAL ; + }skb_pull (skb,4 ); buf = skb->data; -while (buf - skb->data < skb->len) { +while (buf - skb->data +sizeof (struct tlv ) <= skb->len) {struct tlv *tlv = (struct tlv *)buf; +u16 tlv_len =le16_to_cpu (tlv->len); + +if (tlv_len <sizeof (*tlv) || + tlv_len > skb->len - (buf - skb->data)) +break ;switch (le16_to_cpu (tlv->tag)) {case UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION : - *cap =le32_to_cpu (*(__le32 *)(buf +sizeof (*tlv))); +if (tlv_len >=sizeof (*tlv) +sizeof (__le32)) + *cap =le32_to_cpu (*(__le32 *)(buf +sizeof (*tlv)));break ;default :break ; } - buf +=le16_to_cpu (tlv->len); + buf += tlv_len; }dev_kfree_skb (skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 818/1376 wifi: mt76: mt7915: unwind state on add_interface failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 2fb6480c52f611338e1b0abe5e6219be1fc9ab75 ]
When mt76_wcid_alloc() fails, mt7915_add_interface() returned without clearing the vif_mask/omac_mask bits it had already set, without removing the firmware dev info added earlier, and without clearing a monitor_vif pointer to the vif mac80211 is about to free. mac80211 does not call remove_interface() for a failed add, so the indices and firmware dev entry leaked permanently and testmode could dereference the stale monitor_vif. Add a proper error unwind.
--- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/main.c +11 -1
@@ -248,7 +248,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, idx =mt76_wcid_alloc (dev->mt76.wcid_mask,mt7915_wtbl_size (dev));if (idx <0 ) { ret = -ENOSPC ; - goto out; + goto err; }INIT_LIST_HEAD (&mvif->sta.rc_list);
@@ -279,7 +279,17 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,mt7915_mcu_add_sta (dev, vif,NULL ,CONN_STATE_PORT_SECURE , true);rcu_assign_pointer (dev->mt76.wcid[idx], &mvif->sta.wcid); +mutex_unlock (&dev->mt76.mutex); + +return 0 ; + +err: + dev->mt76.vif_mask &= ~BIT_ULL (mvif->mt76.idx); + phy->omac_mask &= ~BIT_ULL (mvif->mt76.omac_idx); +mt7915_mcu_add_dev_info (phy, vif, false); out: +if (phy->monitor_vif == vif) + phy->monitor_vif =NULL ;mutex_unlock (&dev->mt76.mutex);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 819/1376 wifi: mt76: mt7996: reserve space for the CSA-abort countdown TLV
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 50c66bab321140c49aa2ed779a3ec9d2f085b458 ]
When a CSA countdown is active, mt7996_mcu_beacon_cntdwn() emits two bss_bcn_cntdwn_tlv entries (the CSA countdown and the CCA-abort BCC), but MT7996_BEACON_UPDATE_SIZE only reserved one. With MBSSID enabled and a near-maximum beacon template the extra 8 bytes could push the offload command past MT7996_MAX_BSS_OFFLOAD_SIZE and trigger skb_over_panic(). Reserve room for both countdown TLVs.
--- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +1 -1
@@ -804,7 +804,7 @@ enum {#define MT7996_BEACON_UPDATE_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct bss_bcn_content_tlv) + \ 4 + MT_TXD_SIZE + \ - sizeof(struct bss_bcn_cntdwn_tlv) + \ + sizeof(struct bss_bcn_cntdwn_tlv) * 2 + \ sizeof(struct bss_bcn_mbss_tlv))#define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ MT7996_BEACON_UPDATE_SIZE)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 820/1376 wifi: mt76: mt7915: use little-endian for bss_info_ra wire fields
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 04280d0a56be4264720e7b205daaa332c715e5ec ]
train_up_high_thres, train_up_rule_rssi and low_traffic_thres were declared as host-native short in a firmware-facing TLV and assigned host-order constants, so on a big-endian host the firmware received byte-swapped rate-adaptation thresholds. Declare them __le16 and convert with cpu_to_le16().
--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +3 -3
@@ -532,9 +532,9 @@ mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ra->rx_streams = max_nss; ra->algo =4 ; ra->train_up_rule =2 ; - ra->train_up_high_thres =110 ; - ra->train_up_rule_rssi =-70 ; - ra->low_traffic_thres =2 ; + ra->train_up_high_thres =cpu_to_le16 (110 ); + ra->train_up_rule_rssi =cpu_to_le16 (-70 ); + ra->low_traffic_thres =cpu_to_le16 (2 ); ra->phy_cap =cpu_to_le32 (0xfdf ); ra->interval =cpu_to_le32 (500 ); ra->fast_interval =cpu_to_le32 (100 );
drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +3 -3
@@ -318,9 +318,9 @@ struct bss_info_ra {u8 antenna_idx;u8 train_up_rule;u8 rsv[3 ]; -unsigned short train_up_high_thres; -short train_up_rule_rssi; -unsigned short low_traffic_thres; +__le16 train_up_high_thres; +__le16 train_up_rule_rssi; +__le16 low_traffic_thres;__le16 max_phyrate;__le32 phy_cap;__le32 interval;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 821/1376 wifi: mt76: only consume the WO drop bit on WED v2 devices
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 1df54335590bb025c3bd706a9ba9c6e73a1d3000 ]
The RX path is handled by the WO MCU only on WED v2 hardware. On WED v3 the same buf1 bit does not carry drop information, so evaluating it there causes spurious RX drops.
--- drivers/net/wireless/mediatek/mt76/dma.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/dma.c +6 -1
@@ -459,8 +459,13 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, t->ptr =NULL ;mt76_put_rxwi (dev, t); -if (drop) +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +/* the WO MCU owns the RX path only on WED v2, on newer +* versions this buf1 bit carries no drop information +*/ +if (drop && dev->mmio.wed.version ==2 ) *drop |= !!(buf1 &MT_DMA_CTL_WO_DROP ); +#endif }else { dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], SKB_WITH_OVERHEAD(q->buf_size),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 822/1376 ACPI: processor: idle: Optimize ACPI idle driver registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huisong Li <[email protected]>
[ Upstream commit 7a8c994cbb2db3c5335cee35fd486557f5aaf7e1 ]
Currently, the ACPI idle driver is registered from within a CPU hotplug callback. Although this didn't cause any functional issues, this is questionable and confusing. And it is better to register the cpuidle driver when all of the CPUs have been brought up.
So add a new function to initialize acpi_idle_driver based on the power management information of an available CPU and register cpuidle driver in acpi_processor_driver_init().
This commit has four changes under the commit 7a8c994cbb2d (ACPI:
processor: idle: Optimize ACPI idle driver registration):
1) move acpi_processor_register_idle_driver() ahead of the driver_register().
2) add acpi_processor_cstate_first_run_checks() before calling acpi_processor_get_power_info().
3) squash the commit 9d68320b2bca (ACPI: processor: idle: Fix function defined but not used warning) into this change.
4) use for_each_possible_cpu(cpu) to scan all possible cpus.
[ rjw: New comment edits, changelog tweak ]
Stable-dep-of: 06f32dd67e6b ("ACPI: processor: Unregister cpufreq notifier on init failure")
--- drivers/acpi/processor_driver.c | 10 ++++- drivers/acpi/processor_idle.c | 66 +++++++++++++++++++++------------ include/acpi/processor.h | 2 + 3 files changed, 54 insertions(+), 24 deletions(-)
drivers/acpi/processor_driver.c +9 -1
@@ -259,9 +259,11 @@ static int __init acpi_processor_driver_init(void)acpi_processor_ignore_ppc_init (); } +acpi_processor_register_idle_driver (); + result =driver_register (&acpi_processor_driver);if (result <0 ) -return result; + goto unregister_idle_drv; result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "acpi/cpu-drv:online",
@@ -280,8 +282,13 @@ static int __init acpi_processor_driver_init(void)*/ acpi_processor_init_invariance_cppc ();return 0 ; + err:driver_unregister (&acpi_processor_driver); + +unregister_idle_drv: +acpi_processor_unregister_idle_driver (); +return result; }
@@ -299,6 +306,7 @@ static void __exit acpi_processor_driver_exit(void)cpuhp_remove_state_nocalls (hp_online);cpuhp_remove_state_nocalls (CPUHP_ACPI_CPUDRV_DEAD );driver_unregister (&acpi_processor_driver); +acpi_processor_unregister_idle_driver (); }module_init (acpi_processor_driver_init);
drivers/acpi/processor_idle.c +43 -23
96 lines not on this page · raw message
include/acpi/processor.h +2 -0
@@ -418,6 +418,8 @@ int acpi_processor_power_init(struct acpi_processor *pr);int acpi_processor_power_exit (struct acpi_processor *pr);int acpi_processor_power_state_has_changed (struct acpi_processor *pr);int acpi_processor_hotplug (struct acpi_processor *pr); +void acpi_processor_register_idle_driver (void ); +void acpi_processor_unregister_idle_driver (void );#else static inline int acpi_processor_power_init (struct acpi_processor *pr) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 823/1376 ACPI: processor: Unregister cpufreq notifier on init failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
[ Upstream commit 06f32dd67e6b23a05bef0d8183c5335af91c0c3b ]
acpi_processor_driver_init() registers the cpufreq policy notifier before registering the ACPI processor driver and setting up CPU hotplug state.
If driver_register() or cpuhp_setup_state() fails, the error path only unregisters the ACPI processor driver and the idle driver. The cpufreq notifier remains registered even though initialization failed.
Mirror the module exit path on the init failure path and unregister the cpufreq notifier when it has been registered.
--- drivers/acpi/processor_driver.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/acpi/processor_driver.c +6 -0
@@ -289,6 +289,12 @@ static int __init acpi_processor_driver_init(void) unregister_idle_drv:acpi_processor_unregister_idle_driver (); +if (acpi_processor_cpufreq_init) { +cpufreq_unregister_notifier (&acpi_processor_notifier_block, +CPUFREQ_POLICY_NOTIFIER ); + acpi_processor_cpufreq_init = false; + } +return result; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 824/1376 perf: arm_spe: Make wakeup range check overflow safe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit fcc5eaea2d234162dfb8258372dd897bc2a1b862 ]
The current code checks whether the wakeup point is in the current writable range by comparing it with handle->head + handle->size.
The perf AUX head is a monotonically increasing index, so that addition can overflow when head is close to ULONG_MAX. In that case, a wakeup point which is still inside the free space range can be missed.
Use unsigned subtraction to compare the distance from head to wakeup against the handle->size. This can dismiss the issue when addition overflow.
This is unlikely to happen in practice, but the change makes the watermark check logically correct.
--- drivers/perf/arm_spe_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/perf/arm_spe_pmu.c +1 -1
@@ -467,7 +467,7 @@ static u64 __arm_spe_pmu_next_off(struct perf_output_handle *handle)* the page boundary following it. Keep the tail boundary if * that's lower. */ -if (handle->wakeup < (handle->head + handle->size) && head <= wakeup) +if ((handle->wakeup - handle->head) < handle->size && head <= wakeup) limit =min (limit,round_up (wakeup,PAGE_SIZE ));if (limit > head)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 825/1376 drm/msm/dpu: Drop sneaky dev_pm_opp_set_rate(0)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 811c38907eab0f66c22c5e5708e6f8eab14d76fa ]
dev_pm_opp_set_rate(0) removes the vote specified in required-opps but does not actually park the clock, making it run without the necessary power backing. Prevent that from happening when _dpu_core_perf_get_core_clk_rate() returns 0.
Patchwork: https://patchwork.freedesktop.org/patch/742779/
--- drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +4 -0
@@ -383,6 +383,10 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,trace_dpu_core_perf_update_clk (kms->dev, !crtc->enabled, clk_rate); +/* If we're going offline, PM callbacks will disable the clocks instead */ +if (!clk_rate) +return 0 ; + clk_rate =min (clk_rate, kms->perf.max_core_clk_rate); ret =dev_pm_opp_set_rate (&kms->pdev->dev, clk_rate);if (ret) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 826/1376 drm/msm/dsi: Drop dev_pm_opp_set_rate(0)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 06b7ba206561619bb34116f49e0ef26b867ce3aa ]
dev_pm_opp_set_rate(0) removes the vote specified in required-opps but does not actually park the clock, making it run without the necessary power backing. Drop the explicit call to it.
Every call site of ops->link_clk_disable() is followed by pm_runtime_put(), so the power vote will be rescinded if deemed safe.
Patchwork: https://patchwork.freedesktop.org/patch/742783/
--- drivers/gpu/drm/msm/dsi/dsi_host.c | 2 -- 1 file changed, 2 deletions(-)
drivers/gpu/drm/msm/dsi/dsi_host.c +0 -2
@@ -499,8 +499,6 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)void dsi_link_clk_disable_6g (struct msm_dsi_host *msm_host) { -/* Drop the performance state vote */ -dev_pm_opp_set_rate (&msm_host->pdev->dev,0 );clk_disable_unprepare (msm_host->esc_clk);clk_disable_unprepare (msm_host->pixel_clk);clk_disable_unprepare (msm_host->byte_intf_clk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 827/1376 wifi: ath11k: fix leak in ath11k_service_ready_ext_event()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 0293be2212d319d59589082461abf2a9b626cd1c ]
Currently, during ath11k_service_ready_ext_event() processing, svc_rdy_ext.mac_phy_caps can be allocated during TLV parsing. This is a temporary allocation that is freed on the success path, but not on the error path. If parsing succeeds far enough to allocate mac_phy_caps and then fails on a later TLV, the allocation leaks. So free the allocation on the error path.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/wmi.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/ath/ath11k/wmi.c +1 -0
@@ -5077,6 +5077,7 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab,return 0 ; err: +kfree (svc_rdy_ext.mac_phy_caps);ath11k_wmi_free_dbring_caps (ab);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 828/1376 regulator: core: use system_freezable_wq for init complete work
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joy Zou <[email protected]>
[ Upstream commit 03eab318cedd6ae34ecd34533cd986edf5237164 ]
schedule_delayed_work() uses system_wq, which is non-freezable, allowing regulator_init_complete_work to run concurrently with system suspend. This work fires ~30s after boot to disable unused regulators via I2C. When it races with PM suspend, the I2C adapter may already be suspended, triggering a -ESHUTDOWN warning in __i2c_transfer():
WARNING: ... at __i2c_transfer+0x36c/0x3c8
Call trace: __i2c_transfer i2c_transfer regmap_i2c_write _regmap_update_bits regulator_disable_regmap _regulator_do_disable regulator_late_cleanup regulator_init_complete_work_function process_one_work
Switch to system_freezable_wq so the work is frozen before any device is suspended, eliminating the race.
--- drivers/regulator/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/regulator/core.c +4 -2
@@ -27,6 +27,7 @@#include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/module.h> +#include <linux/workqueue.h> #define CREATE_TRACE_POINTS #include <trace/events/regulator.h>
@@ -6467,8 +6468,9 @@ static int __init regulator_init_complete(void)* we'd only do this on systems that need it, and a kernel * command line option might be useful. */ -schedule_delayed_work (®ulator_init_complete_work, -msecs_to_jiffies (30000 )); +queue_delayed_work (system_freezable_wq, + ®ulator_init_complete_work, +msecs_to_jiffies (30000 ));return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 829/1376 perf machine: Fix NULL parent dereference in fork event processing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 73ac546bd6ba8ed4dc8d7a90fcb9bb8236de1568 ]
machine__process_fork_event() calls machine__findnew_thread() for the parent thread, which can return NULL on allocation failure. The code then dereferences parent via thread__pid(parent) without a NULL check when validating whether the parent PID matches. The later NULL check at thread__fork() does not prevent this earlier dereference.
Add a NULL guard before accessing the parent thread.
--- tools/perf/util/machine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +2 -1
@@ -1843,7 +1843,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event* (fork) event that would have removed the thread was lost. Assume the * latter case and continue on as best we can. */ -if (thread__pid (parent) != (pid_t )event->fork.ppid) { +if (parent !=NULL && +thread__pid (parent) != (pid_t )event->fork.ppid) {dump_printf ("removing erroneous parent thread %d/%d\n" ,thread__pid (parent),thread__tid (parent));machine__remove_thread (machine, parent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 830/1376 perf machine: Guard against NULL strlist in machines__findnew()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit e27b96d0a34e1dc87affecf221a99fee8f6c5afc ]
The static 'seen' strlist caches guestmount paths that have already been reported as inaccessible, to avoid repeating the error message. If strlist__new() fails (OOM), 'seen' stays NULL and the next call dereferences it via strlist__has_entry() and strlist__add().
Guard both calls so that on allocation failure the error message is still printed (just not deduplicated) instead of crashing.
--- tools/perf/util/machine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/perf/util/machine.c +3 -2
@@ -296,9 +296,10 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if (!seen) seen =strlist__new (NULL ,NULL ); -if (!strlist__has_entry (seen, path)) { +if (!seen || !strlist__has_entry (seen, path)) {pr_err ("Can't access file %s\n" , path); -strlist__add (seen, path); +if (seen) +strlist__add (seen, path); } machine =NULL ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 831/1376 perf machine: Use snprintf() for guestmount path construction
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit fe63d3bca288c5bb983304efd5fc3a5ff3183403 ]
machines__findnew() and machines__create_guest_kernel_maps() use sprintf() to build paths by prepending symbol_conf.guestmount. Both write into PATH_MAX stack buffers, but guestmount comes from user configuration and is not length-checked. A guestmount path at or near PATH_MAX causes a stack buffer overflow.
Switch to snprintf() with sizeof() to prevent overflow. The subsequent access()/fopen() calls will fail on a truncated path.
Stable-dep-of: cc6abe0012bf ("perf machine: Check snprintf truncation in machines__findnew()")
--- tools/perf/util/machine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/machine.c +4 -4
@@ -289,7 +289,7 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if ((pid !=HOST_KERNEL_ID ) && (pid !=DEFAULT_GUEST_KERNEL_ID ) && (symbol_conf.guestmount)) { -sprintf (path,"%s/%d" , symbol_conf.guestmount, pid); +snprintf (path,sizeof (path),"%s/%d" , symbol_conf.guestmount, pid);if (access (path,R_OK )) {static struct strlist *seen;
@@ -1215,9 +1215,9 @@ int machines__create_guest_kernel_maps(struct machines *machines) namelist[i]->d_name);continue ; } -sprintf (path,"%s/%s/proc/kallsyms" , - symbol_conf.guestmount, - namelist[i]->d_name); +snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , + symbol_conf.guestmount, + namelist[i]->d_name); ret =access (path,R_OK );if (ret) {pr_debug ("Can't access file %s\n" , path);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 832/1376 perf machine: Check snprintf truncation in machines__findnew()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit cc6abe0012bf8c04af8275266f8ed7c55ba4a5fb ]
The guestmount path is built with snprintf() into a PATH_MAX buffer without checking the return value. If symbol_conf.guestmount is long enough to cause truncation, the truncated path could match a different directory, causing the wrong guest to be associated with the pid.
Check for truncation and bail out early.
--- tools/perf/util/machine.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +6 -1
@@ -289,7 +289,12 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if ((pid !=HOST_KERNEL_ID ) && (pid !=DEFAULT_GUEST_KERNEL_ID ) && (symbol_conf.guestmount)) { -snprintf (path,sizeof (path),"%s/%d" , symbol_conf.guestmount, pid); +if (snprintf (path,sizeof (path),"%s/%d" , + symbol_conf.guestmount, pid) >= (int )sizeof (path)) { +pr_err ("Guest path too long for pid %d\n" , pid); + machine =NULL ; + goto out; + }if (access (path,R_OK )) {static struct strlist *seen;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 833/1376 perf machine: Dont abort guest map creation on first inaccessible dir
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit b687e1a418fb819ef83c362d84c216a6a841e3b0 ]
machines__create_guest_kernel_maps() jumps to the failure label when one guest directory's kallsyms file fails access(), skipping all remaining valid guest directories. An inaccessible directory is not fatal — other guests may still be reachable.
Replace 'goto failure' with 'continue' so the loop processes all directories, and remove the now-unreferenced failure label.
--- tools/perf/util/machine.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
tools/perf/util/machine.c +2 -4
@@ -1223,14 +1223,12 @@ int machines__create_guest_kernel_maps(struct machines *machines)snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , symbol_conf.guestmount, namelist[i]->d_name); - ret =access (path,R_OK ); -if (ret) { +if (access (path,R_OK )) {pr_debug ("Can't access file %s\n" , path); - goto failure; +continue ; }machines__create_kernel_maps (machines, pid); } -failure:free (namelist); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 834/1376 perf machine: Reset errno before strtol in guest kernel map creation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 29ec46e43f6ca7d6a6651db724d4ffd820f46e8b ]
machines__create_guest_kernel_maps() checks errno == ERANGE after strtol() to detect overflow, but does not clear errno first. A stale ERANGE from an earlier library call (e.g. scandir internals) causes valid numeric directory names to be incorrectly skipped.
Set errno = 0 before strtol() so only the current conversion can trigger the ERANGE check.
--- tools/perf/util/machine.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/machine.c +1 -0
@@ -1212,6 +1212,7 @@ int machines__create_guest_kernel_maps(struct machines *machines)/* Filter out . and .. */ continue ; } + errno =0 ; pid = (pid_t )strtol (namelist[i]->d_name, &endp,10 ); if ((*endp != '\0') || (endp == namelist[i]->d_name) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 835/1376 perf machine: Free scandir entries in guest kernel map creation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit f53bf58dcd11e1cb088d3b91a035fef77062094b ]
machines__create_guest_kernel_maps() calls scandir() which allocates both the namelist array and each individual dirent entry. The code frees the namelist array but not the individual entries, leaking memory proportional to the number of directories under guestmount.
Free each namelist[i] after it is no longer needed.
--- tools/perf/util/machine.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/util/machine.c +4 -0
@@ -1210,6 +1210,7 @@ int machines__create_guest_kernel_maps(struct machines *machines)for (i =0 ; i < items; i++) {if (!isdigit (namelist[i]->d_name[0 ])) {/* Filter out . and .. */ +free (namelist[i]);continue ; } errno =0 ;
@@ -1219,6 +1220,7 @@ int machines__create_guest_kernel_maps(struct machines *machines) (errno == ERANGE)) {pr_debug ("invalid directory (%s). Skipping.\n" , namelist[i]->d_name); +free (namelist[i]);continue ; } snprintf(path, sizeof(path), "%s/%s/proc/kallsyms",
@@ -1226,9 +1228,11 @@ int machines__create_guest_kernel_maps(struct machines *machines) namelist[i]->d_name);if (access (path,R_OK )) {pr_debug ("Can't access file %s\n" , path); +free (namelist[i]);continue ; }machines__create_kernel_maps (machines, pid); +free (namelist[i]); }free (namelist); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 836/1376 perf machine: Check snprintf truncation for guest kallsyms path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit d04ef71492fad7230d474efe33d05f4c0563d409 ]
machines__create_guest_kernel_maps() builds the guest kallsyms path with snprintf() without checking the return value. A truncated path could pass the access() check if a prefix directory happens to contain a file named "kallsyms", leading to the wrong file being used for symbol resolution.
Check for truncation and skip the directory.
--- tools/perf/util/machine.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +8 -3
@@ -1223,9 +1223,14 @@ int machines__create_guest_kernel_maps(struct machines *machines)free (namelist[i]);continue ; } -snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , - symbol_conf.guestmount, - namelist[i]->d_name); +if (snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , + symbol_conf.guestmount, + namelist[i]->d_name) >= (int )sizeof (path)) { +pr_debug ("Guest kallsyms path too long for %s. Skipping.\n" , + namelist[i]->d_name); +free (namelist[i]); +continue ; + }if (access (path,R_OK )) {pr_debug ("Can't access file %s\n" , path);free (namelist[i]);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 837/1376 bpf, x86: Fix trampoline stack size for 128-bit arguments
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonghong Song <[email protected]>
[ Upstream commit 814cba835ef648e0c5eb79505c96c0493b29eea6 ]
btf_distill_func_proto() accepts a function argument up to 16 bytes, so a 128-bit scalar such as __int128 reaches the x86 trampoline with arg_size == 16. But the current implementation assumes an __int128 argument only needs one register, so the register save area is under-allocated and save_args() overwrites adjacent stack slots.
Compute the register count from arg_size for all arguments to fix it.
--- arch/x86/net/bpf_jit_comp.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
arch/x86/net/bpf_jit_comp.c +2 -5
@@ -2948,11 +2948,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_imWARN_ON_ONCE ((flags &BPF_TRAMP_F_INDIRECT ) && (flags & ~(BPF_TRAMP_F_INDIRECT |BPF_TRAMP_F_RET_FENTRY_RET ))); -/* extra registers for struct arguments */ -for (i =0 ; i < m->nr_args; i++) { -if (m->arg_flags[i] &BTF_FMODEL_STRUCT_ARG ) - nr_regs += (m->arg_size[i] +7 ) /8 -1 ; - } +for (i =0 ; i < m->nr_args; i++) + nr_regs += (m->arg_size[i] +7 ) /8 -1 ;/* x86-64 supports up to MAX_BPF_FUNC_ARGS arguments. 1-6 * are passed through regs, the remains are through stack.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 838/1376 wifi: mt76: mt7915: unlink TWT flow if the MCU rejects the agreement
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 16a04441eab0dcd4d7126a6f66b370adbf28f96d ]
The flow is added to dev->twt_list before sending the agreement to the firmware, but the error path leaves it linked while flowid_mask is never set. The flow slot can then be reused and memset while still on the list, corrupting twt_list, and station removal leaves a dangling entry behind that mt7915_mac_twt_sched_list_add() later walks.
--- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +3 -1
@@ -2371,8 +2371,10 @@ void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, } flow->tsf =le64_to_cpu (twt_agrt->twt); -if (mt7915_mcu_twt_agrt_update (dev, msta->vif, flow,MCU_TWT_AGRT_ADD )) +if (mt7915_mcu_twt_agrt_update (dev, msta->vif, flow,MCU_TWT_AGRT_ADD )) { +list_del (&flow->list); goto unlock; + } setup_cmd =TWT_SETUP_CMD_ACCEPT ; dev->twt.table_mask |=BIT (table_id);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 839/1376 wifi: mt76: mt7915: fix double hif2 init on the non-WED path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 3ae8ad277e2819a281b0e36b55633c8515c16ce7 ]
mt7915_pci_init_hif2() was called unconditionally and again inside the WED-inactive branch. The helper increments the global hif_idx, writes the PCIe RECOG_ID register and takes a get_device() reference via mt7915_pci_get_hif2(), while removal only drops one reference. On non-WED dual-hif hardware this double-incremented hif_idx, wrote RECOG_ID twice and leaked a device reference. Only the call inside the WED-inactive branch is correct; drop the unconditional one. hif2 is already initialised to NULL.
--- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/pci.c +0 -1
@@ -135,7 +135,6 @@ static int mt7915_pci_probe(struct pci_dev *pdev, mdev = &dev->mt76;mt7915_wfsys_reset (dev); - hif2 =mt7915_pci_init_hif2 (pdev); ret =mt7915_mmio_wed_init (dev, pdev, true, &irq);if (ret <0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 840/1376 wifi: mt76: mt7915: fix ext PHY use-after-free on register error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 15b960014f24dce5388d4a2e7274e6490cb3c421 ]
After mt7915_register_ext_phy() succeeded, a failure of the main PHY mt7915_init_debugfs() or mt7915_coredump_register() unwound through free_phy2, which called ieee80211_free_hw() on the ext PHY hw while it was still registered with mac80211, since mt76_unregister_device() only unregisters the main hw. Unregister the ext PHY (thermal + phy + hw) first and skip the redundant free.
--- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/init.c +7 -2
@@ -1253,14 +1253,19 @@ int mt7915_register_device(struct mt7915_dev *dev) ret =mt7915_init_debugfs (&dev->phy);if (ret) - goto unreg_thermal; + goto unreg_ext_phy; ret =mt7915_coredump_register (dev);if (ret) - goto unreg_thermal; + goto unreg_ext_phy;return 0 ; +unreg_ext_phy: +if (phy2) { +mt7915_unregister_ext_phy (dev); + phy2 =NULL ; + } unreg_thermal:mt7915_unregister_thermal (&dev->phy); unreg_dev:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 841/1376 wifi: mt76: mt7915: release hif2 reference on probe IRQ failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 8370aebd26a9dfa2e0de665e3ab504c0e97ee730 ]
The hif2 reference obtained by mt7915_pci_init_hif2() is only released on error paths that key off dev->hif2, which is not assigned until after the IRQ setup. If pci_alloc_irq_vectors() or the primary devm_request_irq() fails, the reference leaks. Drop it explicitly on those paths via mt7915_put_hif2().
--- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/pci.c +6 -2
@@ -144,16 +144,20 @@ static int mt7915_pci_probe(struct pci_dev *pdev, hif2 =mt7915_pci_init_hif2 (pdev); ret =pci_alloc_irq_vectors (pdev,1 ,1 ,PCI_IRQ_ALL_TYPES ); -if (ret <0 ) +if (ret <0 ) { +mt7915_put_hif2 (hif2); goto free_device; + } irq = pdev->irq; } ret =devm_request_irq (mdev->dev, irq, mt7915_irq_handler,IRQF_SHARED ,KBUILD_MODNAME , dev); -if (ret) +if (ret) { +mt7915_put_hif2 (hif2); goto free_wed_or_irq_vector; + }/* master switch of PCIe tnterrupt enable */ mt76_wr (dev,MT_PCIE_MAC_INT_ENABLE ,0xff );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 842/1376 wifi: mt76: mt7996: fix reg addr remap when addr is 0
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: StanleyYP Wang <[email protected]>
[ Upstream commit eb906eeff2d1e84b628dc210dada325269c71383 ]
When addr is less than the hardcoded threshold in __mt7996_reg_addr, it indicates that remapping is unnecessary.
Currently, the flow remaps address 0x0 to MT_HIF_REMAP_BASE_L2, which is incorrect.
To address this, modify __mt7996_reg_addr to return INVALID_REG_ADDR if the address is not below the hardcoded value or is not present in the mt7996_reg_map array.
Additionally, update the remap condition to check if addr is equal to INVALID_REG_ADDR.
--- drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +7 -5
@@ -17,6 +17,8 @@static bool wed_enable;module_param (wed_enable, bool,0644 ); +#define INVALID_REG_ADDR 0xffffffff +static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE ] = { {0x820e2000 ,0x820f2000 ,0x830e2000 } }, [WF_ARB_BASE ] = { {0x820e3000 ,0x820f3000 ,0x830e3000 } },
@@ -183,7 +185,7 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)return dev->reg.map[i].mapped + ofs; } -return 0 ; +return INVALID_REG_ADDR ; }static u32 __mt7996_reg_remap_addr (struct mt7996_dev *dev,u32 addr)
@@ -212,7 +214,7 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, {u32 addr =__mt7996_reg_addr (dev, offset); -if (addr) { +if (addr !=INVALID_REG_ADDR ) {memcpy_fromio (buf, dev->mt76.mmio.regs + addr, len);return ; }
@@ -228,7 +230,7 @@ static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);u32 addr =__mt7996_reg_addr (dev, offset), val; -if (addr) +if (addr !=INVALID_REG_ADDR )return dev->bus_ops->rr (mdev, addr);spin_lock_bh (&dev->reg_lock);
@@ -243,7 +245,7 @@ static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);u32 addr =__mt7996_reg_addr (dev, offset); -if (addr) { +if (addr !=INVALID_REG_ADDR ) { dev->bus_ops->wr (mdev, addr, val);return ; }
@@ -258,7 +260,7 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);u32 addr =__mt7996_reg_addr (dev, offset); -if (addr) +if (addr !=INVALID_REG_ADDR )return dev->bus_ops->rmw (mdev, addr, mask, val);spin_lock_bh (&dev->reg_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 843/1376 wifi: mt76: mt7915: fix chainmask handling for non-dbdc phys on band 1
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit ea891799eccc9e43ebba0dc157d4b197ad6c1a0e ]
On single-adie mt7986 the only phy is bound to band 1, but its chainmask is stored unshifted, because dev->chainshift is still zero while the eeprom is parsed for the main phy. mt7915_set_antenna() on the other hand shifts by chainshift * band_idx, so the representation of the chainmask changed as soon as the antenna configuration was touched. Until then, mt7915_mcu_set_chan_info() passed rx_path = 0 to the firmware, since shifting the unshifted mask down clears all bits.
Keep the unshifted form for that case and add helpers for the band local chainmask, so that only the band 1 phy of a dbdc device uses the shifted form.
--- .../net/wireless/mediatek/mt76/mt7915/eeprom.c | 2 +- .../net/wireless/mediatek/mt76/mt7915/main.c | 6 +++--- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt7915/mt7915.h | 18 ++++++++++++++++++ .../wireless/mediatek/mt76/mt7915/testmode.c | 5 +---- 5 files changed, 24 insertions(+), 9 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +1 -1
@@ -257,7 +257,7 @@ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev, nss =min_t (u8,min_t (u8, nss_max, nss), path); mphy->chainmask =BIT (path) -1 ; -if (band) +if (band && dev->dbdc_support) mphy->chainmask <<= dev->chainshift; mphy->antenna_mask =BIT (nss) -1 ; dev->chainmask |= mphy->chainmask;
drivers/net/wireless/mediatek/mt76/mt7915/main.c +3 -3
@@ -1072,7 +1072,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)struct mt7915_dev *dev =mt7915_hw_dev (hw);struct mt7915_phy *phy =mt7915_hw_phy (hw);int max_nss =hweight8 (hw->wiphy->available_antennas_tx); -u8 chainshift = dev->chainshift; +u8 shift =mt7915_band_chainshift (phy);u8 band = phy->mt76->band_idx;if (!tx_ant || tx_ant != rx_ant ||ffs (tx_ant) > max_nss)
@@ -1085,9 +1085,9 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)/* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ if ((is_mt7916 (&dev->mt76) ||is_mt7981 (&dev->mt76)) && band &&hweight8 (tx_ant) == max_nss) - phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; + phy->mt76->chainmask = (dev->chainmask >> shift) << shift;else - phy->mt76->chainmask = tx_ant << (chainshift * band); + phy->mt76->chainmask = tx_ant << shift;mt76_set_stream_caps (phy->mt76, true);mt7915_set_stream_vht_txbf_caps (phy);
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +1 -1
@@ -2758,7 +2758,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> (dev->chainshift * band), + .rx_path = mt7915_band_chainmask(phy), .band_idx = band, .channel_band = ch_band[chandef->chan->band], };
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +18 -0
@@ -383,6 +383,24 @@ mt7915_ext_phy(struct mt7915_dev *dev)return phy->priv; } +/* without dbdc, the chainmask is stored unshifted, even if the phy is +* bound to band 1 +*/ +static inline u8 mt7915_band_chainshift (struct mt7915_phy *phy) +{ +struct mt7915_dev *dev = phy->dev; + +if (!dev->dbdc_support) +return 0 ; + +return phy->mt76->band_idx * dev->chainshift; +} + +static inline u16 mt7915_band_chainmask (struct mt7915_phy *phy) +{ +return phy->mt76->chainmask >>mt7915_band_chainshift (phy); +} +static inline u32 mt7915_check_adie (struct mt7915_dev *dev,bool sku) {u32 mask = sku ?MT_CONNINFRA_SKU_MASK :MT_ADIE_TYPE_MASK ;
drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +1 -4
@@ -694,9 +694,7 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, {struct mt76_testmode_data *td = &mphy->test;struct mt7915_phy *phy = mphy->priv; -struct mt7915_dev *dev = phy->dev; -u32 chainmask = mphy->chainmask, changed =0 ; -bool ext_phy = phy != &dev->phy; +u32 chainmask =mt7915_band_chainmask (phy), changed =0 ;int i;BUILD_BUG_ON (NUM_TM_CHANGED >=32 );
@@ -705,7 +703,6 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, td->state == MT76_TM_STATE_OFF)return 0 ; - chainmask = ext_phy ? chainmask >> dev->chainshift : chainmask;if (td->tx_antenna_mask > chainmask)return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 844/1376 wifi: mt76: mt7915: report RX chain signal for all RX paths
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit b53c44fe65792608f58028c7b0953e610ad652ee ]
status->chains was set from the antenna mask, which is derived from the number of spatial streams, while the chain_signal array is filled from all RCPI fields. On boards where the number of RX paths exceeds the stream count, e.g. the 3T3R mt7916/mt7981 variant with 2 streams on the 5 GHz band, the RSSI of the extra chains was never reported.
Use the band local RX path chainmask instead.
--- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/mac.c +1 -1
@@ -444,7 +444,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,if (v0 &MT_PRXV_HT_AD_CODE ) status->enc_flags |=RX_ENC_FLAG_LDPC ; - status->chains = mphy->antenna_mask; + status->chains =mt7915_band_chainmask (phy); status->chain_signal[0 ] =to_rssi (MT_PRXV_RCPI0 , v1); status->chain_signal[1 ] =to_rssi (MT_PRXV_RCPI1 , v1); status->chain_signal[2 ] =to_rssi (MT_PRXV_RCPI2 , v1);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 845/1376 wifi: mt76: mt7925: advertise EHT 320MHz capabilities for 6GHz band
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Javier Tia <[email protected]>
[ Upstream commit 77833c57a33450c0409e4b90d7721d255ea23a9e ]
mt7925_init_eht_caps() only populates EHT MCS/NSS maps for BW <= 80 and BW = 160, but never sets BW = 320. This means iw phy shows no 320MHz MCS map entries even though the hardware supports 320MHz operation in the 6GHz band.
Add the missing 320MHz capability bits for 6GHz:
- PHY_CAP0: IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ
- PHY_CAP1: beamformee SS for 320MHz
- PHY_CAP2: sounding dimensions for 320MHz
- PHY_CAP6: MCS15 support for 320MHz width
- MCS/NSS: populate bw._320 maps for 6GHz band
Introduce is_320mhz_supported() to gate 320MHz on MT7927 only, since MT7925 does not support 320MHz operation.
Stable-dep-of: 404c4e564f6b ("wifi: mt76: mt7925: Fix EHT Beamformee SS subfields to meet 802.11be minimum")
--- .../net/wireless/mediatek/mt76/mt76_connac.h | 5 +++++ .../net/wireless/mediatek/mt76/mt7925/main.c | 22 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt76_connac.h +5 -0
@@ -177,6 +177,11 @@ static inline bool is_mt7925(struct mt76_dev *dev)return mt76_chip (dev) ==0x7925 ; } +static inline bool is_320mhz_supported (struct mt76_dev *dev) +{ +return mt76_chip (dev) ==0x7927 ; +} +static inline bool is_mt7920 (struct mt76_dev *dev) {return mt76_chip (dev) ==0x7920 ;
drivers/net/wireless/mediatek/mt76/mt7925/main.c +21 -1
@@ -178,6 +178,10 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE ; +if (band ==NL80211_BAND_6GHZ &&is_320mhz_supported (&phy->dev->mt76)) + eht_cap_elem->phy_cap_info[0 ] |= +IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ ; + eht_cap_elem->phy_cap_info[0 ] |=u8_encode_bits (u8_get_bits (sts -1 ,BIT (0 )),IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK );
@@ -188,10 +192,20 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,u8_encode_bits (sts -1 ,IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK ); +if (band ==NL80211_BAND_6GHZ &&is_320mhz_supported (&phy->dev->mt76)) + eht_cap_elem->phy_cap_info[1 ] |= +u8_encode_bits (sts -1 , +IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK ); + eht_cap_elem->phy_cap_info[2 ] =u8_encode_bits (sts -1 ,IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK ) |u8_encode_bits (sts -1 ,IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK ); +if (band ==NL80211_BAND_6GHZ &&is_320mhz_supported (&phy->dev->mt76)) + eht_cap_elem->phy_cap_info[2 ] |= +u8_encode_bits (sts -1 , +IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK ); + eht_cap_elem->phy_cap_info[3 ] =IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
@@ -212,7 +226,8 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,u8_encode_bits (u8_get_bits (0x11 ,GENMASK (1 ,0 )),IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK ); - val = width ==NL80211_CHAN_WIDTH_160 ?0x7 : + val = width ==NL80211_CHAN_WIDTH_320 ?0xf : + width ==NL80211_CHAN_WIDTH_160 ?0x7 : width ==NL80211_CHAN_WIDTH_80 ?0x3 :0x1 ; eht_cap_elem->phy_cap_info[6 ] = u8_encode_bits(u8_get_bits(0x11, GENMASK(4, 2)),
@@ -234,6 +249,11 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, eht_nss->bw._160.rx_tx_mcs9_max_nss = val; eht_nss->bw._160.rx_tx_mcs11_max_nss = val; eht_nss->bw._160.rx_tx_mcs13_max_nss = val; +if (band ==NL80211_BAND_6GHZ &&is_320mhz_supported (&phy->dev->mt76)) { + eht_nss->bw._320.rx_tx_mcs9_max_nss = val; + eht_nss->bw._320.rx_tx_mcs11_max_nss = val; + eht_nss->bw._320.rx_tx_mcs13_max_nss = val; + } }int mt7925_init_mlo_caps (struct mt792x_phy *phy)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 846/1376 wifi: mt76: mt7925: Fix EHT Beamformee SS subfields to meet 802.11be minimum
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: shengwei.lu <[email protected]>
[ Upstream commit 404c4e564f6b1eeffd10bf2b2d3b86620f5794c3 ]
Per IEEE 802.11be, the Beamformee SS <= 80/160/320 MHz 3-bit subfields in the EHT PHY Capabilities are encoded as (Nss - 1) and are required to be >= 3 (i.e. at least 4 SS receive capability) whenever SU Beamformee is advertised.
MT7925 is a 2x2 STA (sts = 2), so directly filling (sts - 1) = 1 violates the spec minimum. Clamp the encoded value to 3 when sts <= 3, otherwise use (sts - 1). This is applied consistently to the BEAMFORMEE_SS <= 80 MHz (split across phy_cap_info[0]/[1]), <= 160 MHz and <= 320 MHz (6 GHz only) subfields.
--- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7925/main.c +6 -4
@@ -182,19 +182,21 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, eht_cap_elem->phy_cap_info[0 ] |=IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ ; + val = (sts >3 ) ? sts -1 :3 ; + eht_cap_elem->phy_cap_info[0 ] |= -u8_encode_bits (u8_get_bits (sts -1 ,BIT (0 )), +u8_encode_bits (u8_get_bits (val,BIT (0 )),IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK ); eht_cap_elem->phy_cap_info[1 ] = -u8_encode_bits (u8_get_bits (sts -1 ,GENMASK (2 ,1 )), +u8_encode_bits (u8_get_bits (val,GENMASK (2 ,1 )),IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK ) | -u8_encode_bits (sts -1 , +u8_encode_bits (val,IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK );if (band ==NL80211_BAND_6GHZ &&is_320mhz_supported (&phy->dev->mt76)) eht_cap_elem->phy_cap_info[1 ] |= -u8_encode_bits (sts -1 , +u8_encode_bits (val,IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK ); eht_cap_elem->phy_cap_info[2] =
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 847/1376 wifi: ath10k: snoc: use memcpy_fromio() for MSA ramdump
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linghui Wu <[email protected]>
[ Upstream commit 4f25071afe9218aaae1c63fbf75e229aa6405319 ]
On WCN3990/SNOC the MSA region is mapped with devm_memremap(MEMREMAP_WT). On arm64 such a mapping is not Normal-cacheable, so unaligned accesses to it are not permitted. ath10k_msa_dump_memory() copies the region with a plain memcpy(), whose optimized __pi_memcpy_generic implementation issues wide/unaligned loads. This triggers an alignment fault (FSC=0x21) Oops in ath10k_snoc_fw_crashed_dump() while collecting the devcoredump:
Unable to handle kernel paging request ... FSC=0x21: alignment fault pc : __pi_memcpy_generic lr : ath10k_snoc_fw_crashed_dump [ath10k_snoc]
The Oops both leaves the firmware RAM dump buffer zeroed (no dump is captured) and crashes the kernel, which in turn breaks modem SSR recovery.
Use memcpy_fromio(), which only performs accesses that are valid for such a device-memory mapping. The generic memcpy_fromio() implementation aligns the source before issuing word-sized reads and stores the destination with put_unaligned(), so it is also safe for the coherent DMA allocation used on the non-reserved-memory path. ath11k and ath12k use the same pattern when copying target memory into crash dumps, so call it unconditionally here too.
The MEMREMAP_WT pointer is a plain void *, so an explicit __iomem cast is needed; use __force to keep sparse happy.
Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.3.3.7.c5-00107-QCAHLSWMTPL-1
--- drivers/net/wireless/ath/ath10k/snoc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath10k/snoc.c +7 -2
@@ -5,6 +5,7 @@#include <linux/bits.h> #include <linux/clk.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h>
@@ -1455,11 +1456,15 @@ static void ath10k_msa_dump_memory(struct ath10k *ar, hdr->length =cpu_to_le32 (ar->msa.mem_size);if (current_region->len < ar->msa.mem_size) { -memcpy (buf, ar->msa.vaddr, current_region->len); +memcpy_fromio (buf, + (const void __iomem __force *)ar->msa.vaddr, + current_region->len);ath10k_warn (ar,"msa dump length is less than msa size %x, %x\n" , current_region->len, ar->msa.mem_size); }else { -memcpy (buf, ar->msa.vaddr, ar->msa.mem_size); +memcpy_fromio (buf, + (const void __iomem __force *)ar->msa.vaddr, + ar->msa.mem_size); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 848/1376 iommu/arm-smmu-v3: Convert to use atomic poll timeout
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pranjal Shrivastava <[email protected]>
[ Upstream commit eced8058c82a3a81ae480a6546e2da32100dddfa ]
The arm_smmu_write_reg_sync() helper is currently implemented using readl_relaxed_poll_timeout() (that relies on usleep_range() internally) which becomes a critical issue when used in the gerror irq handler.
If the SMMU hits a gerror and enters Service Failure Mode (GERROR_SFM_ERR), the gerror handler calls arm_smmu_device_disable() in hard-irq context. This becomes a problem as arm_smmu_device_disable() inevitably calls arm_smmu_write_reg_sync() which might attempt to sleep inside a hard-irq context.
Fix this by converting the arm_smmu_write_reg_sync to use the readl_relaxed_poll_timeout_atomic() polling helper.
(Discovered while running Sashiko locally on another patch series).
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +3 -2
@@ -3774,8 +3774,9 @@ static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,u32 reg;writel_relaxed (val, smmu->base + reg_off); -return readl_relaxed_poll_timeout (smmu->base + ack_off, reg, reg == val, -1 ,ARM_SMMU_POLL_TIMEOUT_US ); +return readl_relaxed_poll_timeout_atomic (smmu->base + ack_off, reg, + reg == val,1 , +ARM_SMMU_POLL_TIMEOUT_US ); }/* GBPA is "special" */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 849/1376 perf/cxlpmu: Fix 64-bit write to 32-bit HDM filter register
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <[email protected]>
[ Upstream commit ea434e8fd3a539e9c53285b10d3c7e539e228591 ]
The HDM decoder filter configuration register is 32 bits wide, but the driver programs it with a 64-bit writeq(). The filter value never exceeds 32 bits, so the upper half of the write is always zero and lands in the adjacent Filter ID 1 (Channel/Rank/Bank) configuration register at offset+4.
--- drivers/perf/cxl_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/perf/cxl_pmu.c +1 -1
@@ -632,7 +632,7 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags) cfg =cxl_pmu_config2_get_hdm_decoder (event); else cfg =GENMASK (31 ,0 );/* No filtering if 0xFFFF_FFFF */ -writeq (cfg, base +CXL_PMU_FILTER_CFG_REG (hwc->idx,0 )); +writel (cfg, base +CXL_PMU_FILTER_CFG_REG (hwc->idx,0 )); } cfg =readq (base +CXL_PMU_COUNTER_CFG_REG (hwc->idx));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 850/1376 wifi: mac80211: send TWT teardown to peer after setup TX failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit a28fcce6ee74be8a4526e6cfa16dc7786d62a784 ]
When an AP's TWT Setup response is not acknowledged, ieee80211_s1g_tx_twt_setup_fail() asks the driver to tear down the local agreement and sends a TWT teardown action as the peer notification. It uses the response SA as the destination, but ieee80211_s1g_send_twt_setup() built that response with SA set to the AP's address. The teardown is therefore queued with DA, SA and BSSID all set to the AP address and never reaches the station.
The in-tree driver callbacks update local hardware state and emit no action frame. The station receives no notification that mac80211 asked the driver to remove the agreement and can keep following the TWT schedule, leaving the peers' power-save state desynchronized.
Address the teardown to the response DA, the station to which the failed response was sent. This also matches the station lookup the transmit status path already performs on the same frame.
--- net/mac80211/s1g.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mac80211/s1g.c +1 -1
@@ -147,7 +147,7 @@ ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata,drv_twt_teardown_request (sdata->local, sdata, &sta->sta, flowid); -ieee80211_s1g_send_twt_teardown (sdata, mgmt->sa, sdata->vif.addr, +ieee80211_s1g_send_twt_teardown (sdata, mgmt->da, sdata->vif.addr, flowid); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 851/1376 wifi: zd1211rw: reject secondary interfaces to prevent conflicts
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Slawomir Stepien <[email protected]>
[ Upstream commit 0e4532ec658606f76f62eb277e7a933919d36cbb ]
The zd1211rw driver is designed for single-function Wi-Fi dongles and hardcodes its USB endpoints. When a malformed USB device exposes multiple interfaces that match the driver's device ID, the driver blindly binds to all of them.
During probe(), the driver calls usb_reset_device(), which iterates over all interfaces and invokes the pre_reset() callback for each bound interface. Since multiple interfaces are bound to zd1211rw, pre_reset() is called sequentially for each instance, acquiring their respective &mac->chip.mutex. Because all instances initialize their mutexes with the same lock class, lockdep detects a task acquiring a lock of the same class it already holds and flags it as a possible recursive deadlock:
WARNING: possible recursive locking detected kworker/0:1/11 is trying to acquire lock:ffff88810371dde0 (&chip->mutex){+.+.}-{4:4}, at:zd_chip_disable_rxtx+0x20/0x50 drivers/net/wireless/zydas/zd1211rw/zd_chip.c:1465
but task is already holding lock:ffff8881138ddde0 (&chip->mutex){+.+.}-{4:4}, at: pre_reset+0x28c/0x380 drivers/net/wireless/zydas/zd1211rw/zd_usb.c:1505
Fix this by explicitly rejecting secondary interfaces (bInterfaceNumber !=
0) during probe(). This ensures that only a single instance of the driver binds to the device, eliminating the recursive locking scenario.
--- drivers/net/wireless/zydas/zd1211rw/zd_usb.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/wireless/zydas/zd1211rw/zd_usb.c +8 -0
@@ -1352,6 +1352,14 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)struct zd_usb *usb;struct ieee80211_hw *hw =NULL ; +/* +* ZD1211 devices are single-function. Reject secondary interfaces +* to prevent multiple instances from conflicting on hardcoded endpoints +* and triggering recursive locking warnings. +*/ +if (intf->cur_altsetting->desc.bInterfaceNumber !=0 ) +return -ENODEV ; +print_id (udev);if (id->driver_info &DEVICE_INSTALLER )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 852/1376 wifi: mac80211: skip unused probe response countdown offsets
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit fd2bf5e718108c00732eb07fd94a5d8830f62a9f ]
mac80211 copies cfg80211's variable-length countdown offset list into a zero-initialized fixed-size array, leaving unused entries at zero. The beacon branch already skips those zero entries, but the AP probe-response branch writes through them unconditionally.
When a probe-response template has no countdown offset, the write through an unused zero entry overwrites resp->data[0], corrupting the first byte of the template. cfg80211 already bounds explicitly supplied non-zero offsets in nl80211_parse_counter_offsets(), so this is a zero-sentinel bug, not an out-of-bounds write.
Skip zero probe-response offsets, matching the beacon path.
--- net/mac80211/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/mac80211/tx.c +2 -1
@@ -5051,7 +5051,8 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,if (sdata->vif.type ==NL80211_IFTYPE_AP && resp) {u16 *resp_offsets = resp->cntdwn_counter_offsets; - resp->data[resp_offsets[i]] = count; +if (resp_offsets[i]) + resp->data[resp_offsets[i]] = count; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 853/1376 wifi: mac80211: disconnect on CSA to channel 0
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <[email protected]>
[ Upstream commit cf57f0a674cc3e3cda1a789359cc1238b61b9d7d ]
The refactor for the CSA parsing erroneously equates channel zero and no information present, leading it to ignore a CSA on an AP that advertises a switch to that (invalid) channel. This leads to not disconnecting, which we should. For Intel devices, this can lead to a firmware crash.
Fix this by using an int type for the channel number as well as the opclass, and using a (negative) value that cannot be encoded in the element to indicate it's not present.
--- net/mac80211/spectmgmt.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
net/mac80211/spectmgmt.c +6 -5
@@ -228,7 +228,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, {enum nl80211_band new_band = current_band;int new_freq; -u8 new_chan_no =0 , new_op_class =0 ; +int new_chan_no =-1 , new_op_class =-1 ;struct ieee80211_channel *new_chan;struct cfg80211_chan_def new_chandef = {};const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
@@ -257,7 +257,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, new_op_class = ext_chansw_elem->new_operating_class;if (!ieee80211_operating_class_to_band (new_op_class, &new_band)) { - new_op_class =0 ; + new_op_class =-1 ;if (!unprot_action) sdata_info(sdata, "cannot understand ECSA IE operating class, %d, ignoring\n",
@@ -269,14 +269,14 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, } } -if (!new_op_class && elems->ch_switch_ie) { +if (new_op_class <0 && elems->ch_switch_ie) { new_chan_no = elems->ch_switch_ie->new_ch_num; csa_ie->count = elems->ch_switch_ie->count; csa_ie->mode = elems->ch_switch_ie->mode; }/* nothing here we understand */ -if (!new_chan_no) +if (new_chan_no <0 )return 1 ;/* Mesh Channel Switch Parameters Element */
@@ -360,7 +360,8 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,get_unaligned_le16 (bwi->info.optional); }else if (!wide_bw_chansw_ie || !wbcs_elem_to_chandef (wide_bw_chansw_ie, &new_chandef)) { -if (!ieee80211_operating_class_to_chandef (new_op_class, new_chan, +if (new_op_class <0 || + !ieee80211_operating_class_to_chandef (new_op_class, new_chan, &new_chandef)) new_chandef = csa_ie->chanreq.oper; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 854/1376 firmware: google: Add bounds checks in coreboot_table_populate()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Titouan Ameline de Cadeville <[email protected]>
[ Upstream commit 7b1a1af4556a4f95ef273e91435fe804cbfcd223 ]
coreboot_table_populate() iterates over firmware-provided table entries with no validation that the entries stay within the mapped memory region. A corrupt table with a large entry->size advances ptr_entry past the mapped region, causing an out-of-bounds read on the next iteration.
Add a check before dereferencing ptr_entry to ensure the entry header is readable, and a second check after reading entry->size to ensure the full entry stays within the mapped region.
Pass len from coreboot_table_probe() into coreboot_table_populate() to make the mapped region size available for validation.
Stable-dep-of: a58a57a1076f ("firmware: coreboot: Validate table bounds")
--- drivers/firmware/google/coreboot_table.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/firmware/google/coreboot_table.c +9 -2
@@ -101,16 +101,20 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) }EXPORT_SYMBOL (coreboot_driver_unregister); -static int coreboot_table_populate (struct device *dev,void *ptr) +static int coreboot_table_populate (struct device *dev,void *ptr,resource_size_t len) {int i, ret;void *ptr_entry;struct coreboot_device *device;struct coreboot_table_entry *entry;struct coreboot_table_header *header = ptr; +void *ptr_end; + ptr_end = ptr + len; ptr_entry = ptr + header->header_bytes;for (i =0 ; i < header->table_entries; i++) { +if (ptr_entry +sizeof (*entry) > ptr_end) +return -EINVAL ; entry = ptr_entry;if (entry->size <sizeof (*entry)) {
@@ -118,6 +122,9 @@ static int coreboot_table_populate(struct device *dev, void *ptr)return -EINVAL ; } +if (ptr_entry + entry->size > ptr_end) +return -EINVAL ; + device =kzalloc (sizeof (device->dev) + entry->size,GFP_KERNEL );if (!device)return -ENOMEM ;
@@ -183,7 +190,7 @@ static int coreboot_table_probe(struct platform_device *pdev)if (!ptr)return -ENOMEM ; - ret =coreboot_table_populate (dev, ptr); + ret =coreboot_table_populate (dev, ptr, len);memunmap (ptr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 855/1376 firmware: coreboot: Validate table bounds
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <[email protected]>
[ Upstream commit a58a57a1076f8c5dae0327e3710899478c3be901 ]
The existing coreboot_table_populate() bounds checks limit individual entries to the mapped length. However, coreboot_table_probe() replaces the platform resource length with header and table sizes supplied by firmware before mapping the full table.
A malformed table can overflow the 32-bit size addition or advertise an extent beyond the resource, causing the driver to map and parse memory outside the resource. A resource shorter than the fixed header is also mapped as though it contained a complete header.
Reject resources shorter than the fixed header. After validating the signature, require a complete header, calculate the advertised extent with overflow checking, and reject extents beyond the resource before remapping the table.
--- drivers/firmware/google/coreboot_table.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
drivers/firmware/google/coreboot_table.c +13 -4
@@ -159,6 +159,7 @@ static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_static int coreboot_table_probe (struct platform_device *pdev) {resource_size_t len; +resource_size_t table_span;struct coreboot_table_header *header;struct resource *res;struct device *dev = &pdev->dev;
@@ -170,7 +171,7 @@ static int coreboot_table_probe(struct platform_device *pdev)return -EINVAL ; len =resource_size (res); -if (!res->start || !len) +if (!res->start || len <sizeof (*header))return -EINVAL ;/* Check just the header first to make sure things are sane */
@@ -178,19 +179,27 @@ static int coreboot_table_probe(struct platform_device *pdev)if (!header)return -ENOMEM ; - len = header->header_bytes + header->table_bytes; ret =strncmp (header->signature,"LBIO" ,sizeof (header->signature)); + +if (!ret && + (header->header_bytes <sizeof (*header) || +check_add_overflow ((resource_size_t )header->header_bytes, + (resource_size_t )header->table_bytes, + &table_span) || + table_span > len)) + ret = -EINVAL ; +memunmap (header);if (ret) {dev_warn (dev,"coreboot table missing or corrupt!\n" );return -ENODEV ; } - ptr =memremap (res->start, len,MEMREMAP_WB ); + ptr =memremap (res->start, table_span,MEMREMAP_WB );if (!ptr)return -ENOMEM ; - ret =coreboot_table_populate (dev, ptr, len); + ret =coreboot_table_populate (dev, ptr, table_span);memunmap (ptr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 856/1376 powerpc/smp: add NULL guard for cause_ipi in smp_muxed_ipi_message_pass
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <[email protected]>
[ Upstream commit 5aabc192702defb8950e7c81b05c3f4ca8ee43ec ]
smp_muxed_ipi_message_pass() calls smp_ops->cause_ipi() without checking whether it has been set.
On platforms using muxed IPI (e.g. powernv/pseries), smp_ops->cause_ipi is initialized to NULL in the static smp_ops and only assigned during the platform smp_probe() handler. If the IPI subsystem fails to initialize -- for example when xive_init_ipis() fails and xive_smp_probe() returns an error -- the probe handler returns early and cause_ipi is never set. Any subsequent IPI send (e.g. arch_smp_send_reschedule()) would dereference the NULL pointer.
Add a NULL check to avoid the crash in that situation.
--- arch/powerpc/kernel/smp.c | 3 +++ 1 file changed, 3 insertions(+)
arch/powerpc/kernel/smp.c +3 -0
@@ -288,6 +288,9 @@ void smp_muxed_ipi_set_message(int cpu, int msg)void smp_muxed_ipi_message_pass (int cpu,int msg) { +if (!smp_ops->cause_ipi) +return ; +smp_muxed_ipi_set_message (cpu, msg);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 857/1376 powerpc/irq: Fix missing r2 clobber in PCREL inline assembly
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Saket Kumar Bhaskar <[email protected]>
[ Upstream commit 00be69070d91d2be978e752bb117a0a4db0e1281 ]
In CONFIG_PPC_KERNEL_PCREL mode, r2 is no longer reserved for the TOC pointer and is available as a caller-saved register [0].
Both call_do_irq() and call_do_softirq() use inline assembly to call functions with stack switching, but fail to list r2 in their clobber lists. This causes the compiler to assume r2 is preserved across these calls, leading to register corruption when the called functions (__do_irq and __do_softirq) clobber r2.
As a result of this kernel crash during interrupt handling is seen and the kernel fails to boot:
BUG: Unable to handle kernel data access on write at 0xc000000404697638 Faulting instruction address: 0xc0000000000181ec Oops: Kernel access of bad area, sig: 11 [#1] NIP [c0000000000181ec] __do_IRQ+0x6c/0xc0
With older GCC, the compiler would conservatively allocate callee-saved registers (like r31) for values spanning function calls, accidentally avoiding the bug:
<__do_IRQ>:
00 00 00 60 nop
a6 02 08 7c mflr r0 f8 ff e1 fb std r31,-8(r1) f0 ff c1 fb std r30,-16(r1) 2d 03 10 06 pla r31,53297316
...
3d e8 ff 4b bl c0000000000165ac <__do_irq> 00 00 21 e8 ld r1,0(r1) 28 00 4d e9 ld r10,40(r13) 40 00 21 38 addi r1,r1,64 2a f9 aa 7f stdx r29,r10,r31
With newer GCC 14, the compiler uses r2 for such values, exposing the missing clobber specification:
<__do_IRQ>:
00 00 00 60 nop a6 02 08 7c mflr r0 f0 ff c1 fb std r30,-16(r1) f8 ff e1 fb std r31,-8(r1) 29 02 10 06 pla r2,36252592 # c0000000022aadc0 <__irq_regs>
...
85 dc ff 4b bl c000000000015ee0 <__do_irq> 00 00 21 e8 ld r1,0(r1) 28 00 2d e9 ld r9,40(r13) 30 00 21 38 addi r1,r1,48 2a 11 c9 7f stdx r30,r9,r2
Fix this by adding r2 to the clobber list for both call_do_irq() and call_do_softirq() when CONFIG_PPC_KERNEL_PCREL is enabled.
[0]: https://www.mail-archive.com/[email protected]/msg313226.html
--- arch/powerpc/kernel/irq.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
arch/powerpc/kernel/irq.c +12 -4
@@ -217,8 +217,12 @@ static __always_inline void call_do_softirq(const void *sp) [sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE), [callee] "i" (__do_softirq) : // Clobbers -"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" , -"cr7" ,"r0" ,"r3" ,"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" , +"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" ,"cr7" ,"r0" , +/* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */ +#ifdef CONFIG_PPC_KERNEL_PCREL +"r2" , +#endif +"r3" ,"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" ,"r11" ,"r12" ); }
@@ -275,8 +279,12 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) [sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE), [callee] "i" (__do_irq) : // Clobbers -"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" , -"cr7" ,"r0" ,"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" , +"lr" ,"xer" ,"ctr" ,"memory" ,"cr0" ,"cr1" ,"cr5" ,"cr6" ,"cr7" ,"r0" , +/* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */ +#ifdef CONFIG_PPC_KERNEL_PCREL +"r2" , +#endif +"r4" ,"r5" ,"r6" ,"r7" ,"r8" ,"r9" ,"r10" ,"r11" ,"r12" ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 858/1376 MIPS: ptrace: Fix syscall skipping via PTRACE_SYSCALL
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Bogendoerfer <[email protected]>
[ Upstream commit 5475c03fa25f31cfd5f8c7e552f8d10347bbaad9 ]
If tracer wanted to skip a syscall return value was always overwritten with -ENOSYS. Fix this by checking against original syscall number and only return -ENOSYS, if it is negative.
--- arch/mips/kernel/ptrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/mips/kernel/ptrace.c +5 -1
@@ -1319,8 +1319,12 @@ long arch_ptrace(struct task_struct *child, long request,*/ asmlinkage long syscall_trace_enter (struct pt_regs *regs) { +long syscall; +user_exit (); + syscall =current_thread_info ()->syscall; +if (test_thread_flag (TIF_SYSCALL_TRACE )) {if (ptrace_report_syscall_entry (regs))return -1 ;
@@ -1356,7 +1360,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs)* Negative syscall numbers are mistaken for rejected syscalls, but * won't have had the return value set appropriately, so we do so now. */ -if (current_thread_info ()->syscall <0 ) +if (syscall <0 )syscall_set_return_value (current, regs, -ENOSYS ,0 );return current_thread_info ()->syscall; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 859/1376 serial: amba-pl011: unprepare console clock on unregister
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 7f93da9d78d433c37836d85de475c5d884ad58ed ]
pl011_console_setup() calls clk_prepare() on the UART clock, but the console provides no matching teardown, so the clock is never unprepared when the console is unregistered -- via the sysfs "console" attribute or a driver unbind. Each re-registration prepares the clock again, leaking one prepare reference per cycle.
Even where preparing the clock has no hardware effect, the stale reference leaves the clock framework's prepare count unbalanced. For providers with prepare/unprepare operations or runtime-PM integration, it may also retain resources after the console is unregistered.
Add a console .exit() callback that clk_unprepare()s the clock, balancing the clk_prepare() in pl011_console_setup().
--- drivers/tty/serial/amba-pl011.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/tty/serial/amba-pl011.c +10 -0
@@ -2434,6 +2434,15 @@ static int pl011_console_setup(struct console *co, char *options)return uart_set_options (&uap->port, co, baud, parity, bits, flow); } +static int pl011_console_exit (struct console *co) +{ +struct uart_amba_port *uap = amba_ports[co->index]; + +clk_unprepare (uap->clk); + +return 0 ; +} +/** * pl011_console_match - non-standard console matching * @co: registering console
@@ -2500,6 +2509,7 @@ static struct console amba_console = { .write = pl011_console_write, .device = uart_console_device, .setup = pl011_console_setup, + .exit = pl011_console_exit, .match = pl011_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 860/1376 tty: clear cdev pointer after cdev_add() failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 6645856f0df3aeecd45519cb611415b4b89c2223 ]
tty_cdev_add() drops the cdev reference when cdev_add() fails, but leaves driver->cdevs[index] pointing to freed memory. tty_unregister_device() later passes that stale pointer to cdev_del(), causing a use-after-free.
Clear the slot after dropping the reference.
--- drivers/tty/tty_io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/tty/tty_io.c +3 -1
@@ -3181,8 +3181,10 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, driver->cdevs[index]->ops = &tty_fops; driver->cdevs[index]->owner = driver->owner; err =cdev_add (driver->cdevs[index], dev, count); -if (err) +if (err) {kobject_put (&driver->cdevs[index]->kobj); + driver->cdevs[index] =NULL ; + }return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 861/1376 HID: i2c-hid: Refactor _DSM helper and add i2c-hid-acpi-prp0001 driver
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: 谢致邦 (XIE Zhibang) <[email protected]>
[ Upstream commit fd7c67d05fb695b1deb07f9e213dd7e80e3a8427 ]
Move the _DSM call that gets the HID descriptor address from i2c-hid-acpi.c into i2c-hid-acpi.h as a static inline so both the ACPI and the new PRP0001 driver can use it. While refactoring, move the blacklist check and the _DSM call to the top of probe() to avoid a pointless alloc when the device is blacklisted or does not implement the _DSM.
Some devices, for example the Lenovo KaiTian N60d and Inspur CP300L3, are declared with _HID "PRP0001" and _DSD compatible "hid-over-i2c" but lack "hid-descr-addr" from the _DSD and provide the HID descriptor address only through an ACPI _DSM. The OF driver fails to probe them because it requires hid-descr-addr. Add a new driver that handles these devices by calling the shared _DSM helper.
--- drivers/hid/i2c-hid/Makefile | 2 +- drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c | 104 +++++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-acpi.c | 52 +++-------- drivers/hid/i2c-hid/i2c-hid-acpi.h | 33 +++++++ 4 files changed, 152 insertions(+), 39 deletions(-) create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c create mode 100644 drivers/hid/i2c-hid/i2c-hid-acpi.h
drivers/hid/i2c-hid/Makefile +1 -1
@@ -8,7 +8,7 @@ obj-$(CONFIG_I2C_HID_CORE) += i2c-hid.o i2c-hid-objs = i2c-hid-core.o i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o -obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o +obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o i2c-hid-acpi-prp0001.o obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o obj-$(CONFIG_I2C_HID_OF_ELAN) += i2c-hid-of-elan.o obj-$(CONFIG_I2C_HID_OF_GOODIX) += i2c-hid-of-goodix.o
drivers/hid/i2c-hid/i2c-hid-acpi-prp0001.c new file +104 -0
104 lines not on this page · raw message
drivers/hid/i2c-hid/i2c-hid-acpi.c +14 -38
86 lines not on this page · raw message
drivers/hid/i2c-hid/i2c-hid-acpi.h new file +33 -0
@@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _I2C_HID_ACPI_H +#define _I2C_HID_ACPI_H + +#include <linux/acpi.h> +#include <linux/uuid.h> + +static inline int i2c_hid_acpi_get_descriptor (struct acpi_device *adev) +{ +/* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */ +static const guid_t i2c_hid_guid = +GUID_INIT (0x3CDFF6F7 ,0x4267 ,0x4555 , +0xAD ,0x05 ,0xB3 ,0x0A ,0x3D ,0x89 ,0x38 ,0xDE ); + +acpi_handle handle =acpi_device_handle (adev); +union acpi_object *obj; +u16 addr; + + obj =acpi_evaluate_dsm_typed (handle, &i2c_hid_guid, +1 ,1 ,NULL ,ACPI_TYPE_INTEGER ); +if (!obj) { +acpi_handle_err (handle, +"Error _DSM call to get HID descriptor address failed\n" ); +return -ENODEV ; + } + + addr = obj->integer.value; +ACPI_FREE (obj); +return addr; +} + +#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 862/1376 HID: synchronize input before cleaning up a failed probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
[ Upstream commit 207853d46f7ef2e28042344a1468da8754c3ddbf ]
hid_device_io_start() allows reports to run concurrently with probe. If the probe subsequently fails, __hid_device_probe() releases driver resources and clears hdev->driver without first excluding those report callbacks.
For example, a report may enter hidraw_report_event() while the failure path frees the associated hidraw object, leading to a use-after-free when the report takes the object's list lock.
Stop input before performing failed-probe cleanup. This reacquires driver_input_lock and waits for any report callback already in progress.
--- drivers/hid/hid-core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/hid/hid-core.c +2 -0
@@ -2780,6 +2780,8 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)*/ if (ret) { +if (hdev->io_started) +hid_device_io_stop (hdev);devres_release_group (&hdev->dev, hdev->devres_group_id);hid_close_report (hdev); hdev->driver =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 863/1376 HID: i2c-hid: Fix "(null)" output when reading report descriptor fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ai Chao <[email protected]>
[ Upstream commit 8da0f0951deec9f0728ed2d9c54ded1c344b7542 ]
When i2c-hid fails to read the HID report descriptor during device initialization, the error message prints as:
hid (null): reading report descriptor failed
The HID device name is set in hid_add_device() after calling hdev->ll_driver->parse(), so when i2c_hid_parse() fails and calls hid_err(), the device name has not been set yet, resulting in "(null)" output.
Use dev_err(&client->dev, ...) instead of hid_err(hid, ...) because the I2C client device is fully initialized with a proper name, providing meaningful error messages for debugging.
Before: hid (null): reading report descriptor failed After: i2c_hid i2c-TPD0001:00: reading report descriptor failed
--- drivers/hid/i2c-hid/i2c-hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hid/i2c-hid/i2c-hid-core.c +1 -1
@@ -784,7 +784,7 @@ static int i2c_hid_parse(struct hid_device *hid) ihid->hdesc.wReportDescRegister, rdesc, rsize);if (ret) { -hid_err (hid,"reading report descriptor failed\n" ); +dev_err (&client->dev,"reading report descriptor failed\n" ); goto out; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 864/1376 HID: i2c-hid: goodix: Disable VDD on VDDIO enable failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Huang <[email protected]>
[ Upstream commit 8e2c560faea0220664169f7be4b498915ea1469f ]
If enabling VDDIO fails after VDD has been enabled, the power-up path returns without disabling VDD. This leaves the regulator enabled and its enable count unbalanced.
Disable VDD before returning the VDDIO error.
--- drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hid/i2c-hid/i2c-hid-of-goodix.c +3 -1
@@ -51,8 +51,10 @@ static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)return ret; ret =regulator_enable (ihid_goodix->vddio); -if (ret) +if (ret) { +regulator_disable (ihid_goodix->vdd);return ret; + }if (ihid_goodix->timings->post_power_delay_ms)msleep (ihid_goodix->timings->post_power_delay_ms);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 865/1376 HID: lg4ff: validate report length before fixed offsets
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiancheng Huang <[email protected]>
[ Upstream commit be00988cce4ed44db1e61231d0ab71a64bab44cd ]
lg4ff_raw_event() rewrites fixed report offsets when combined pedals are enabled. It currently assumes that each product report contains every source and destination byte used by the rewrite.
Return without rewriting a short report before each product-specific access. Apply the same bound to the computed offset path.
--- drivers/hid/hid-lg4ff.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/hid/hid-lg4ff.c +8 -0
@@ -336,6 +336,8 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,if (entry->wdata.combine) {switch (entry->wdata.product_id) {case USB_DEVICE_ID_LOGITECH_WHEEL : +if (size <7 ) +return 0 ; rd[5 ] = rd[3 ]; rd[6 ] =0x7F ;return 1 ;
@@ -343,10 +345,14 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG :case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL :case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 : +if (size <6 ) +return 0 ; rd[4 ] = rd[3 ]; rd[5 ] =0x7F ;return 1 ;case USB_DEVICE_ID_LOGITECH_DFP_WHEEL : +if (size <7 ) +return 0 ; rd[5 ] = rd[4 ]; rd[6 ] =0x7F ;return 1 ;
@@ -366,6 +372,8 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report, }/* Compute a combined axis when wheel does not supply it */ +if (size <= offset +1 ) +return 0 ; rd[offset] = (0xFF + rd[offset] - rd[offset+1 ]) >>1 ; rd[offset+1 ] =0x7F ;return 1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 866/1376 perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit ab9c84d1cd59e6b3b73de34982a35a76e3a9b032 ]
thread_stack__br_sample() copies the wrap-around portion of the branch stack ring buffer with:
nr = min(ts->br_stack_pos, sz); memcpy(be, &src->entries[0], bsz * ts->br_stack_pos);
'nr' is correctly bounded to min(br_stack_pos, sz) but the memcpy uses the unbounded ts->br_stack_pos directly. When br_stack_pos exceeds the remaining destination space 'sz', this writes past the destination buffer.
Use 'nr' (the bounded value) in the memcpy size, matching the pattern of the first memcpy in the same function.
--- tools/perf/util/thread-stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/thread-stack.c +1 -1
@@ -642,7 +642,7 @@ void thread_stack__br_sample(struct thread *thread, int cpu, sz -= nr; be = &dst->entries[nr]; nr =min (ts->br_stack_pos, sz); -memcpy (be, &src->entries[0 ], bsz * ts->br_stack_pos); +memcpy (be, &src->entries[0 ], bsz * nr); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 867/1376 perf auxtrace: Fix queue grow overflow and old array leak
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 96fcc9ea5f18c083a1fa73da23afef7e953f7dca ]
auxtrace_queues__grow() has two bugs:
1. When idx is UINT_MAX, the caller passes new_nr_queues = idx + 1 = 0. The function skips growing (since any nr_queues >= 0), returns success, and the caller accesses queue_array[UINT_MAX] — an OOB heap write. Fix by rejecting new_nr_queues == 0 up front.
2. The function allocates a new queue_array via calloc and copies elements from the old array, but never frees the old array. Fix by saving the old pointer and freeing it after the copy.
--- tools/perf/util/auxtrace.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
tools/perf/util/auxtrace.c +10 -5
@@ -237,8 +237,12 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues, {unsigned int nr_queues = queues->nr_queues;struct auxtrace_queue *queue_array; +struct auxtrace_queue *old_array = queues->queue_array;unsigned int i; +if (!new_nr_queues) +return -EINVAL ; +if (!nr_queues) nr_queues =AUXTRACE_INIT_NR_QUEUES ;
@@ -253,16 +257,17 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,return -ENOMEM ;for (i =0 ; i < queues->nr_queues; i++) { -list_splice_tail (&queues->queue_array[i].head, +list_splice_tail (&old_array[i].head, &queue_array[i].head); - queue_array[i].tid = queues->queue_array[i].tid; - queue_array[i].cpu = queues->queue_array[i].cpu; - queue_array[i].set = queues->queue_array[i].set; - queue_array[i].priv = queues->queue_array[i].priv; + queue_array[i].tid = old_array[i].tid; + queue_array[i].cpu = old_array[i].cpu; + queue_array[i].set = old_array[i].set; + queue_array[i].priv = old_array[i].priv; } queues->nr_queues = nr_queues; queues->queue_array = queue_array; +free (old_array);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 868/1376 perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit c4362d5e1a5ed4ce2098798f655a636c4340fa20 ]
min_sz is set to sizeof(u64) * INTEL_PT_PER_CPU_MMAPS, but the code accesses auxtrace_info->priv[INTEL_PT_PER_CPU_MMAPS], which requires at least INTEL_PT_PER_CPU_MMAPS + 1 elements. A file with exactly min_sz bytes of priv data passes the size check but the access reads one u64 past the validated region.
Use (INTEL_PT_PER_CPU_MMAPS + 1) to ensure the highest accessed index is within bounds.
--- tools/perf/util/intel-pt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/intel-pt.c +1 -1
@@ -4359,7 +4359,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event, struct perf_session *session) {struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; -size_t min_sz =sizeof (u64) *INTEL_PT_PER_CPU_MMAPS ; +size_t min_sz =sizeof (u64) * (INTEL_PT_PER_CPU_MMAPS +1 );struct intel_pt *pt;void *info_end;__u64 *info;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 869/1376 perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit b9fb8225951ce27e62a2235a71f3ab01137aaec3 ]
Same pattern as the Intel PT fix: min_sz is set to sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE, but the code accesses auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE], which requires at least INTEL_BTS_SNAPSHOT_MODE + 1 elements.
Use (INTEL_BTS_SNAPSHOT_MODE + 1) to ensure the highest accessed index is within bounds.
--- tools/perf/util/intel-bts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/intel-bts.c +1 -1
@@ -829,7 +829,7 @@ int intel_bts_process_auxtrace_info(union perf_event *event, struct perf_session *session) {struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; -size_t min_sz =sizeof (u64) *INTEL_BTS_SNAPSHOT_MODE ; +size_t min_sz =sizeof (u64) * (INTEL_BTS_SNAPSHOT_MODE +1 );struct intel_bts *bts;int err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 870/1376 iio: light: tsl2772: fix ALS calibscale readback
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuanshen Cao <[email protected]>
[ Upstream commit ac75550ab5b5d73649bffea245c2075fd9249bd0 ]
The read_raw() implementation uses IIO_LIGHT to distinguish between the ambient light and proximity channels when handling IIO_CHAN_INFO_CALIBSCALE.
However, the ALS channel is registered as IIO_INTENSITY, while write_raw() correctly writes to IIO_INTENSITY. As a result, reading in_intensity0_calibscale incorrectly returns the proximity gain instead of the ALS gain.
This causes the following user-visible behavior:
- Writing in_intensity0_calibscale appears to have no effect because the readback reports the proximity gain.
- Writing in_proximity0_calibscale causes both in_proximity0_calibscale and in_intensity0_calibscale to report the same value.
Fix this by checking for IIO_INTENSITY in read_raw(), matching the channel definition and the existing write_raw() implementation.
--- drivers/iio/light/tsl2772.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/tsl2772.c +1 -1
@@ -1263,7 +1263,7 @@ static int tsl2772_read_raw(struct iio_dev *indio_dev, }break ;case IIO_CHAN_INFO_CALIBSCALE : -if (chan->type ==IIO_LIGHT ) +if (chan->type ==IIO_INTENSITY ) *val = tsl2772_als_gain[chip->settings.als_gain];else *val = tsl2772_prox_gain[chip->settings.prox_gain];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 871/1376 iio: light: isl29028: return zero in write_raw() on success
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Heon Jeon <[email protected]>
[ Upstream commit 55b75622829779223b9e32aa9600a8651d3e2df4 ]
isl29028_write_raw() returns the value of pm_runtime_put_autosuspend(), which is 1 if the device is already runtime suspended.
In that case write() on the sysfs attribute returns 1 instead of the number of bytes written. Make isl29028_write_raw() always return zero on success.
--- drivers/iio/light/isl29028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/isl29028.c +1 -1
@@ -414,7 +414,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,if (ret <0 )return ret; -return ret; +return 0 ; } static int isl29028_read_raw(struct iio_dev *indio_dev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 872/1376 iio: light: tsl2583: return zero in write_raw() on success
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Heon Jeon <[email protected]>
[ Upstream commit 42e8791841e0677418a3ccc97fa5c22a1455f417 ]
tsl2583_write_raw() returns the value of pm_runtime_put_autosuspend(), which is 1 if the device is already runtime suspended.
In that case write() on the sysfs attribute returns 1 instead of the number of bytes written. Make tsl2583_write_raw() always return zero on success.
--- drivers/iio/light/tsl2583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/tsl2583.c +1 -1
@@ -800,7 +800,7 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,if (ret <0 )return ret; -return ret; +return 0 ; }static const struct iio_info tsl2583_info = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 873/1376 net: stmmac: Skip PHY attach if custom PCS is in use
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zxyan Zhu <[email protected]>
[ Upstream commit af4d934164457f0578bf90e92ae0fcc5348260cb ]
When a platform provides a custom PCS via the pcs_init callback, the MAC's phylink_pcs is already configured. In this case, no traditional PHY device is needed.
Without this, stmmac_init_phy() falls through to the no-phy-node path and errors out with "no phy found" when the DT has no phy-handle for such interfaces.
Skip the PHY attach when priv->hw->phylink_pcs is set and phy_addr is invalid.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +4 -0
@@ -1183,6 +1183,10 @@ static int stmmac_init_phy(struct net_device *dev)struct phy_device *phydev;if (addr <0 ) { +/* If a custom PCS is in use, no PHY is needed */ +if (priv->hw->phylink_pcs) +return 0 ; +netdev_err (priv->dev,"no phy found\n" );return -ENODEV ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 874/1376 phonet: pep: do not write beyond optlen in getsockopt
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 77e5eb0e192aec6710c03ca8144582fd2af36ca4 ]
pep_getsockopt() clamps the reported length to the caller's buffer with min_t(), but then stores the value with put_user(val, (int __user *) optval), which always writes sizeof(int) bytes. A getsockopt() call with an optlen smaller than sizeof(int) thus reports the clamped length yet writes a full int, one to three bytes past the user buffer.
Write the value with copy_to_user() bounded by len, so at most optlen bytes are copied, matching the length reported back to userspace.
--- net/phonet/pep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/phonet/pep.c +1 -1
@@ -1116,7 +1116,7 @@ static int pep_getsockopt(struct sock *sk, int level, int optname, len = min_t(unsigned int, sizeof(int), len);if (put_user (len, optlen))return -EFAULT ; -if (put_user (val, (int __user *) optval)) +if (copy_to_user (optval, &val, len))return -EFAULT ;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 875/1376 blk-cgroup: skip dying blkg in blkcg_activate_policy()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zheng Qixing <[email protected]>
[ Upstream commit 5e9220389920f33b6a804d50c548cd0cd1b04634 ]
When switching IO schedulers on a block device, blkcg_activate_policy() can race with concurrent blkcg deletion, leading to a use-after-free in rcu_accelerate_cbs.
T1: T2:
blkg_destroy
kill(&blkg->refcnt) // blkg->refcnt=1->0
blkg_release // call_rcu(__blkg_release)
...
blkg_free_workfn
->pd_free_fn(pd)elv_iosched_storeelevator_switch
...
iterate blkg listblkg_get(blkg) // blkg->refcnt=0->1
list_del_init(&blkg->q_node)
blkg_put(pinned_blkg) // blkg->refcnt=1->0blkg_release // call_rcu againrcu_accelerate_cbs // uaf
Fix this by checking hlist_unhashed(&blkg->blkcg_node) before getting a reference to the blkg. This is the same check used in blkg_destroy() to detect if a blkg has already been destroyed. If the blkg is already unhashed, skip processing it since it's being destroyed.
--- block/blk-cgroup.c | 2 ++ 1 file changed, 2 insertions(+)
block/blk-cgroup.c +2 -0
@@ -1573,6 +1573,8 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)if (blkg->pd[pol->plid])continue ; +if (hlist_unhashed (&blkg->blkcg_node)) +continue ;/* If prealloc matches, use it; otherwise try GFP_NOWAIT */ if (blkg == pinned_blkg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 876/1376 block/blk-stat: drain per-cpu callback stats over possible CPUs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 9d617828cfc4d9a4d385daa2cd61f9db0592c53f ]
blk_stat_timer_fn() sums and resets a callback's per-cpu buckets using for_each_online_cpu(). A CPU that goes offline with pending samples is skipped, so its samples are neither accumulated into the window nor cleared; they sit in the bucket until the CPU comes back online, at which point the stale values are flushed into whatever window is then running.
This silently corrupts the latency picture that consumers (notably writeback throttling via wbt, and blk-mq latency tracking) base decisions on around CPU hotplug: under-counting while the CPU is offline, then a burst of stale data on re-online.
--- block/blk-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/blk-stat.c +1 -1
@@ -83,7 +83,7 @@ static void blk_stat_timer_fn(struct timer_list *t)for (bucket =0 ; bucket < cb->buckets; bucket++)blk_rq_stat_init (&cb->stat[bucket]); -for_each_online_cpu (cpu) { +for_each_possible_cpu (cpu) {struct blk_rq_stat *cpu_stat; cpu_stat =per_cpu_ptr (cb->cpu_stat, cpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 877/1376 block/blk-iocost: collect per-cpu latency stats over possible CPUs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 4e050c5b92c1600415b2cd452583e543036f3d73 ]
ioc_lat_stat() walks ioc->pcpu_stat with for_each_online_cpu() to compute missed-ppm and rq_wait deltas. An offlined CPU is skipped, so its delta is dropped from the period and its last_* watermark is not advanced; on re-online the next collection sees a delta spanning the whole offline interval, corrupting the latency/vrate picture.
--- block/blk-iocost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/blk-iocost.c +1 -1
@@ -1603,7 +1603,7 @@ static void ioc_lat_stat(struct ioc *ioc, u32 *missed_ppm_ar, u32 *rq_wait_pct_pu64 rq_wait_ns =0 ;int cpu, rw; -for_each_online_cpu (cpu) { +for_each_possible_cpu (cpu) {struct ioc_pcpu_stat *stat =per_cpu_ptr (ioc->pcpu_stat, cpu);u64 this_rq_wait_ns;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 878/1376 block/kyber-iosched: flush per-cpu latency buckets over possible CPUs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
[ Upstream commit 482fc257de95ab181688e9d1dfcc6b6a58857b1e ]
kyber_timer_fn() sums the per-cpu latency histograms with for_each_online_cpu(). A CPU that goes offline mid-interval leaves its bucket un-flushed; the samples are lost from the current decision and re-appear (stale) when the CPU is onlined again.
--- block/kyber-iosched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
block/kyber-iosched.c +1 -1
@@ -279,7 +279,7 @@ static void kyber_timer_fn(struct timer_list *t)bool bad = false;/* Sum all of the per-cpu latency histograms. */ -for_each_online_cpu (cpu) { +for_each_possible_cpu (cpu) {struct kyber_cpu_latency *cpu_latency; cpu_latency =per_cpu_ptr (kqd->cpu_latency, cpu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 879/1376 ublk: check for ublk_unmap_io() returning 0
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Caleb Sander Mateos <[email protected]>
[ Upstream commit 24fd3706178f1ae5501fd1ff9036e170ed0665ba ]
If the userspace ublk server passes an unmapped address as the data buffer for a completed ublk read, ublk_unmap_io() will return 0 indicating no bytes could be copied. Currently, this will result in calling blk_update_request() with nr_bytes=0, which doesn't seem supported. Fail the I/O with BLK_STS_IOERR in this case instead.
--- drivers/block/ublk_drv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/block/ublk_drv.c +7 -1
@@ -1072,8 +1072,14 @@ static inline void __ublk_complete_rq(struct request *req)* * Re-read simply for this unlikely case. */ -if (unlikely (unmapped_bytes < io->res)) +if (unlikely (unmapped_bytes < io->res)) { +if (unlikely (!unmapped_bytes)) { + res =BLK_STS_IOERR ; + goto exit; + } + io->res = unmapped_bytes; + }/* * Run bio->bi_end_io() with softirqs disabled. If the final fput
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 880/1376 o2hb_region_dev_store(): avoid goto around fdget()/fdput()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <[email protected]>
[ Upstream commit 554ceb7a5e14435725ac59a42bf0708f95721405 ]
Preparation for CLASS(fd) conversion.
Stable-dep-of: 688bc88e2046 ("ocfs2/cluster: keep heartbeat local node stable")
--- fs/ocfs2/cluster/heartbeat.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
fs/ocfs2/cluster/heartbeat.c +5 -6
@@ -1778,23 +1778,23 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,int live_threshold;if (reg->hr_bdev_file) - goto out; +return -EINVAL ;/* We can't heartbeat without having had our node number * configured yet. */ if (o2nm_this_node () ==O2NM_MAX_NODES ) - goto out; +return -EINVAL ; fd =simple_strtol (p, &p,0 );if (!p || (*p && (*p !='\n' ))) - goto out; +return -EINVAL ;if (fd <0 || fd >=INT_MAX ) - goto out; +return -EINVAL ; f =fdget (fd);if (fd_file (f) ==NULL ) - goto out; +return -EINVAL ;if (reg->hr_blocks ==0 || reg->hr_start_block ==0 || reg->hr_block_bytes ==0 )
@@ -1916,7 +1916,6 @@ static ssize_t o2hb_region_dev_store(struct config_item *item, } out2:fdput (f); -out:return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 881/1376 ocfs2/cluster: keep heartbeat local node stable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 688bc88e2046dd6ce81ce18079b5254cb8dadc0e ]
o2nm_node_local_store() handles local=0 by stopping o2net and setting cl_local_node to O2NM_INVALID_NODE_NUM, but it leaves cl_has_local set. That stale state makes o2nm_this_node() return 255, blocks a later local=1 attempt with -EBUSY, and can feed 255 to heartbeat users that call o2nm_this_node() dynamically.
Clearing cl_has_local is required when the local node is reset. But heartbeat threads can still be running at that point. They pin the local node config item at startup, yet o2hb_do_disk_heartbeat() and thread teardown re-read o2nm_this_node() for the local slot and for o2nm_undepend_this_node(). Once local=0 has cleared the live local-node state, those dynamic reads return O2NM_MAX_NODES, which is also the invalid node number 255.
Store the local node number in the heartbeat region when the region starts. Use that stable node for heartbeat slot writes/checks, negotiation messages, and the final configfs undepend. Stop the heartbeat loop when the current local node no longer matches the stored node, and clear cl_has_local together with cl_local_node in the local=0 path so nodemanager state matches node removal.
Validation reproduced this kernel report:
KASAN slab-out-of-bounds in o2hb_do_disk_heartbeat+0x372/0xb30
RIP: 0010:memset+0xf/0x20 Read of size 8 Call trace: dump_stack_lvl+0x66/0xa0 print_report+0xd0/0x630 o2hb_do_disk_heartbeat+0x372/0xb30 (fs/ocfs2/cluster/heartbeat.c:1079) srso_alias_return_thunk+0x5/0xfbef5 __virt_addr_valid+0x188/0x2f0 kasan_report+0xe4/0x120 o2hb_do_disk_heartbeat+0x5/0xb30 (fs/ocfs2/cluster/heartbeat.c:1079) o2hb_thread+0x14e/0x770 kthread_affine_node+0x139/0x180 lockdep_hardirqs_on_prepare+0xda/0x190 trace_hardirqs_on+0x18/0x130 kthread+0x19d/0x1e0 ret_from_fork+0x37a/0x4d0 __switch_to+0x2d5/0x6f0 ret_from_fork_asm+0x1a/0x30
--- fs/ocfs2/cluster/heartbeat.c | 43 +++++++++++++++++++++++----------- fs/ocfs2/cluster/nodemanager.c | 19 +++++++++++---- fs/ocfs2/cluster/nodemanager.h | 2 ++ 3 files changed, 46 insertions(+), 18 deletions(-)
fs/ocfs2/cluster/heartbeat.c +29 -14
@@ -210,6 +210,7 @@ struct o2hb_region {/* protected by the hr_callback_sem */ struct task_struct *hr_task; +u8 hr_node_num;unsigned int hr_blocks;unsigned long long hr_start_block;
@@ -357,12 +358,12 @@ static void o2hb_disarm_timeout(struct o2hb_region *reg)cancel_delayed_work_sync (®->hr_nego_timeout_work); } -static int o2hb_send_nego_msg (int key,int type,u8 target) +static int o2hb_send_nego_msg (int key,int type,u8 target,u8 node_num) {struct o2hb_nego_msg msg;int status, ret; - msg.node_num =o2nm_this_node (); + msg.node_num = node_num; again: ret =o2net_send_message (type, key, &msg,sizeof (msg), target, &status);
@@ -380,8 +381,10 @@ static void o2hb_nego_timeout(struct work_struct *work)unsigned long live_node_bitmap[BITS_TO_LONGS (O2NM_MAX_NODES )];int master_node, i, ret;struct o2hb_region *reg; +u8 node_num; reg = container_of(work, struct o2hb_region, hr_nego_timeout_work.work); + node_num = reg->hr_node_num;/* don't negotiate timeout if last hb failed since it is very * possible io failed. Should let write timeout fence self. */
@@ -392,10 +395,10 @@ static void o2hb_nego_timeout(struct work_struct *work)/* lowest node as master node to make negotiate decision. */ master_node =find_first_bit (live_node_bitmap,O2NM_MAX_NODES ); -if (master_node ==o2nm_this_node ()) { +if (master_node == node_num) {if (!test_bit (master_node, reg->hr_nego_node_bitmap)) {printk (KERN_NOTICE "o2hb: node %d hb write hung for %ds on region %s (%pg).\n" , -o2nm_this_node (),O2HB_NEGO_TIMEOUT_MS /1000 , + node_num,O2HB_NEGO_TIMEOUT_MS /1000 ,config_item_name (®->hr_item),reg_bdev (reg));set_bit (master_node, reg->hr_nego_node_bitmap); }
@@ -424,7 +427,7 @@ static void o2hb_nego_timeout(struct work_struct *work)mlog (ML_HEARTBEAT ,"send NEGO_APPROVE msg to node %d\n" , i); ret =o2hb_send_nego_msg (reg->hr_key, -O2HB_NEGO_APPROVE_MSG , i); +O2HB_NEGO_APPROVE_MSG , i, node_num);if (ret)mlog (ML_ERROR ,"send NEGO_APPROVE msg to node %d fail %d\n" , i, ret);
@@ -432,10 +435,10 @@ static void o2hb_nego_timeout(struct work_struct *work) }else {/* negotiate timeout with master node. */ printk (KERN_NOTICE "o2hb: node %d hb write hung for %ds on region %s (%pg), negotiate timeout with node %d.\n" , -o2nm_this_node (),O2HB_NEGO_TIMEOUT_MS /1000 ,config_item_name (®->hr_item), + node_num,O2HB_NEGO_TIMEOUT_MS /1000 ,config_item_name (®->hr_item),reg_bdev (reg), master_node); ret =o2hb_send_nego_msg (reg->hr_key,O2HB_NEGO_TIMEOUT_MSG , - master_node); + master_node, node_num);if (ret)mlog (ML_ERROR ,"send NEGO_TIMEOUT msg to node %d fail %d\n" , master_node, ret);
@@ -608,7 +611,9 @@ static int o2hb_issue_node_write(struct o2hb_region *reg,o2hb_bio_wait_init (write_wc); - slot =o2nm_this_node (); + slot = reg->hr_node_num; +if (slot >=O2NM_MAX_NODES ) +return -EINVAL ; bio =o2hb_setup_one_bio (reg, write_wc, &slot, slot+1 ,REQ_OP_WRITE |REQ_SYNC );
@@ -677,8 +682,12 @@ static int o2hb_check_own_slot(struct o2hb_region *reg)struct o2hb_disk_slot *slot;struct o2hb_disk_heartbeat_block *hb_block;char *errstr; +u8 node_num = reg->hr_node_num; + +if (node_num >=O2NM_MAX_NODES ) +return 0 ; - slot = ®->hr_slots[o2nm_this_node ()]; + slot = ®->hr_slots[node_num];/* Don't check on our 1st timestamp */ if (!slot->ds_last_time)return 0 ;
@@ -719,7 +728,10 @@ static inline void o2hb_prepare_block(struct o2hb_region *reg,struct o2hb_disk_slot *slot;struct o2hb_disk_heartbeat_block *hb_block; - node_num =o2nm_this_node (); + node_num = reg->hr_node_num; +if (node_num >=O2NM_MAX_NODES ) +return ; + slot = ®->hr_slots[node_num]; hb_block = (struct o2hb_disk_heartbeat_block *)slot->ds_raw_block;
@@ -1213,7 +1225,7 @@ static int o2hb_thread(void *data)set_user_nice (current,MIN_NICE );/* Pin node */ - ret =o2nm_depend_this_node (); + ret =o2nm_depend_node (reg->hr_node_num);if (ret) {mlog (ML_ERROR ,"Node has been deleted, ret = %d\n" , ret); reg->hr_node_deleted =1 ;
@@ -1222,7 +1234,8 @@ static int o2hb_thread(void *data) }while (!kthread_should_stop () && - !reg->hr_unclean_stop && !reg->hr_aborted_start) { + !reg->hr_unclean_stop && !reg->hr_aborted_start && +o2nm_this_node () == reg->hr_node_num) {/* We track the time spent inside * o2hb_do_disk_heartbeat so that we avoid more than * hr_timeout_ms between disk writes. On busy systems
@@ -1271,7 +1284,7 @@ static int o2hb_thread(void *data) }/* Unpin node */ -o2nm_undepend_this_node (); +o2nm_undepend_node (reg->hr_node_num);mlog (ML_HEARTBEAT |ML_KTHREAD ,"o2hb thread exiting\n" );
@@ -1782,7 +1795,8 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,/* We can't heartbeat without having had our node number * configured yet. */ -if (o2nm_this_node () ==O2NM_MAX_NODES ) + reg->hr_node_num =o2nm_this_node (); +if (reg->hr_node_num ==O2NM_MAX_NODES )return -EINVAL ; fd =simple_strtol (p, &p,0 );
@@ -2017,6 +2031,7 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g ret = -ENAMETOOLONG ; goto free; } + reg->hr_node_num =O2NM_MAX_NODES ;spin_lock (&o2hb_live_lock); reg->hr_region_num =0 ;
fs/ocfs2/cluster/nodemanager.c +15 -4
@@ -366,6 +366,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,if (!tmp && cluster->cl_has_local && cluster->cl_local_node == node->nd_num) {o2net_stop_listening (node); + cluster->cl_has_local =0 ; cluster->cl_local_node =O2NM_INVALID_NODE_NUM ; }
@@ -787,12 +788,12 @@ void o2nm_undepend_item(struct config_item *item)configfs_undepend_item (item); } -int o2nm_depend_this_node (void ) +int o2nm_depend_node (u8 node_num) {int ret =0 ;struct o2nm_node *local_node; - local_node =o2nm_get_node_by_num (o2nm_this_node ()); + local_node =o2nm_get_node_by_num (node_num);if (!local_node) { ret = -EINVAL ; goto out;
@@ -805,17 +806,27 @@ int o2nm_depend_this_node(void)return ret; } -void o2nm_undepend_this_node (void ) +void o2nm_undepend_node (u8 node_num) {struct o2nm_node *local_node; - local_node =o2nm_get_node_by_num (o2nm_this_node ()); + local_node =o2nm_get_node_by_num (node_num);BUG_ON (!local_node);o2nm_undepend_item (&local_node->nd_item);o2nm_node_put (local_node); } +int o2nm_depend_this_node (void ) +{ +return o2nm_depend_node (o2nm_this_node ()); +} + +void o2nm_undepend_this_node (void ) +{ +o2nm_undepend_node (o2nm_this_node ()); +} + static void __exit exit_o2nm(void) {
fs/ocfs2/cluster/nodemanager.h +2 -0
@@ -66,6 +66,8 @@ void o2nm_node_put(struct o2nm_node *node);int o2nm_depend_item (struct config_item *item);int o2nm_depend_item_unlocked (struct config_item *item);void o2nm_undepend_item (struct config_item *item); +int o2nm_depend_node (u8 node_num); +void o2nm_undepend_node (u8 node_num);int o2nm_depend_this_node (void );void o2nm_undepend_this_node (void );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 882/1376 lib/string: fix memchr_inv() for large ranges
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
[ Upstream commit c04cffb8c51618538f0c05c478a931eb6e1a806b ]
memchr_inv() takes a size_t length but counts 8 byte words in an unsigned int. At 32GiB that count wraps, so the scan can quietly miss most of the range.
Use size_t for the word count.
--- lib/string.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/string.c +2 -1
@@ -828,7 +828,8 @@ void *memchr_inv(const void *start, int c, size_t bytes) {u8 value = c;u64 value64; -unsigned int words, prefix; +size_t words; +unsigned int prefix;if (bytes <=16 )return check_bytes8 (start, value, bytes);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 883/1376 pps: dont try to wait for negative timeouts in PPS_FETCH
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Calvin Owens <[email protected]>
[ Upstream commit 45217e98987a87ff2372386dbf82fd5325db28ea ]
If userspace passes a negative timeout to PPS_FETCH, it triggers a kernel splat from schedule_timeout():
schedule_timeout: wrong timeout value fffffffffff0bfb4
CPU: 17 UID: 0 PID: 4720 Comm: a.out Not tainted 7.1.0-rc5-x86-kvm-00150-g331d97e36b37 #1 PREEMPT_RT
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-20240910_120124-localhost 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x4b/0x70
schedule_timeout+0xb7/0xe0
pps_cdev_pps_fetch.isra.0+0x93/0x150
pps_cdev_ioctl+0x70/0x310
__x64_sys_ioctl+0x7b/0xc0
do_syscall_64+0xb6/0xfc0
entry_SYSCALL_64_after_hwframe+0x4b/0x53Here is a trivial reproducer that works with the PPS_CLIENT_KTIMER test device enabled in the kernel:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/pps.h>
#include <err.h>
int main() {
struct pps_fdata fdata;
int fd;
fd = open("/dev/pps0", O_RDWR);
if (fd == -1)
err(1, "Failed to open /dev/pps0");
fdata.timeout.sec = -1;
fdata.timeout.nsec = 0;
if (ioctl(fd, PPS_FETCH, &fdata))
err(2, "PPS_FETCH failed");
close(fd);
return 0;
}Sashiko imagines this to be some sort of security problem, which is obviously really silly. But I think it is still worth fixing, so buggy userspace code can't trigger the splat.
Silence the splat by using timespec64_to_jiffies(), which hard limits the timeout to LONG_MAX jiffies. To be safe, explicitly preserve the -ETIMEDOUT return value userspace sees today if it passes a negative timeout.
If you really squint, this is still a slight behavior change in that there are "denormalized" combinations of tv_sec and tv_nsec which used to work but will now return -ETIMEDOUT. I can't imagine anybody will care about that...
--- drivers/pps/pps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/pps/pps.c +8 -2
@@ -63,13 +63,19 @@ static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata) err =wait_event_interruptible (pps->queue, ev != pps->last_ev); else { +struct timespec64 ts;unsigned long ticks;dev_dbg (&pps->dev,"timeout %lld.%09d\n" , (long long ) fdata->timeout.sec, fdata->timeout.nsec); - ticks = fdata->timeout.sec *HZ ; - ticks += fdata->timeout.nsec / (NSEC_PER_SEC /HZ ); + +if (fdata->timeout.sec <0 ) +return -ETIMEDOUT ; + + ts.tv_sec = fdata->timeout.sec; + ts.tv_nsec = fdata->timeout.nsec; + ticks =timespec64_to_jiffies (&ts);if (ticks !=0 ) { err = wait_event_interruptible_timeout(
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 884/1376 pps: clients: gpio: Bypass edges direction check when not needed
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bastien Curutchet <[email protected]>
[ Upstream commit a01f6287c244f35eeec11ca932d09061181eed8c ]
In the IRQ handler, the GPIO's state is read to verify the direction of the edge that triggered the interruption before generating the PPS event. If a pulse is too short, the GPIO line can reach back its original state before this verification and the PPS event is lost.
This check is needed when info->capture_clear is set because it needs interruptions on both rising and falling edges. When info->capture_clear is not set, interruption is triggered by one edge only so this check can be omitted.
Add a warning if irq_handler is left without triggering any PPS event. Bypass the edge's direction verification when info->capture_clear is not set.
Stable-dep-of: b899e0279f90 ("pps-gpio: remove dead capture_clear code")
--- drivers/pps/clients/pps-gpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/pps/clients/pps-gpio.c +5 -1
@@ -52,7 +52,9 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) info = data; - rising_edge =gpiod_get_value (info->gpio_pin); +/* Small trick to bypass the check on edge's direction when capture_clear is unset */ + rising_edge = info->capture_clear ? +gpiod_get_value (info->gpio_pin) : !info->assert_falling_edge;if ((rising_edge && !info->assert_falling_edge) || (!rising_edge && info->assert_falling_edge))pps_event (info->pps, &ts,PPS_CAPTUREASSERT , data);
@@ -60,6 +62,8 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) ((rising_edge && info->assert_falling_edge) || (!rising_edge && !info->assert_falling_edge)))pps_event (info->pps, &ts,PPS_CAPTURECLEAR , data); + else + dev_warn_ratelimited(&info->pps->dev, "IRQ did not trigger any PPS event\n");return IRQ_HANDLED ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 885/1376 pps: pps-gpio: split IRQ handler into hardirq timestamper + threaded handler
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Byczkowski <[email protected]>
[ Upstream commit 93781560b2fdd26fa8499d64db8a95a07e1dc902 ]
Split the pps-gpio interrupt handler into a primary (hardirq) handler that captures the PPS timestamp at interrupt entry, and a threaded handler that processes the event. This produces the same two-part handler structure on both PREEMPT_RT and non-RT kernels.
On non-RT kernels the threaded portion runs immediately after the primary, with no behavioral change compared to the previous single-handler implementation.
On PREEMPT_RT, where interrupt handlers are force-threaded by default, the previous single-handler implementation captured the timestamp inside the threaded portion, after IRQ-thread scheduling delay. With the split, the timestamp is captured in true hardirq context as it is on non-RT kernels, eliminating a significant source of PPS jitter on RT systems.
Stable-dep-of: b899e0279f90 ("pps-gpio: remove dead capture_clear code")
--- drivers/pps/clients/pps-gpio.c | 37 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-)
drivers/pps/clients/pps-gpio.c +25 -12
@@ -35,33 +35,44 @@ struct pps_gpio_device_data {bool capture_clear;unsigned int echo_active_ms;/* PPS echo active duration */ unsigned long echo_timeout;/* timer timeout value in jiffies */ +struct pps_event_time ts;/* timestamp captured in hardirq */ };/* * Report the PPS event */ -static irqreturn_t pps_gpio_irq_handler (int irq,void *data) +/* +* Primary hardirq handler -- runs in hardirq context even on PREEMPT_RT. +* Only captures the timestamp; all other work is deferred to the thread. +*/ +static irqreturn_t pps_gpio_irq_hardirq (int irq,void *data) { -const struct pps_gpio_device_data *info; -struct pps_event_time ts; -int rising_edge; +struct pps_gpio_device_data *info = data; + +pps_get_ts (&info->ts); -/* Get the time stamp first */ -pps_get_ts (&ts); +return IRQ_WAKE_THREAD ; +} - info = data; +/* +* Threaded handler -- processes the PPS event using the timestamp +* captured in hardirq context above. +*/ +static irqreturn_t pps_gpio_irq_thread (int irq,void *data) +{ +struct pps_gpio_device_data *info = data; +int rising_edge; -/* Small trick to bypass the check on edge's direction when capture_clear is unset */ rising_edge = info->capture_clear ?gpiod_get_value (info->gpio_pin) : !info->assert_falling_edge;if ((rising_edge && !info->assert_falling_edge) || (!rising_edge && info->assert_falling_edge)) -pps_event (info->pps, &ts,PPS_CAPTUREASSERT , data); +pps_event (info->pps, &info->ts,PPS_CAPTUREASSERT , data);else if (info->capture_clear && ((rising_edge && info->assert_falling_edge) || (!rising_edge && !info->assert_falling_edge))) -pps_event (info->pps, &ts,PPS_CAPTURECLEAR , data); +pps_event (info->pps, &info->ts,PPS_CAPTURECLEAR , data);else dev_warn_ratelimited (&info->pps->dev,"IRQ did not trigger any PPS event\n" );
@@ -210,8 +221,10 @@ static int pps_gpio_probe(struct platform_device *pdev) }/* register IRQ interrupt handler */ - ret =request_irq (data->irq, pps_gpio_irq_handler, -get_irqf_trigger_flags (data), data->info.name, data); + ret =request_threaded_irq (data->irq, + pps_gpio_irq_hardirq, pps_gpio_irq_thread, +get_irqf_trigger_flags (data) |IRQF_ONESHOT , + data->info.name, data);if (ret) {pps_unregister_source (data->pps);dev_err (dev,"failed to acquire IRQ %d\n" , data->irq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 886/1376 pps-gpio: remove dead capture_clear code
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Calvin Owens <[email protected]>
[ Upstream commit b899e0279f90c3ce4099d68b989dd27861cc5c4f ]
The capture_clear field is never set, and all code conditional on it being set has been unreachable since the platform data logic was removed from pps-gpio in ee89646619ba ("pps: clients: gpio: Get rid of legacy platform data").
I think the only logical thing to do here is to remove it all, since no in-tree code ever actually used it in the first place, and it has been completely dead code for over five years (since v5.13).
Sashiko asked some questions about the gpiod_get_value() call which caused me to look deeper and figure this out, but it did not actually notice capture_clear is never set.
--- drivers/pps/clients/pps-gpio.c | 37 ++++------------------------------ 1 file changed, 4 insertions(+), 33 deletions(-)
drivers/pps/clients/pps-gpio.c +4 -33
@@ -32,7 +32,6 @@ struct pps_gpio_device_data {struct gpio_desc *echo_pin;struct timer_list echo_timer;/* timer to reset echo active state */ bool assert_falling_edge; -bool capture_clear;unsigned int echo_active_ms;/* PPS echo active duration */ unsigned long echo_timeout;/* timer timeout value in jiffies */ struct pps_event_time ts;/* timestamp captured in hardirq */
@@ -62,19 +61,8 @@ static irqreturn_t pps_gpio_irq_hardirq(int irq, void *data)static irqreturn_t pps_gpio_irq_thread (int irq,void *data) {struct pps_gpio_device_data *info = data; -int rising_edge; - - rising_edge = info->capture_clear ? -gpiod_get_value (info->gpio_pin) : !info->assert_falling_edge; -if ((rising_edge && !info->assert_falling_edge) || - (!rising_edge && info->assert_falling_edge)) -pps_event (info->pps, &info->ts,PPS_CAPTUREASSERT , data); -else if (info->capture_clear && - ((rising_edge && info->assert_falling_edge) || - (!rising_edge && !info->assert_falling_edge))) -pps_event (info->pps, &info->ts,PPS_CAPTURECLEAR , data); -else -dev_warn_ratelimited (&info->pps->dev,"IRQ did not trigger any PPS event\n" ); + +pps_event (info->pps, &info->ts,PPS_CAPTUREASSERT , data);return IRQ_HANDLED ; }
@@ -90,11 +78,6 @@ static void pps_gpio_echo(struct pps_device *pps, int event, void *data)if (pps->params.mode &PPS_ECHOASSERT )gpiod_set_value (info->echo_pin,1 );break ; - -case PPS_CAPTURECLEAR : -if (pps->params.mode &PPS_ECHOCLEAR ) -gpiod_set_value (info->echo_pin,1 ); -break ; }/* fire the timer */
@@ -156,15 +139,8 @@ static int pps_gpio_setup(struct device *dev)static unsigned long get_irqf_trigger_flags (const struct pps_gpio_device_data *data) { -unsigned long flags = data->assert_falling_edge ? -IRQF_TRIGGER_FALLING :IRQF_TRIGGER_RISING ; - -if (data->capture_clear) { - flags |= ((flags &IRQF_TRIGGER_RISING ) ? -IRQF_TRIGGER_FALLING :IRQF_TRIGGER_RISING ); - } - -return flags; +return data->assert_falling_edge ?IRQF_TRIGGER_FALLING : +IRQF_TRIGGER_RISING ; }static int pps_gpio_probe (struct platform_device *pdev)
@@ -197,9 +173,6 @@ static int pps_gpio_probe(struct platform_device *pdev)/* initialize PPS specific parts of the bookkeeping data structure. */ data->info.mode =PPS_CAPTUREASSERT |PPS_OFFSETASSERT |PPS_ECHOASSERT |PPS_CANWAIT |PPS_TSFMT_TSPEC ; -if (data->capture_clear) - data->info.mode |=PPS_CAPTURECLEAR |PPS_OFFSETCLEAR | -PPS_ECHOCLEAR ; data->info.owner =THIS_MODULE ;snprintf (data->info.name,PPS_MAX_NAME_LEN -1 ,"%s.%d" , pdev->name, pdev->id);
@@ -211,8 +184,6 @@ static int pps_gpio_probe(struct platform_device *pdev)/* register PPS source */ pps_default_params =PPS_CAPTUREASSERT |PPS_OFFSETASSERT ; -if (data->capture_clear) - pps_default_params |=PPS_CAPTURECLEAR |PPS_OFFSETCLEAR ; data->pps =pps_register_source (&data->info, pps_default_params);if (IS_ERR (data->pps)) { dev_err(dev, "failed to register IRQ %d as PPS source\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 887/1376 rapidio: clear mport->net when rio_add_net() fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit b74030fbf187b43c1f85b66a7082e9946511cb5d ]
rio_alloc_net() stores the newly allocated rio_net in mport->net before rio_scan_alloc_net() registers the device.
If rio_add_net() fails, rio_scan_alloc_net() drops the device reference with put_device(), which releases the rio_net through the device release callback. However, mport->net is left pointing at the freed object.
A later mport unregister path can then dereference the dangling mport->net pointer and may try to free the same rio_net again.
Clear mport->net in the rio_add_net() failure path, matching the cleanup done for the destID table allocation failure path.
--- drivers/rapidio/rio-scan.c | 1 + 1 file changed, 1 insertion(+)
drivers/rapidio/rio-scan.c +1 -0
@@ -874,6 +874,7 @@ static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport, net->dev.release = rio_scan_release_dev;if (rio_add_net (net)) {put_device (&net->dev); + mport->net =NULL ; net =NULL ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 888/1376 fat: release buffer head after rebuilding parent
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 83e98dbf19ab64e8528e101e20f8d50e1aaa68a8 ]
fat_scan_logstart() leaves the matching directory entry's buffer head in sinfo.bh for the caller to release, just like fat_scan().
fat_rebuild_parent() uses the directory entry to rebuild the parent inode for the nostale_ro NFS export path, but does not release sinfo.bh after a successful scan. Release it once fat_build_inode() has consumed the directory entry data.
--- fs/fat/nfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/fat/nfs.c +3 -1
@@ -250,8 +250,10 @@ struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart)MSDOS_I (dummy_grand_parent)->i_pos =-1 ; } -if (!fat_scan_logstart (dummy_grand_parent, clus_to_match, &sinfo)) +if (!fat_scan_logstart (dummy_grand_parent, clus_to_match, &sinfo)) { parent =fat_build_inode (sb, sinfo.de, sinfo.i_pos); +brelse (sinfo.bh); + }brelse (parent_bh);iput (dummy_grand_parent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 889/1376 riscv: dts: sophgo: cv180x: Allow the DMA multiplexer to set channel number for DMA controller
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Inochi Amaoto <[email protected]>
[ Upstream commit 5011466bade64483bb52bc4a926719d6794e6dab ]
Change the DMA controller compatible to the sophgo,cv1800b-axi-dma, which supports setting DMA channel number in DMA phandle args.
This dts change does not break backward compatibility as a fallback compatiable string is added.
--- arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/boot/dts/sophgo/cv18xx.dtsi +1 -1
@@ -298,7 +298,7 @@ sdhci0: mmc@4310000 { }; dmac: dma-controller@4330000 { - compatible = "snps,axi-dma-1.01a"; + compatible = "sophgo,cv1800b-axi-dma", "snps,axi-dma-1.01a"; reg = <0x04330000 0x1000>; interrupts = <29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk CLK_SDMA_AXI>, <&clk CLK_SDMA_AXI>;
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0889/1376] riscv: dts: sophgo: cv180x: Allow the DMA multiplexer to set channel number for DMA controller
Hi Greg/Sasha,
Quoted 31 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Inochi Amaoto <[email protected]>
[ Upstream commit
5011466bade64483bb52bc4a926719d6794e6dab]Change the DMA controller compatible to the sophgo,cv1800b-axi-dma, which supports setting DMA channel number in DMA phandle args.
This dts change does not break backward compatibility as a fallback compatiable string is added.
Fixes 514951a81a5e ("riscv: dts: sophgo: cv18xx: add DMA controller")Reported-by Anton D. Stavinskii <[email protected]>Tested-by Anton D. Stavinskii <[email protected]>Signed-off-by Inochi Amaoto <[email protected]>Signed-off-by Chen Wang <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)arch/riscv/boot/dts/sophgo/cv18xx.dtsi +0
-0
arch/riscv/boot/dts/sophgo/cv18xx.dtsi sdhci0: mmc@4310000 { · line 301
Quoted 5 lines
arch/riscv/boot/dts/sophgo/cv18xx.dtsi +1
-1@@ -298,7 +298,7 @@ sdhci0: mmc@4310000 { }; dmac: dma-controller@4330000 { - compatible = "snps,axi-dma-1.01a"; + compatible = "sophgo,cv1800b-axi-dma", "snps,axi-dma-1.01a";
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The patch adds the Sophgo CV1800B DMA compatible, but 6.12 lacks the matching driver support from b49c70273801. The generic fallback therefore matches and still calls dma_get_any_slave_channel(), so the phandle channel number is not honored. The branch also lacks the CV1800B mux driver db7d07b5add4 and its syscon/mux DTS integration from 126a1b3c61cb.
Upstream driver code after b49c70273801:
if (dw->hdata->use_handshake_as_channel_number)
dchan = dma_get_slave_channel(&chan->vc.chan);
else
dchan = dma_get_any_slave_channel(&dw->dma);Downstream 6.12.y code:
compatible = "sophgo,cv1800b-axi-dma",
"snps,axi-dma-1.01a";
dchan = dma_get_any_slave_channel(&dw->dma);Downstream falls back to the generic match and ignores the channel ID.
Maybe we should be dropping this or reverting this.
thanks,
Harshit
Quoted 3 lines
arch/riscv/boot/dts/sophgo/cv18xx.dtsi +0
-0reg = <0x04330000 0x1000>; interrupts = <29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk CLK_SDMA_AXI>, <&clk CLK_SDMA_AXI>;
Re: [PATCH 6.12 0889/1376] riscv: dts: sophgo: cv180x: Allow the DMA multiplexer to set channel number for DMA controller
Quoted 63 lines · Harshit Mogalapalli
Hi Greg/Sasha,
Quoted 31 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Inochi Amaoto <[email protected]>
[ Upstream commit
5011466bade64483bb52bc4a926719d6794e6dab]Change the DMA controller compatible to the sophgo,cv1800b-axi-dma, which supports setting DMA channel number in DMA phandle args.
This dts change does not break backward compatibility as a fallback compatiable string is added.
Fixes 514951a81a5e ("riscv: dts: sophgo: cv18xx: add DMA controller")Reported-by Anton D. Stavinskii <[email protected]>Tested-by Anton D. Stavinskii <[email protected]>Signed-off-by Inochi Amaoto <[email protected]>Signed-off-by Chen Wang <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)arch/riscv/boot/dts/sophgo/cv18xx.dtsi +0
-0arch/riscv/boot/dts/sophgo/cv18xx.dtsi sdhci0: mmc@4310000 { · line 300
Quoted 4 lines
arch/riscv/boot/dts/sophgo/cv18xx.dtsi +1
-1@@ -298,7 +298,7 @@ sdhci0: mmc@4310000 { }; dmac: dma-controller@4330000 { - compatible = "snps,axi-dma-1.01a"; + compatible = "sophgo,cv1800b-axi-dma", "snps,axi-dma-1.01a";I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The patch adds the Sophgo CV1800B DMA compatible, but 6.12 lacks the matching driver support from
b49c70273801. The generic fallback therefore matches and still callsdma_get_any_slave_channel(), so the phandle channel number is not honored. The branch also lacks the CV1800B mux driverdb7d07b5add4and its syscon/mux DTS integration from126a1b3c61cb.Upstream driver code after
b49c70273801:if (dw->hdata->use_handshake_as_channel_number) dchan = dma_get_slave_channel(&chan->vc.chan); else dchan = dma_get_any_slave_channel(&dw->dma);Downstream 6.12.y code:
compatible = "sophgo,cv1800b-axi-dma", "snps,axi-dma-1.01a"; dchan = dma_get_any_slave_channel(&dw->dma);
Quoted 11 lines
Downstream falls back to the generic match and ignores the channel ID.
Maybe we should be dropping this or reverting this.
thanks,
HarshitQuoted 3 lines
arch/riscv/boot/dts/sophgo/cv18xx.dtsi +0
-0reg = <0x04330000 0x1000>; interrupts = <29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk CLK_SDMA_AXI>, <&clk CLK_SDMA_AXI>;
I think this fix does not change something as we already have the fallback compatiable, even if we does not backport the driver fix. As this does not change the behavior, I think this could be kept.
Regards,
Inochi
Greg Kroah-Hartman
maintainerPATCH 890/1376 drm/omap: dsi: Do not copy isr table
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andreas Kemnade <[email protected]>
[ Upstream commit 97c03b32b28a9f7f13f768f2b06e1eaafe850e66 ]
To be able to unregister stuff from isrs, the corresponding table was copied. Nobody seems to unregister stuff that way, so it does not help. But there are stack-allocated objects passed to these isrs giving chances of UAF of these objects if irqs are unregistered while they are handled, so better do not copy that table.
--- drivers/gpu/drm/omapdrm/dss/dsi.c | 7 +------ drivers/gpu/drm/omapdrm/dss/dsi.h | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-)
drivers/gpu/drm/omapdrm/dss/dsi.c +1 -6
@@ -455,15 +455,10 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)del_timer (&dsi->te_timer);#endif -/* make a copy and unlock, so that isrs can unregister -* themselves */ -memcpy (&dsi->isr_tables_copy, &dsi->isr_tables, -sizeof (dsi->isr_tables)); +dsi_handle_isrs (&dsi->isr_tables, irqstatus, vcstatus, ciostatus);spin_unlock (&dsi->irq_lock); -dsi_handle_isrs (&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus); -dsi_handle_irq_errors (dsi, irqstatus, vcstatus, ciostatus);dsi_collect_irq_stats (dsi, irqstatus, vcstatus, ciostatus);
drivers/gpu/drm/omapdrm/dss/dsi.h +0 -2
@@ -379,8 +379,6 @@ struct dsi_data {spinlock_t irq_lock;struct dsi_isr_tables isr_tables; -/* space for a copy used by the interrupt handler */ -struct dsi_isr_tables isr_tables_copy;int update_vc;#ifdef DSI_PERF_MEASURE
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 891/1376 arm64: dts: qcom: agatti: Add missing CX power domain to DISPCC
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imran Shaik <[email protected]>
[ Upstream commit 26d7b23caa4b1d8208e28c5981a85cf83e658e7c ]
Add the missing power-domains property to associate DISPCC with CX rail. This is to ensure the genpd performance state votes on the GDSC to get propagated to the CX rail and to avoid the rail under-voltage conditions.
--- arch/arm64/boot/dts/qcom/qcm2290.dtsi | 1 + 1 file changed, 1 insertion(+)
arch/arm64/boot/dts/qcom/qcm2290.dtsi +1 -0
@@ -1798,6 +1798,7 @@ dispcc: clock-controller@5f00000 { "gcc_disp_gpll0_div_clk_src", "dsi0_phy_pll_out_byteclk", "dsi0_phy_pll_out_dsiclk"; + power-domains = <&rpmpd QCM2290_VDDCX>; #power-domain-cells = <1>; #clock-cells = <1>; #reset-cells = <1>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 892/1376 remoteproc: Move resource table data structure to its own header
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 0590420c2f90de497d342c9a41a618f46f4d09ab ]
The resource table data structure has traditionally been associated with the remoteproc framework, where the resource table is included as a section within the remote processor firmware binary. However, it is also possible to obtain the resource table through other means—such as from a reserved memory region populated by the boot firmware, statically maintained driver data, or via a secure SMC call—when it is not embedded in the firmware.
There are multiple Qualcomm remote processors (e.g., Venus, Iris, GPU, etc.) in the upstream kernel that do not use the remoteproc framework to manage their lifecycle for various reasons.
When Linux is running at EL2, similar to the Qualcomm PAS driver (qcom_q6v5_pas.c), client drivers for subsystems like video and GPU may also want to use the resource table SMC call to retrieve and map resources before they are used by the remote processor.
In such cases, the resource table data structure is no longer tightly coupled with the remoteproc headers. Client drivers that do not use the remoteproc framework should still be able to parse the resource table obtained through alternative means. Therefore, there is a need to decouple the resource table definitions from the remoteproc headers.
Stable-dep-of: bb840ea69347 ("remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()")
--- include/linux/remoteproc.h | 269 +------------------------------- include/linux/rsc_table.h | 306 +++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 268 deletions(-) create mode 100644 include/linux/rsc_table.h
include/linux/remoteproc.h +1 -268
@@ -43,274 +43,7 @@#include <linux/completion.h> #include <linux/idr.h> #include <linux/of.h> - -/** -* struct resource_table - firmware resource table header -* @ver: version number -* @num: number of resource entries -* @reserved: reserved (must be zero) -* @offset: array of offsets pointing at the various resource entries -* -* A resource table is essentially a list of system resources required -* by the remote processor. It may also include configuration entries. -* If needed, the remote processor firmware should contain this table -* as a dedicated ".resource_table" ELF section. -* -* Some resources entries are mere announcements, where the host is informed -* of specific remoteproc configuration. Other entries require the host to -* do something (e.g. allocate a system resource). Sometimes a negotiation -* is expected, where the firmware requests a resource, and once allocated, -* the host should provide back its details (e.g. address of an allocated -* memory region). -* -* The header of the resource table, as expressed by this structure, -* contains a version number (should we need to change this format in the -* future), the number of available resource entries, and their offsets -* in the table. -* -* Immediately following this header are the resource entries themselves, -* each of which begins with a resource entry header (as described below). -*/ -struct resource_table { -u32 ver; -u32 num; -u32 reserved[2 ]; -u32 offset[]; -} __packed; - -/** -* struct fw_rsc_hdr - firmware resource entry header -* @type: resource type -* @data: resource data -* -* Every resource entry begins with a 'struct fw_rsc_hdr' header providing -* its @type. The content of the entry itself will immediately follow -* this header, and it should be parsed according to the resource type. -*/ -struct fw_rsc_hdr { -u32 type; -u8 data[]; -} __packed; - -/** -* enum fw_resource_type - types of resource entries -* -* @RSC_CARVEOUT: request for allocation of a physically contiguous -* memory region. -* @RSC_DEVMEM: request to iommu_map a memory-based peripheral. -* @RSC_TRACE: announces the availability of a trace buffer into which -* the remote processor will be writing logs. -* @RSC_VDEV: declare support for a virtio device, and serve as its -* virtio header. -* @RSC_LAST: just keep this one at the end of standard resources -* @RSC_VENDOR_START: start of the vendor specific resource types range -* @RSC_VENDOR_END: end of the vendor specific resource types range -* -* For more details regarding a specific resource type, please see its -* dedicated structure below. -* -* Please note that these values are used as indices to the rproc_handle_rsc -* lookup table, so please keep them sane. Moreover, @RSC_LAST is used to -* check the validity of an index before the lookup table is accessed, so -* please update it as needed. -*/ -enum fw_resource_type { -RSC_CARVEOUT =0 , -RSC_DEVMEM =1 , -RSC_TRACE =2 , -RSC_VDEV =3 , -RSC_LAST =4 , -RSC_VENDOR_START =128 , -RSC_VENDOR_END =512 , -}; - -#define FW_RSC_ADDR_ANY (-1) - -/** -* struct fw_rsc_carveout - physically contiguous memory request -* @da: device address -* @pa: physical address -* @len: length (in bytes) -* @flags: iommu protection flags -* @reserved: reserved (must be zero) -* @name: human-readable name of the requested memory region -* -* This resource entry requests the host to allocate a physically contiguous -* memory region. -* -* These request entries should precede other firmware resource entries, -* as other entries might request placing other data objects inside -* these memory regions (e.g. data/code segments, trace resource entries, ...). -* -* Allocating memory this way helps utilizing the reserved physical memory -* (e.g. CMA) more efficiently, and also minimizes the number of TLB entries -* needed to map it (in case @rproc is using an IOMMU). Reducing the TLB -* pressure is important; it may have a substantial impact on performance. -* -* If the firmware is compiled with static addresses, then @da should specify -* the expected device address of this memory region. If @da is set to -* FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then -* overwrite @da with the dynamically allocated address. -* -* We will always use @da to negotiate the device addresses, even if it -* isn't using an iommu. In that case, though, it will obviously contain -* physical addresses. -* -* Some remote processors needs to know the allocated physical address -* even if they do use an iommu. This is needed, e.g., if they control -* hardware accelerators which access the physical memory directly (this -* is the case with OMAP4 for instance). In that case, the host will -* overwrite @pa with the dynamically allocated physical address. -* Generally we don't want to expose physical addresses if we don't have to -* (remote processors are generally _not_ trusted), so we might want to -* change this to happen _only_ when explicitly required by the hardware. -* -* @flags is used to provide IOMMU protection flags, and @name should -* (optionally) contain a human readable name of this carveout region -* (mainly for debugging purposes). -*/ -struct fw_rsc_carveout { -u32 da; -u32 pa; -u32 len; -u32 flags; -u32 reserved; -u8 name[32 ]; -} __packed; - -/** -* struct fw_rsc_devmem - iommu mapping request -* @da: device address -* @pa: physical address -* @len: length (in bytes) -* @flags: iommu protection flags -* @reserved: reserved (must be zero) -* @name: human-readable name of the requested region to be mapped -* -* This resource entry requests the host to iommu map a physically contiguous -* memory region. This is needed in case the remote processor requires -* access to certain memory-based peripherals; _never_ use it to access -* regular memory. -* -* This is obviously only needed if the remote processor is accessing memory -* via an iommu. -* -* @da should specify the required device address, @pa should specify -* the physical address we want to map, @len should specify the size of -* the mapping and @flags is the IOMMU protection flags. As always, @name may -* (optionally) contain a human readable name of this mapping (mainly for -* debugging purposes). -* -* Note: at this point we just "trust" those devmem entries to contain valid -* physical addresses, but this isn't safe and will be changed: eventually we -* want remoteproc implementations to provide us ranges of physical addresses -* the firmware is allowed to request, and not allow firmwares to request -* access to physical addresses that are outside those ranges. -*/ -struct fw_rsc_devmem { -u32 da; -u32 pa; -u32 len; -u32 flags; -u32 reserved; -u8 name[32 ]; -} __packed; - -/** -* struct fw_rsc_trace - trace buffer declaration -* @da: device address -* @len: length (in bytes) -* @reserved: reserved (must be zero) -* @name: human-readable name of the trace buffer -* -* This resource entry provides the host information about a trace buffer -* into which the remote processor will write log messages. -* -* @da specifies the device address of the buffer, @len specifies -* its size, and @name may contain a human readable name of the trace buffer. -* -* After booting the remote processor, the trace buffers are exposed to the -* user via debugfs entries (called trace0, trace1, etc..). -*/ -struct fw_rsc_trace { -u32 da; -u32 len; -u32 reserved; -u8 name[32 ]; -} __packed; - -/** -* struct fw_rsc_vdev_vring - vring descriptor entry -* @da: device address -* @align: the alignment between the consumer and producer parts of the vring -* @num: num of buffers supported by this vring (must be power of two) -* @notifyid: a unique rproc-wide notify index for this vring. This notify -* index is used when kicking a remote processor, to let it know that this -* vring is triggered. -* @pa: physical address -* -* This descriptor is not a resource entry by itself; it is part of the -* vdev resource type (see below). -* -* Note that @da should either contain the device address where -* the remote processor is expecting the vring, or indicate that -* dynamically allocation of the vring's device address is supported. -*/ -struct fw_rsc_vdev_vring { -u32 da; -u32 align; -u32 num; -u32 notifyid; -u32 pa; -} __packed; - -/** -* struct fw_rsc_vdev - virtio device header -* @id: virtio device id (as in virtio_ids.h) -* @notifyid: a unique rproc-wide notify index for this vdev. This notify -* index is used when kicking a remote processor, to let it know that the -* status/features of this vdev have changes. -* @dfeatures: specifies the virtio device features supported by the firmware -* @gfeatures: a place holder used by the host to write back the -* negotiated features that are supported by both sides. -* @config_len: the size of the virtio config space of this vdev. The config -* space lies in the resource table immediate after this vdev header. -* @status: a place holder where the host will indicate its virtio progress. -* @num_of_vrings: indicates how many vrings are described in this vdev header -* @reserved: reserved (must be zero) -* @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. -* -* This resource is a virtio device header: it provides information about -* the vdev, and is then used by the host and its peer remote processors -* to negotiate and share certain virtio properties. -* -* By providing this resource entry, the firmware essentially asks remoteproc -* to statically allocate a vdev upon registration of the rproc (dynamic vdev -* allocation is not yet supported). -* -* Note: -* 1. unlike virtualization systems, the term 'host' here means -* the Linux side which is running remoteproc to control the remote -* processors. We use the name 'gfeatures' to comply with virtio's terms, -* though there isn't really any virtualized guest OS here: it's the host -* which is responsible for negotiating the final features. -* Yeah, it's a bit confusing. -* -* 2. immediately following this structure is the virtio config space for -* this vdev (which is specific to the vdev; for more info, read the virtio -* spec). The size of the config space is specified by @config_len. -*/ -struct fw_rsc_vdev { -u32 id; -u32 notifyid; -u32 dfeatures; -u32 gfeatures; -u32 config_len; -u8 status; -u8 num_of_vrings; -u8 reserved[2 ]; -struct fw_rsc_vdev_vring vring[]; -} __packed; +#include <linux/rsc_table.h> struct rproc ;
include/linux/rsc_table.h new file +306 -0
306 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 893/1376 remoteproc: use rsc_table_for_each_entry() in rproc_handle_resources()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 49abb5d6e1ac8169cdfc0c3aa4408e0d90ee5696 ]
Replace the open-coded resource table iteration loop in rproc_handle_resources() with the rsc_table_for_each_entry() helper.
The remoteproc-specific dispatch logic (vendor resource handling via rproc_handle_rsc(), RSC_LAST bounds check, handler table lookup) is moved into a local callback rproc_handle_rsc_entry(), keeping the iteration mechanics in one canonical place.
The callback receives the payload offset within the table so that handlers which write back into the resource table (e.g. rproc_handle_carveout() recording a dynamically allocated address via rsc_offset) continue to work correctly.
No functional change.
Stable-dep-of: bb840ea69347 ("remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()")
--- drivers/remoteproc/remoteproc_core.c | 81 +++++++++++++--------------- include/linux/rsc_table.h | 53 ++++++++++++++++++ 2 files changed, 91 insertions(+), 43 deletions(-)
drivers/remoteproc/remoteproc_core.c +38 -43
@@ -1016,60 +1016,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { [RSC_VDEV] = rproc_handle_vdev, }; -/* handle firmware resource entries before booting the remote processor */ -static int rproc_handle_resources (struct rproc *rproc, -rproc_handle_resource_t handlers[RSC_LAST ]) +struct rproc_rsc_cb_data { +struct rproc *rproc; +rproc_handle_resource_t *handlers; +}; + +static int rproc_handle_rsc_entry (u32 type,void *rsc,int offset, +int avail,void *data) { +struct rproc_rsc_cb_data *d = data; +struct rproc *rproc = d->rproc;struct device *dev = &rproc->dev;rproc_handle_resource_t handler; -int ret =0 , i; - -if (!rproc->table_ptr) -return 0 ; +int ret; -for (i =0 ; i < rproc->table_ptr->num; i++) { -int offset = rproc->table_ptr->offset[i]; -struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; -int avail = rproc->table_sz - offset -sizeof (*hdr); -void *rsc = (void *)hdr +sizeof (*hdr); +dev_dbg (dev,"rsc: type %d\n" , type); -/* make sure table isn't truncated */ -if (avail <0 ) { -dev_err (dev,"rsc table is truncated\n" ); -return -EINVAL ; - } - -dev_dbg (dev,"rsc: type %d\n" , hdr->type); +if (type >=RSC_VENDOR_START && type <=RSC_VENDOR_END ) { + ret =rproc_handle_rsc (rproc, type, rsc, offset, avail); +if (ret ==RSC_HANDLED ) +return 0 ; +if (ret <0 ) +return ret; +dev_warn (dev,"unsupported vendor resource %d\n" , type); +return 0 ; + } -if (hdr->type >=RSC_VENDOR_START && - hdr->type <=RSC_VENDOR_END ) { - ret =rproc_handle_rsc (rproc, hdr->type, rsc, - offset +sizeof (*hdr), avail); -if (ret ==RSC_HANDLED ) -continue ; -else if (ret <0 ) -break ; +if (type >=RSC_LAST ) { +dev_warn (dev,"unsupported resource %d\n" , type); +return 0 ; + } -dev_warn (dev,"unsupported vendor resource %d\n" , - hdr->type); -continue ; - } + handler = d->handlers[type]; +if (!handler) +return 0 ; -if (hdr->type >=RSC_LAST ) { -dev_warn (dev,"unsupported resource %d\n" , hdr->type); -continue ; - } +return handler (rproc, rsc, offset, avail); +} - handler = handlers[hdr->type]; -if (!handler) -continue ; +/* handle firmware resource entries before booting the remote processor */ +static int rproc_handle_resources (struct rproc *rproc, +rproc_handle_resource_t handlers[RSC_LAST ]) +{ +struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers }; - ret =handler (rproc, rsc, offset +sizeof (*hdr), avail); -if (ret) -break ; - } +if (!rproc->table_ptr) +return 0 ; -return ret; +return rsc_table_for_each_entry (rproc->table_ptr, rproc->table_sz, + &rproc->dev, rproc_handle_rsc_entry, &d); }static int rproc_prepare_subdevices (struct rproc *rproc)
include/linux/rsc_table.h +53 -0
57 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 894/1376 remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit bb840ea69347aff7bde5a208e7b5b180669a7656 ]
table->offset[i] is a u32 from firmware, but was stored into a signed int. A crafted offset like 0xFFFFFFF0 becomes -16, placing hdr 16 bytes before the table buffer. The subsequent avail check was bypassed because the negative int was promoted to a large size_t in the expression "table_sz - offset - sizeof(*hdr)", yielding a large positive avail and letting the out-of-bounds hdr->type read proceed undetected.
Store the offset as u32 and validate it with unsigned comparisons before any pointer arithmetic.
--- include/linux/rsc_table.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
include/linux/rsc_table.h +11 -6
@@ -337,17 +337,22 @@ static inline int rsc_table_for_each_entry(struct resource_table *table,int i, ret;for (i =0 ; i < table->num; i++) { -int offset = table->offset[i]; -struct fw_rsc_hdr *hdr = (void *)table + offset; -int avail = table_sz - offset -sizeof (*hdr); -int rsc_offset = offset +sizeof (*hdr); -void *rsc = (void *)hdr +sizeof (*hdr); +u32 offset = table->offset[i]; +struct fw_rsc_hdr *hdr; +int avail, rsc_offset; +void *rsc; -if (avail <0 ) { +if (offset <sizeof (*table) || offset >= table_sz || + table_sz - offset <sizeof (*hdr)) {dev_err (dev,"rsc table is truncated\n" );return -EINVAL ; } + hdr = (void *)table + offset; + avail = table_sz - offset -sizeof (*hdr); + rsc_offset = offset +sizeof (*hdr); + rsc = (void *)hdr +sizeof (*hdr); + ret =cb (hdr->type, rsc, rsc_offset, avail, data);if (ret)return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 895/1376 bpf, cgroup: Fix invalid storage access after __cgroup_bpf_attach failed
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 6655c409707ec8ce9ce0850ffe4fe02331fd4d9c ]
A potential invalid storage access issue can occur after replacing a cgroup bpf prog.
This occurs in the following scenario:
1. prog1 with storage is attached to a cgroup in multi-attach mode.
2. prog1 is replaced with prog2 using BPF_F_REPLACE in multi-attach mode, but fails midway (e.g. in bpf_trampoline_link_cgroup_shim or update_effective_progs).
3. A new prog3 is attached to the cgroup in multi-attach mode.
The reason is that __cgroup_bpf_attach overwrites pl->storage with the new storage prior to attachment completion. When attachment fails midway, the cleanup path calls bpf_cgroup_storages_free(new_storage) to free the newly allocated storage, but fails to restore pl->storage back to old_storage.
Consequently, the still-active prog1 holds invalid or dangling storage pointers, leading to an invalid memory access when prog1 executes and calls bpf_get_local_storage. Additionally, original pl->flags and cgrp->bpf.flags[atype] are left unrestored.
Fix this by saving old_pl_flags, old_storage, and old_flags prior to the update, and properly restoring all of them in the cleanup path on error.
--- kernel/bpf/cgroup.c | 8 ++++++++ 1 file changed, 8 insertions(+)
kernel/bpf/cgroup.c +8 -0
@@ -646,8 +646,10 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,struct bpf_prog *old_prog =NULL ;struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE ] = {};struct bpf_cgroup_storage *new_storage[MAX_BPF_CGROUP_STORAGE_TYPE ] = {}; +struct bpf_cgroup_storage *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE ] = {};struct bpf_prog *new_prog = prog ? : link->link.prog;enum cgroup_bpf_attach_type atype; +u32 old_flags, old_pl_flags;struct bpf_prog_list *pl;struct hlist_head *progs;int err;
@@ -693,6 +695,8 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,if (pl) { old_prog = pl->prog; + old_pl_flags = pl->flags; +bpf_cgroup_storages_assign (old_storage, pl->storage); }else {struct hlist_node *last =NULL ;
@@ -716,6 +720,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp, pl->link = link; pl->flags = flags;bpf_cgroup_storages_assign (pl->storage, storage); + old_flags = cgrp->bpf.flags[atype]; cgrp->bpf.flags[atype] = saved_flags;if (type ==BPF_LSM_CGROUP ) {
@@ -746,12 +751,15 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,if (old_prog) { pl->prog = old_prog; pl->link =NULL ; + pl->flags = old_pl_flags; +bpf_cgroup_storages_assign (pl->storage, old_storage); }bpf_cgroup_storages_free (new_storage);if (!old_prog) {hlist_del (&pl->node);kfree (pl); } + cgrp->bpf.flags[atype] = old_flags;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 896/1376 selftests/mm: add new test cases to the migration test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donet Tom <[email protected]>
[ Upstream commit 901083d8f5c55dc125834bbc5ac1720014e66758 ]
Added three new test cases to the migration tests:
1. Shared anon THP migration test
This test will mmap shared anon memory, madvise it to MADV_HUGEPAGE, then do migration entry testing. One thread will move pages back and forth between nodes whilst other threads try and access them.
2. Private anon hugetlb migration test
This test will mmap private anon hugetlb memory and then do the migration entry testing.
3. Shared anon hugetlb migration test
This test will mmap shared anon hugetlb memory and then do the migration entry testing.
Test results
============
# ./tools/testing/selftests/mm/migration TAP version 13 1..6 # Starting 6 tests from 1 test cases. # RUN migration.private_anon ... # OK migration.private_anon ok 1 migration.private_anon # RUN migration.shared_anon ... # OK migration.shared_anon ok 2 migration.shared_anon # RUN migration.private_anon_thp ... # OK migration.private_anon_thp ok 3 migration.private_anon_thp # RUN migration.shared_anon_thp ... # OK migration.shared_anon_thp ok 4 migration.shared_anon_thp # RUN migration.private_anon_htlb ... # OK migration.private_anon_htlb ok 5 migration.private_anon_htlb # RUN migration.shared_anon_htlb ... # OK migration.shared_anon_htlb ok 6 migration.shared_anon_htlb # PASSED: 6 / 6 tests passed. # Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0 #
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/migration.c | 99 ++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
tools/testing/selftests/mm/migration.c +99 -0
@@ -205,4 +205,103 @@ TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME)ASSERT_EQ (pthread_cancel (self->threads[i]),0 ); } +/* +* migration test with shared anon THP page +*/ + +TEST_F_TIMEOUT(migration, shared_anon_thp, 2*RUNTIME) +{ +pid_t pid; +uint64_t *ptr; +int i; + +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 ) +SKIP (return,"Not enough threads or NUMA nodes available" ); + + ptr =mmap (NULL ,2 *TWOMEG ,PROT_READ |PROT_WRITE , +MAP_SHARED |MAP_ANONYMOUS ,-1 ,0 ); +ASSERT_NE (ptr,MAP_FAILED ); + + ptr = (uint64_t *)ALIGN ((uintptr_t ) ptr,TWOMEG ); +ASSERT_EQ (madvise (ptr,TWOMEG ,MADV_HUGEPAGE ),0 ); + +memset (ptr,0xde ,TWOMEG ); +for (i =0 ; i < self->nthreads -1 ; i++) { + pid =fork (); +if (!pid) { +prctl (PR_SET_PDEATHSIG ,SIGHUP ); +/* Parent may have died before prctl so check now. */ +if (getppid () ==1 ) +kill (getpid (),SIGHUP ); +access_mem (ptr); + }else { + self->pids[i] = pid; + } + } + +ASSERT_EQ (migrate (ptr, self->n1, self->n2),0 ); +for (i =0 ; i < self->nthreads -1 ; i++) +ASSERT_EQ (kill (self->pids[i],SIGTERM ),0 ); +} + +/* +* migration test with private anon hugetlb page +*/ +TEST_F_TIMEOUT(migration, private_anon_htlb, 2*RUNTIME) +{ +uint64_t *ptr; +int i; + +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 ) +SKIP (return,"Not enough threads or NUMA nodes available" ); + + ptr =mmap (NULL ,TWOMEG ,PROT_READ |PROT_WRITE , +MAP_PRIVATE |MAP_ANONYMOUS |MAP_HUGETLB ,-1 ,0 ); +ASSERT_NE (ptr,MAP_FAILED ); + +memset (ptr,0xde ,TWOMEG ); +for (i =0 ; i < self->nthreads -1 ; i++) +if (pthread_create (&self->threads[i],NULL , access_mem, ptr)) +perror ("Couldn't create thread" ); + +ASSERT_EQ (migrate (ptr, self->n1, self->n2),0 ); +for (i =0 ; i < self->nthreads -1 ; i++) +ASSERT_EQ (pthread_cancel (self->threads[i]),0 ); +} + +/* +* migration test with shared anon hugetlb page +*/ +TEST_F_TIMEOUT(migration, shared_anon_htlb, 2*RUNTIME) +{ +pid_t pid; +uint64_t *ptr; +int i; + +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 ) +SKIP (return,"Not enough threads or NUMA nodes available" ); + + ptr =mmap (NULL ,TWOMEG ,PROT_READ |PROT_WRITE , +MAP_SHARED |MAP_ANONYMOUS |MAP_HUGETLB ,-1 ,0 ); +ASSERT_NE (ptr,MAP_FAILED ); + +memset (ptr,0xde ,TWOMEG ); +for (i =0 ; i < self->nthreads -1 ; i++) { + pid =fork (); +if (!pid) { +prctl (PR_SET_PDEATHSIG ,SIGHUP ); +/* Parent may have died before prctl so check now. */ +if (getppid () ==1 ) +kill (getpid (),SIGHUP ); +access_mem (ptr); + }else { + self->pids[i] = pid; + } + } + +ASSERT_EQ (migrate (ptr, self->n1, self->n2),0 ); +for (i =0 ; i < self->nthreads -1 ; i++) +ASSERT_EQ (kill (self->pids[i],SIGTERM ),0 ); +} +TEST_HARNESS_MAIN
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 897/1376 ksm_tests: skip hugepage test when Transparent Hugepages are disabled
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Wang <[email protected]>
[ Upstream commit fdc3bc3497946c6b416a17628907581657102e60 ]
Some systems (e.g. minimal or real-time kernels) may not enable Transparent Hugepages (THP), causing MADV_HUGEPAGE to return EINVAL. This patch introduces a runtime check using the existing THP sysfs interface and skips the hugepage merging test (-H) when THP is not available.
To avoid those failures:
# -----------------------------
# running ./ksm_tests -H -s 100 # ----------------------------- # ksm_tests: MADV_HUGEPAGE: Invalid argument # [FAIL] not ok 1 ksm_tests -H -s 100 # exit=2
# --------------------
# running ./khugepaged # -------------------- # Reading PMD pagesize failed# [FAIL] not ok 1 khugepaged # exit=1
# --------------------
# running ./soft-dirty # -------------------- # TAP version 13 # 1..15 # ok 1 Test test_simple # ok 2 Test test_vma_reuse dirty bit of allocated page # ok 3 Test test_vma_reuse dirty bit of reused address page # Bail out! Reading PMD pagesize failed# Planned tests != run tests (15 != 3) # # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0 # [FAIL] not ok 1 soft-dirty # exit=1 # SUMMARY: PASS=0 SKIP=0 FAIL=1
# -------------------
# running ./migration # ------------------- # TAP version 13 # 1..3 # # Starting 3 tests from 1 test cases. # # RUN migration.private_anon ... # # OK migration.private_anon # ok 1 migration.private_anon # # RUN migration.shared_anon ... # # OK migration.shared_anon # ok 2 migration.shared_anon # # RUN migration.private_anon_thp ... # # migration.c:196:private_anon_thp:Expected madvise(ptr, TWOMEG, MADV_HUGEPAGE) (-1) == 0 (0) # # private_anon_thp: Test terminated by assertion # # FAIL migration.private_anon_thp # not ok 3 migration.private_anon_thp # # FAILED: 2 / 3 tests passed. # # Totals: pass:2 fail:1 xfail:0 xpass:0 skip:0 error:0 # [FAIL] not ok 1 migration # exit=1
It's true that CONFIG_TRANSPARENT_HUGEPAGE=y is explicitly enabled in tools/testing/selftests/mm/config, so ideally the runtime environment should also support THP.
However, in practice, we've found that on some systems:
- THP is disabled at boot time (transparent_hugepage=never)
- Or manually disabled via sysfs
- Or unavailable in RT kernels, containers, or minimal CI environments
In these cases, the test will fail with EINVAL on madvise(MADV_HUGEPAGE), even though the kernel config is correct.
To make the test suite more robust and avoid false negatives, this patch adds a runtime check for /sys/kernel/mm/transparent_hugepage/enabled.
If THP is not available, the hugepage test (-H) is skipped with a clear message.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/khugepaged.c | 5 +++++ tools/testing/selftests/mm/ksm_tests.c | 6 ++++++ tools/testing/selftests/mm/migration.c | 8 ++++++++ tools/testing/selftests/mm/soft-dirty.c | 9 ++++++++- tools/testing/selftests/mm/thp_settings.c | 11 +++++++++++ tools/testing/selftests/mm/thp_settings.h | 2 ++ 6 files changed, 40 insertions(+), 1 deletion(-)
tools/testing/selftests/mm/khugepaged.c +5 -0
@@ -1190,6 +1190,11 @@ int main(int argc, char **argv) .read_ahead_kb = 0, }; +if (!thp_is_enabled ()) { +printf ("Transparent Hugepages not available\n" ); +return KSFT_SKIP ; + } +parse_test_type (argc, argv);setbuf (stdout,NULL );
tools/testing/selftests/mm/ksm_tests.c +6 -0
@@ -15,6 +15,7 @@#include "../kselftest.h" #include <include/vdso/time64.h> #include "vm_util.h" +#include "thp_settings.h" #define KSM_SYSFS_PATH "/sys/kernel/mm/ksm/"#define KSM_FP (s) (KSM_SYSFS_PATH s)
@@ -555,6 +556,11 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,unsigned long scan_time_ns;int pagemap_fd, n_normal_pages, n_huge_pages; +if (!thp_is_enabled ()) { +printf ("Transparent Hugepages not available\n" ); +return KSFT_SKIP ; + } + map_size *=MB ;size_t len = map_size;
tools/testing/selftests/mm/migration.c +8 -0
@@ -5,6 +5,8 @@*/ #include "../kselftest_harness.h" +#include "thp_settings.h" +#include <strings.h> #include <pthread.h> #include <numa.h>
@@ -186,6 +188,9 @@ TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME)uint64_t *ptr;int i; +if (!thp_is_enabled ()) +SKIP (return,"Transparent Hugepages not available" ); +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 )SKIP (return,"Not enough threads or NUMA nodes available" );
@@ -215,6 +220,9 @@ TEST_F_TIMEOUT(migration, shared_anon_thp, 2*RUNTIME)uint64_t *ptr;int i; +if (!thp_is_enabled ()) +SKIP (return,"Transparent Hugepages not available" ); +if (self->nthreads <2 || self->n1 <0 || self->n2 <0 )SKIP (return,"Not enough threads or NUMA nodes available" );
tools/testing/selftests/mm/soft-dirty.c +8 -1
@@ -6,8 +6,10 @@#include <stdint.h> #include <malloc.h> #include <sys/mman.h> +#include "../kselftest.h" #include "vm_util.h" +#include "thp_settings.h" #define PAGEMAP_FILE_PATH "/proc/self/pagemap"#define TEST_ITERATIONS 10000
@@ -78,8 +80,13 @@ static void test_hugepage(int pagemap_fd, int pagesize) {char *map;int i, ret; -size_t hpage_len =read_pmd_pagesize (); +if (!thp_is_enabled ()) { +ksft_test_result_skip ("Transparent Hugepages not available\n" ); +return ; + } + +size_t hpage_len =read_pmd_pagesize ();if (!hpage_len)ksft_exit_fail_msg ("Reading PMD pagesize failed" );
tools/testing/selftests/mm/thp_settings.c +11 -0
@@ -381,3 +381,14 @@ unsigned long thp_shmem_supported_orders(void) {return __thp_supported_orders (true); } + +bool thp_is_enabled (void ) +{ +if (access (THP_SYSFS ,F_OK ) !=0 ) +return false; + +int mode =thp_read_string ("enabled" , thp_enabled_strings); + +/* THP is considered enabled if it's either "always" or "madvise" */ +return mode ==1 || mode ==3 ; +}
tools/testing/selftests/mm/thp_settings.h +2 -0
@@ -84,4 +84,6 @@ void thp_set_read_ahead_path(char *path);unsigned long thp_supported_orders (void );unsigned long thp_shmem_supported_orders (void ); +bool thp_is_enabled (void ); +#endif /* __THP_SETTINGS_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 898/1376 selftests/mm: ksm_tests: use kselftest framework
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Rapoport (Microsoft) <[email protected]>
[ Upstream commit 4cc68d5f52de9614e2db70f43c52f012d1ebb5ad ]
Convert ksm_tests to use kselftest framework for reporting and tracking successful and failing runs.
Stable-dep-of: 15828a150c58 ("selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes")
--- tools/testing/selftests/mm/ksm_tests.c | 180 +++++++++++-------------- 1 file changed, 81 insertions(+), 99 deletions(-)
tools/testing/selftests/mm/ksm_tests.c +81 -99
@@ -203,12 +203,12 @@ static void *allocate_memory(void *ptr, int prot, int mapping, char data, size_void *map_ptr =mmap (ptr, map_size,PROT_WRITE , mapping,-1 ,0 );if (!map_ptr) { -perror ("mmap" ); +ksft_perror ("mmap" );return NULL ; }memset (map_ptr, data, map_size);if (mprotect (map_ptr, map_size, prot)) { -perror ("mprotect" ); +ksft_perror ("mprotect" );munmap (map_ptr, map_size);return NULL ; }
@@ -229,11 +229,11 @@ static int ksm_do_scan(int scan_count, struct timespec start_time, int timeout)if (ksm_read_sysfs (KSM_FP ("full_scans" ), &cur_scan))return 1 ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &cur_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return 1 ; }if ((cur_time.tv_sec - start_time.tv_sec) > timeout) { -printf ("Scan time limit exceeded\n" ); +ksft_print_msg ("Scan time limit exceeded\n" );return 1 ; } }
@@ -246,12 +246,12 @@ static int ksm_merge_pages(int merge_type, void *addr, size_t size, {if (merge_type ==KSM_MERGE_MADVISE ) {if (madvise (addr, size,MADV_MERGEABLE )) { -perror ("madvise" ); +ksft_perror ("madvise" );return 1 ; } }else if (merge_type ==KSM_MERGE_PRCTL ) {if (prctl (PR_SET_MEMORY_MERGE ,1 ,0 ,0 ,0 )) { -perror ("prctl" ); +ksft_perror ("prctl" );return 1 ; } }
@@ -270,7 +270,7 @@ static int ksm_unmerge_pages(void *addr, size_t size, struct timespec start_time, int timeout) { if (madvise(addr, size, MADV_UNMERGEABLE)) { -perror ("madvise" ); +ksft_perror ("madvise" );return 1 ; }return 0 ;
@@ -352,7 +352,7 @@ static int check_ksm_merge(int merge_type, int mapping, int prot,struct timespec start_time;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }
@@ -366,7 +366,6 @@ static int check_ksm_merge(int merge_type, int mapping, int prot,/* verify that the right number of pages are merged */ if (assert_ksm_pages_count (page_count)) { -printf ("OK\n" );munmap (map_ptr, page_size * page_count);if (merge_type ==KSM_MERGE_PRCTL )prctl (PR_SET_MEMORY_MERGE ,0 ,0 ,0 ,0 );
@@ -374,7 +373,6 @@ static int check_ksm_merge(int merge_type, int mapping, int prot, } err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -386,7 +384,7 @@ static int check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout,int page_count =2 ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }
@@ -408,13 +406,11 @@ static int check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout,/* check that unmerging was successful and 0 pages are currently merged */ if (assert_ksm_pages_count (0 )) { -printf ("OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_PASS ; } err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -426,7 +422,7 @@ static int check_ksm_zero_page_merge(int merge_type, int mapping, int prot, longstruct timespec start_time;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }
@@ -453,12 +449,10 @@ static int check_ksm_zero_page_merge(int merge_type, int mapping, int prot, longelse if (!use_zero_pages && !assert_ksm_pages_count (page_count)) goto err_out; -printf ("OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -493,16 +487,16 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeoint first_node;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }if (numa_available () <0 ) { -perror ("NUMA support not enabled" ); +ksft_print_msg ("NUMA support not enabled\n" );return KSFT_SKIP ; }if (numa_num_configured_nodes () <=1 ) { -printf ("At least 2 NUMA nodes must be available\n" ); +ksft_print_msg ("At least 2 NUMA nodes must be available\n" );return KSFT_SKIP ; }if (ksm_write_sysfs (KSM_FP ("merge_across_nodes" ), merge_across_nodes))
@@ -513,7 +507,7 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo numa1_map_ptr =numa_alloc_onnode (page_size, first_node); numa2_map_ptr =numa_alloc_onnode (page_size,get_next_mem_node (first_node));if (!numa1_map_ptr || !numa2_map_ptr) { -perror ("numa_alloc_onnode" ); +ksft_perror ("numa_alloc_onnode" );return KSFT_FAIL ; }
@@ -538,13 +532,11 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeonuma_free (numa1_map_ptr, page_size);numa_free (numa2_map_ptr, page_size); -printf ("OK\n" );return KSFT_PASS ; err_out:numa_free (numa1_map_ptr, page_size);numa_free (numa2_map_ptr, page_size); -printf ("Not OK\n" );return KSFT_FAIL ; }
@@ -557,7 +549,7 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,int pagemap_fd, n_normal_pages, n_huge_pages;if (!thp_is_enabled ()) { -printf ("Transparent Hugepages not available\n" ); +ksft_print_msg ("Transparent Hugepages not available\n" );return KSFT_SKIP ; }
@@ -587,36 +579,35 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,else n_huge_pages++; } -printf ("Number of normal pages: %d\n" , n_normal_pages); -printf ("Number of huge pages: %d\n" , n_huge_pages); +ksft_print_msg ("Number of normal pages: %d\n" , n_normal_pages); +ksft_print_msg ("Number of huge pages: %d\n" , n_huge_pages);memset (map_ptr,'*' , len);if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_merge_pages (merge_type, map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } scan_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n" , map_size /MB ); -printf ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n" , map_size /MB ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , scan_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / ((double )scan_time_ns /NSEC_PER_SEC ));munmap (map_ptr_orig, len +HPAGE_SIZE );return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr_orig, len +HPAGE_SIZE );return KSFT_FAIL ; }
@@ -634,30 +625,29 @@ static int ksm_merge_time(int merge_type, int mapping, int prot, int timeout, sireturn KSFT_FAIL ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_merge_pages (merge_type, map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } scan_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n" , map_size /MB ); -printf ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n" , map_size /MB ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , scan_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / ((double )scan_time_ns /NSEC_PER_SEC ));munmap (map_ptr, map_size);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, map_size);return KSFT_FAIL ; }
@@ -674,37 +664,36 @@ static int ksm_unmerge_time(int merge_type, int mapping, int prot, int timeout,if (!map_ptr)return KSFT_FAIL ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_merge_pages (merge_type, map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }if (ksm_unmerge_pages (map_ptr, map_size, start_time, timeout)) goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } scan_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n" , map_size /MB ); -printf ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n" , map_size /MB ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , scan_time_ns /NSEC_PER_SEC , scan_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , (map_size /MB ) / ((double )scan_time_ns /NSEC_PER_SEC ));munmap (map_ptr, map_size);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, map_size);return KSFT_FAIL ; }
@@ -723,24 +712,24 @@ static int ksm_cow_time(int merge_type, int mapping, int prot, int timeout, sizereturn KSFT_FAIL ;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; }for (size_t i =0 ; i < page_count -1 ; i = i +2 )memset (map_ptr + page_size * i,'-' ,1 );if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" );return KSFT_FAIL ; } cow_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Total size: %lu MiB\n\n" , (page_size * page_count) /MB ); -printf ("Not merged pages:\n" ); -printf ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Total size: %lu MiB\n\n" , (page_size * page_count) /MB ); +ksft_print_msg ("Not merged pages:\n" ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , cow_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n\n" , ((page_size * (page_count /2 )) /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n\n" , ((page_size * (page_count /2 )) /MB ) / ((double )cow_time_ns /NSEC_PER_SEC ));/* Create 2000 pairs of duplicate pages */
@@ -752,30 +741,29 @@ static int ksm_cow_time(int merge_type, int mapping, int prot, int timeout, size goto err_out;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; }for (size_t i =0 ; i < page_count -1 ; i = i +2 )memset (map_ptr + page_size * i,'-' ,1 );if (clock_gettime (CLOCK_MONOTONIC_RAW , &end_time)) { -perror ("clock_gettime" ); +ksft_perror ("clock_gettime" ); goto err_out; } cow_time_ns = (end_time.tv_sec - start_time.tv_sec) *NSEC_PER_SEC + (end_time.tv_nsec - start_time.tv_nsec); -printf ("Merged pages:\n" ); -printf ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , +ksft_print_msg ("Merged pages:\n" ); +ksft_print_msg ("Total time: %ld.%09ld s\n" , cow_time_ns /NSEC_PER_SEC , cow_time_ns %NSEC_PER_SEC ); -printf ("Average speed: %.3f MiB/s\n" , ((page_size * (page_count /2 )) /MB ) / +ksft_print_msg ("Average speed: %.3f MiB/s\n" , ((page_size * (page_count /2 )) /MB ) / ((double )cow_time_ns /NSEC_PER_SEC ));munmap (map_ptr, page_size * page_count);return KSFT_PASS ; err_out: -printf ("Not OK\n" );munmap (map_ptr, page_size * page_count);return KSFT_FAIL ; }
@@ -793,6 +781,10 @@ int main(int argc, char *argv[])bool use_zero_pages =KSM_USE_ZERO_PAGES_DEFAULT ;bool merge_across_nodes =KSM_MERGE_ACROSS_NODES_DEFAULT ;long size_MB =0 ; +const char *test_descr ="KSM merging" ; + +ksft_print_header (); +ksft_set_plan (1 );while ((opt =getopt (argc, argv,"dha:p:l:z:m:s:t:MUZNPCHD" )) !=-1 ) {switch (opt) {
@@ -801,17 +793,13 @@ int main(int argc, char *argv[])break ;case 'p' : page_count =atol (optarg); -if (page_count <=0 ) { -printf ("The number of pages must be greater than 0\n" ); -return KSFT_FAIL ; - } +if (page_count <=0 ) +ksft_exit_fail_msg ("The number of pages must be greater than 0\n" );break ;case 'l' : ksm_scan_limit_sec =atoi (optarg); -if (ksm_scan_limit_sec <=0 ) { -printf ("Timeout value must be greater than 0\n" ); -return KSFT_FAIL ; - } +if (ksm_scan_limit_sec <=0 ) +ksft_exit_fail_msg ("Timeout value must be greater than 0\n" );break ;case 'h' :print_help ();
@@ -833,19 +821,15 @@ int main(int argc, char *argv[])break ;case 's' : size_MB =atoi (optarg); -if (size_MB <=0 ) { -printf ("Size must be greater than 0\n" ); -return KSFT_FAIL ; - } +if (size_MB <=0 ) +ksft_exit_fail_msg ("Size must be greater than 0\n" );break ;case 't' : {int tmp =atoi (optarg); -if (tmp <0 || tmp >KSM_MERGE_LAST ) { -printf ("Invalid merge type\n" ); -return KSFT_FAIL ; - } +if (tmp <0 || tmp >KSM_MERGE_LAST ) +ksft_exit_fail_msg ("Invalid merge type\n" ); merge_type = tmp; }break ;
@@ -873,82 +857,80 @@ int main(int argc, char *argv[]) test_name =KSM_COW_TIME ;break ;default : -return KSFT_FAIL ; +ksft_exit_fail_msg ("Unknown option\n" ); } }if (prot ==0 ) prot =str_to_prot (KSM_PROT_STR_DEFAULT ); -if (access (KSM_SYSFS_PATH ,F_OK )) { -printf ("Config KSM not enabled\n" ); -return KSFT_SKIP ; - } +if (access (KSM_SYSFS_PATH ,F_OK )) +ksft_exit_skip ("Config KSM not enabled\n" ); -if (ksm_save_def (&ksm_sysfs_old)) { -printf ("Cannot save default tunables\n" ); -return KSFT_FAIL ; - } +if (ksm_save_def (&ksm_sysfs_old)) +ksft_exit_fail_msg ("Cannot save default tunables\n" );if (ksm_write_sysfs (KSM_FP ("run" ),2 ) ||ksm_write_sysfs (KSM_FP ("sleep_millisecs" ),0 ) ||numa_available () ?0 :ksm_write_sysfs (KSM_FP ("merge_across_nodes" ),1 ) ||ksm_write_sysfs (KSM_FP ("pages_to_scan" ), page_count)) -return KSFT_FAIL ; +ksft_exit_fail_msg ("Cannot set up KSM tunables\n" );switch (test_name) {case CHECK_KSM_MERGE : + test_descr ="KSM merging" ; ret =check_ksm_merge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, page_count, ksm_scan_limit_sec, page_size);break ;case CHECK_KSM_UNMERGE : + test_descr ="KSM unmerging" ; ret =check_ksm_unmerge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, page_size);break ;case CHECK_KSM_ZERO_PAGE_MERGE : + test_descr ="KSM zero page merging" ; ret =check_ksm_zero_page_merge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, page_count, ksm_scan_limit_sec, use_zero_pages, page_size);break ;case CHECK_KSM_NUMA_MERGE : + test_descr ="KSM NUMA merging" ; ret =check_ksm_numa_merge (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, merge_across_nodes, page_size);break ;case KSM_MERGE_TIME : -if (size_MB ==0 ) { -printf ("Option '-s' is required.\n" ); -return KSFT_FAIL ; - } +if (size_MB ==0 ) +ksft_exit_fail_msg ("Option '-s' is required\n" ); + test_descr ="KSM merge time" ; ret =ksm_merge_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, size_MB);break ;case KSM_MERGE_TIME_HUGE_PAGES : -if (size_MB ==0 ) { -printf ("Option '-s' is required.\n" ); -return KSFT_FAIL ; - } +if (size_MB ==0 ) +ksft_exit_fail_msg ("Option '-s' is required\n" ); + test_descr ="KSM merge time with huge pages" ; ret =ksm_merge_hugepages_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, size_MB);break ;case KSM_UNMERGE_TIME : -if (size_MB ==0 ) { -printf ("Option '-s' is required.\n" ); -return KSFT_FAIL ; - } +if (size_MB ==0 ) +ksft_exit_fail_msg ("Option '-s' is required\n" ); + test_descr ="KSM unmerge time" ; ret =ksm_unmerge_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, size_MB);break ;case KSM_COW_TIME : + test_descr ="KSM COW time" ; ret =ksm_cow_time (merge_type,MAP_PRIVATE |MAP_ANONYMOUS , prot, ksm_scan_limit_sec, page_size);break ; } -if (ksm_restore (&ksm_sysfs_old)) { -printf ("Cannot restore default tunables\n" ); -return KSFT_FAIL ; - } +if (ksm_restore (&ksm_sysfs_old)) +ksft_print_msg ("Cannot restore default tunables\n" ); + +ksft_test_result_report (ret,"%s\n" , test_descr); -return ret; +ksft_finished (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 899/1376 selftests/mm: fix ksm NUMA merge test for systems with memoryless NUMA nodes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 15828a150c5806869b7feb9e38ad2c0284fbf18a ]
The KSM NUMA merge test allocates identical pages on different NUMA nodes and verifies KSM behavior with merge_across_nodes enabled and disabled.
On systems with memoryless NUMA nodes, for example:
#numactl -H
available: 2 nodes (0,4)
.....
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 14825 MB
node 0 free: 1382 MB
node 4 cpus:
node 4 size: 0 MB
node 4 free: 0 MBthe test may attempt to allocate memory on a node without memory, causing numa_alloc_onnode() to fail and resulting in a spurious test failure.
The test currently checks numa_num_configured_nodes() to determine whether sufficient NUMA nodes are available. However, configured nodes do not necessarily have memory.
Reuse the existing get_first_mem_node() and get_next_mem_node() helpers to locate NUMA nodes that actually contain memory, and skip the test when fewer than two such nodes are available.
Before patch:
---------------------------
running ./ksm_tests -N -m 1
---------------------------
mbind: Invalid argument
ok 1 KSM NUMA merging
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0 [PASS]
ok 1 ksm_tests -N -m 1
---------------------------
running ./ksm_tests -N -m 0
---------------------------
mbind: Invalid argument
not ok 1 KSM NUMA merging
Totals: pass:0 fail:1 xfail:0 xpass:0 skip:0 error:0 [FAIL]
not ok 2 ksm_tests -N -m 0 # exit=1
After patch:
---------------------------
running ./ksm_tests -N -m 1
---------------------------
At least 2 NUMA nodes with memory must be available ok 1
SKIP KSM NUMA merging
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0 [PASS]
ok 1 ksm_tests -N -m 1
---------------------------
running ./ksm_tests -N -m 0
---------------------------
At least 2 NUMA nodes with memory must be available ok 1
SKIP KSM NUMA merging
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0 [PASS]
ok 2 ksm_tests -N -m 0
--- tools/testing/selftests/mm/ksm_tests.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
tools/testing/selftests/mm/ksm_tests.c +9 -7
@@ -468,9 +468,9 @@ static int get_next_mem_node(int node) mem_node = i % (max_node +1 ); node_size =numa_node_size (mem_node,NULL );if (node_size >0 ) -break ; +return mem_node; } -return mem_node; +return -ENODEV ; }static int get_first_mem_node (void )
@@ -483,8 +483,8 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeo {void *numa1_map_ptr, *numa2_map_ptr;struct timespec start_time; +int first_node, second_node;int page_count =2 ; -int first_node;if (clock_gettime (CLOCK_MONOTONIC_RAW , &start_time)) {ksft_perror ("clock_gettime" );
@@ -495,17 +495,19 @@ static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeoksft_print_msg ("NUMA support not enabled\n" );return KSFT_SKIP ; } -if (numa_num_configured_nodes () <=1 ) { -ksft_print_msg ("At least 2 NUMA nodes must be available\n" ); + first_node =get_first_mem_node (); + second_node =get_next_mem_node (first_node); + +if (second_node <0 ) { +ksft_print_msg ("At least 2 NUMA nodes with memory must be available\n" );return KSFT_SKIP ; }if (ksm_write_sysfs (KSM_FP ("merge_across_nodes" ), merge_across_nodes))return KSFT_FAIL ;/* allocate 2 pages in 2 different NUMA nodes and fill them with the same data */ - first_node =get_first_mem_node (); numa1_map_ptr =numa_alloc_onnode (page_size, first_node); - numa2_map_ptr =numa_alloc_onnode (page_size,get_next_mem_node (first_node)); + numa2_map_ptr =numa_alloc_onnode (page_size, second_node);if (!numa1_map_ptr || !numa2_map_ptr) {ksft_perror ("numa_alloc_onnode" );return KSFT_FAIL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 900/1376 selftests/mm: fix ternary operator precedence in ksm_tests
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 4e1fbffb3333626682a011db7c4b4e9e40ba96d4 ]
The KSM selftest uses conditional expressions to skip accesses to merge_across_nodes on systems without NUMA support. However, the ternary operator is combined with logical OR without parentheses:
a || numa_available() ? 0 : b || c
Due to operator precedence rules, this is parsed as:
(a || numa_available()) ? 0 : (b || c)
instead of the intended:
a || (numa_available() ? 0 : b) || c
Add parentheses around the conditional expressions to ensure the correct evaluation order.
--- tools/testing/selftests/mm/ksm_tests.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
tools/testing/selftests/mm/ksm_tests.c +6 -6
@@ -316,8 +316,8 @@ static bool assert_ksm_pages_count(long dupl_page_count)static int ksm_save_def (struct ksm_sysfs *ksm_sysfs) { if (ksm_read_sysfs(KSM_FP("max_page_sharing"), &ksm_sysfs->max_page_sharing) || - numa_available() ? 0 : - ksm_read_sysfs(KSM_FP("merge_across_nodes"), &ksm_sysfs->merge_across_nodes) || + (numa_available() ? 0 : + ksm_read_sysfs(KSM_FP("merge_across_nodes"), &ksm_sysfs->merge_across_nodes)) || ksm_read_sysfs(KSM_FP("sleep_millisecs"), &ksm_sysfs->sleep_millisecs) || ksm_read_sysfs(KSM_FP("pages_to_scan"), &ksm_sysfs->pages_to_scan) || ksm_read_sysfs(KSM_FP("run"), &ksm_sysfs->run) ||
@@ -332,8 +332,8 @@ static int ksm_save_def(struct ksm_sysfs *ksm_sysfs)static int ksm_restore (struct ksm_sysfs *ksm_sysfs) { if (ksm_write_sysfs(KSM_FP("max_page_sharing"), ksm_sysfs->max_page_sharing) || - numa_available() ? 0 : - ksm_write_sysfs(KSM_FP("merge_across_nodes"), ksm_sysfs->merge_across_nodes) || + (numa_available() ? 0 : + ksm_write_sysfs(KSM_FP("merge_across_nodes"), ksm_sysfs->merge_across_nodes)) || ksm_write_sysfs(KSM_FP("pages_to_scan"), ksm_sysfs->pages_to_scan) || ksm_write_sysfs(KSM_FP("run"), ksm_sysfs->run) || ksm_write_sysfs(KSM_FP("sleep_millisecs"), ksm_sysfs->sleep_millisecs) ||
@@ -874,8 +874,8 @@ int main(int argc, char *argv[])if (ksm_write_sysfs (KSM_FP ("run" ),2 ) ||ksm_write_sysfs (KSM_FP ("sleep_millisecs" ),0 ) || -numa_available () ?0 : -ksm_write_sysfs (KSM_FP ("merge_across_nodes" ),1 ) || + (numa_available () ?0 : +ksm_write_sysfs (KSM_FP ("merge_across_nodes" ),1 )) ||ksm_write_sysfs (KSM_FP ("pages_to_scan" ), page_count))ksft_exit_fail_msg ("Cannot set up KSM tunables\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 901/1376 arm64: dts: qcom: qcs8550-aim300: Fix swapped USB QMP PHY vdda-phy/vdda-pll supplies
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit c0ea3b6339881c2a5fff0830557b1279d9681036 ]
The QMP PHY expects the vdda-phy supply to be around 0.88V and the vdda-pll supply to be 1.2V. But these two supplies are swapped for the USB QMP PHY on this board, feeding 1.2V to vdda-phy and 0.88V to vdda-pll.
Fix it by swapping the two supplies back.
--- arch/arm64/boot/dts/qcom/qcs8550-aim300.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/qcom/qcs8550-aim300.dtsi +2 -2
@@ -396,8 +396,8 @@ &usb_1_hsphy { }; &usb_dp_qmpphy { - vdda-phy-supply = <&vreg_l3e_1p2>; - vdda-pll-supply = <&vreg_l3f_0p88>; + vdda-phy-supply = <&vreg_l3f_0p88>; + vdda-pll-supply = <&vreg_l3e_1p2>; }; &xo_board {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 902/1376 arm64: dts: qcom: sm7225-fairphone-fp4: Fix swapped USB QMP PHY vdda-phy/vdda-pll supplies
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit a3b3a060b696d964c769a7d9dc5835c79e4fe964 ]
The QMP PHY expects the vdda-phy supply to be around 0.88V and the vdda-pll supply to be 1.2V. But these two supplies are swapped for the USB QMP PHY on this board, feeding 1.2V to vdda-phy and 0.9V to vdda-pll.
Fix it by swapping the two supplies back.
--- arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +2 -2
@@ -1143,8 +1143,8 @@ &usb_1_hsphy { }; &usb_1_qmpphy { - vdda-phy-supply = <&vreg_l22a>; - vdda-pll-supply = <&vreg_l16a>; + vdda-phy-supply = <&vreg_l16a>; + vdda-pll-supply = <&vreg_l22a>; status = "okay"; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 903/1376 scripts/tags.sh: Prevent binary files appearing in cscope.files
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergei Litvin <[email protected]>
[ Upstream commit a9b93c34625a27bed5dc0f80ee2a359ceb955172 ]
When executing the command make COMPILED_SOURCE=1 cscope, the resulting cscope.files file contains filenames with the extensions *.rlib, *.rmeta, and *.so.
To fix this, modify the regular expression in the all_compiled_sources() function so that only files with the extensions *.h, *.c, *.S, and *.rs are accepted.
The issue has been introduced by commit 4f491bb6ea2a ("scripts/tags.sh:
collect compiled source precisely") which implemented the parsing of compiled sources from *.cmd files instead of using the "find" command.
--- scripts/tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/tags.sh +1 -1
@@ -100,7 +100,7 @@ all_compiled_sources() { echo include/generated/autoconf.h find $ignore -name "*.cmd" -exec \ - grep -Poh '(?<=^ )\S+|(?<== )\S+[^\\](?=$)' {} \+ | + grep -Poh '(?<=^ )\S+\.([chS]|rs)(?=\s)|(?<== )\S+\.(?1)(?=$)' {} \+ | awk '!a[$0]++' } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) | sort -u
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 904/1376 modpost: prevent leak when early return no suffix .o in read_symbols()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Robertus Diawan Chris <[email protected]>
[ Upstream commit 9a5b76027ed91680e10f90111d9cba300f96d1ab ]
The allocation for elf info symsearch and hdr from parse_elf() haven't been released when return because of modname didn't have suffix ".o". And it seems like the suffix ".o" check did not depends on parse_elf() to succeed first. So, move the suffix ".o" check before checking parse_elf() result to prevent resource leak when the modname didn't have suffix ".o" and return early.
This is reported by Coverity Scan as "Resource leak".
--- scripts/mod/modpost.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
scripts/mod/modpost.c +3 -3
@@ -1567,14 +1567,14 @@ static void read_symbols(const char *modname)struct elf_info info = { };Elf_Sym *sym; -if (!parse_elf (&info, modname)) -return ; -if (!strends (modname,".o" )) {error ("%s: filename must be suffixed with .o\n" , modname);return ; } +if (!parse_elf (&info, modname)) +return ; +/* strip trailing .o */ mod =new_module (modname,strlen (modname) -strlen (".o" ));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 905/1376 RDMA/erdma: Hold CQ references when processing EQ events
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng Xu <[email protected]>
[ Upstream commit 98df2aee1459ee1c62c70cbe9b370d2a532aea36 ]
EQ handlers look up CQs from dev->cq_xa and invoke CQ completion or error callbacks outside the xarray lock. erdma_destroy_cq() can erase the CQ from the xarray and free its queue buffer and doorbell record while a previously scheduled EQ handler is still using the CQ.
Add a CQ refcount and take a reference under the xarray lock with refcount_inc_not_zero(). Remove the CQ from the xarray before dropping the destroy-path reference, then wait for in-flight EQ users before releasing CQ resources.
--- drivers/infiniband/hw/erdma/erdma_eq.c | 6 ++++-- drivers/infiniband/hw/erdma/erdma_verbs.c | 12 +++++++++-- drivers/infiniband/hw/erdma/erdma_verbs.h | 25 +++++++++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-)
drivers/infiniband/hw/erdma/erdma_eq.c +4 -2
@@ -52,7 +52,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)if (FIELD_GET (ERDMA_AEQE_HDR_TYPE_MASK ,le32_to_cpu (aeqe->hdr)) ==ERDMA_AE_TYPE_CQ_ERR ) { cqn =le32_to_cpu (aeqe->event_data0); - cq =find_cq_by_cqn (dev, cqn); + cq =erdma_cq_get_by_cqn (dev, cqn);if (!cq)continue ;
@@ -62,6 +62,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)if (cq->ibcq.event_handler) cq->ibcq.event_handler (&event, cq->ibcq.cq_context); +erdma_cq_put (cq); }else { qpn =le32_to_cpu (aeqe->event_data0); qp =find_qp_by_qpn (dev, qpn);
@@ -157,7 +158,7 @@ void erdma_ceq_completion_handler(struct erdma_eq_cb *ceq_cb) poll_cnt++; cqn =FIELD_GET (ERDMA_CEQE_HDR_CQN_MASK ,READ_ONCE (*ceqe)); - cq =find_cq_by_cqn (dev, cqn); + cq =erdma_cq_get_by_cqn (dev, cqn);if (!cq)continue ;
@@ -166,6 +167,7 @@ void erdma_ceq_completion_handler(struct erdma_eq_cb *ceq_cb)if (cq->ibcq.comp_handler) cq->ibcq.comp_handler (&cq->ibcq, cq->ibcq.cq_context); +erdma_cq_put (cq); }notify_eq (&ceq_cb->eq);
drivers/infiniband/hw/erdma/erdma_verbs.c +10 -2
@@ -1278,6 +1278,7 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)struct erdma_dev *dev =to_edev (ibcq->device);struct erdma_ucontext *ctx =rdma_udata_to_drv_context ( udata, struct erdma_ucontext, ibucontext); +unsigned long flags;int err;struct erdma_cmdq_destroy_cq_req req;
@@ -1292,6 +1293,13 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)"failed to destroy CQ %u: %d\n" , cq->cqn, err); +xa_lock_irqsave (&dev->cq_xa, flags); +__xa_erase (&dev->cq_xa, cq->cqn); +xa_unlock_irqrestore (&dev->cq_xa, flags); + +erdma_cq_put (cq); +wait_for_completion (&cq->free); +if (rdma_is_kernel_res (&cq->ibcq.res)) {dma_free_coherent (&dev->pdev->dev, cq->depth <<CQE_SHIFT , cq->kern_cq.qbuf, cq->kern_cq.qbuf_dma_addr);
@@ -1302,8 +1310,6 @@ int erdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)put_mtt_entries (dev, &cq->user_cq.qbuf_mem); } -xa_erase (&dev->cq_xa, cq->cqn); -return 0 ; }
@@ -1932,6 +1938,8 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->ibcq.cqe = depth; cq->depth = depth; cq->assoc_eqn = attr->comp_vector +1 ; +refcount_set (&cq->refcount,1 ); +init_completion (&cq->free); ret = xa_alloc_cyclic(&dev->cq_xa, &cq->cqn, cq, XA_LIMIT(1, dev->attrs.max_cq - 1),
drivers/infiniband/hw/erdma/erdma_verbs.h +23 -2
@@ -7,6 +7,9 @@#ifndef __ERDMA_VERBS_H__#define __ERDMA_VERBS_H__ +#include <linux/completion.h> +#include <linux/refcount.h> +#include "erdma.h" /* RDMA Capability. */
@@ -341,6 +344,8 @@ struct erdma_cq {u32 depth;u32 assoc_eqn; +refcount_t refcount; +struct completion free;union {struct erdma_kcq_info kern_cq;
@@ -355,9 +360,25 @@ static inline struct erdma_qp *find_qp_by_qpn(struct erdma_dev *dev, int id)return (struct erdma_qp *)xa_load (&dev->qp_xa, id); } -static inline struct erdma_cq *find_cq_by_cqn (struct erdma_dev *dev,int id) +static inline struct erdma_cq *erdma_cq_get_by_cqn (struct erdma_dev *dev, +int id) +{ +struct erdma_cq *cq; +unsigned long flags; + +xa_lock_irqsave (&dev->cq_xa, flags); + cq =xa_load (&dev->cq_xa, id); +if (cq && !refcount_inc_not_zero (&cq->refcount)) + cq =NULL ; +xa_unlock_irqrestore (&dev->cq_xa, flags); + +return cq; +} + +static inline void erdma_cq_put (struct erdma_cq *cq) { -return (struct erdma_cq *)xa_load (&dev->cq_xa, id); +if (refcount_dec_and_test (&cq->refcount)) +complete (&cq->free); }void erdma_qp_get (struct erdma_qp *qp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 906/1376 RDMA/erdma: Hold QP references for AE and CM processing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng Xu <[email protected]>
[ Upstream commit a52eeff32024f190b3bdc99088c7becccd4fa60b ]
AE QP fatal events and iWARP CM paths load QPs from dev->qp_xa and then use or reference them outside the xarray lock. erdma_destroy_qp() can drop the destroy-path reference and free QP resources while such a lookup is in flight.
Add erdma_qp_get_by_qpn() to acquire a kref under the xarray lock with kref_get_unless_zero(). Remove the QP from the xarray before dropping the destroy-path reference so no new lookup can acquire it while destruction waits for existing users.
--- drivers/infiniband/hw/erdma/erdma_cm.c | 6 ++---- drivers/infiniband/hw/erdma/erdma_eq.c | 3 ++- drivers/infiniband/hw/erdma/erdma_verbs.c | 6 +++++- drivers/infiniband/hw/erdma/erdma_verbs.h | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 6 deletions(-)
drivers/infiniband/hw/erdma/erdma_cm.c +2 -4
@@ -1021,10 +1021,9 @@ int erdma_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)if (laddr->sa_family !=AF_INET || raddr->sa_family !=AF_INET )return -EAFNOSUPPORT ; - qp =find_qp_by_qpn (dev, params->qpn); + qp =erdma_qp_get_by_qpn (dev, params->qpn);if (!qp)return -ENOENT ; -erdma_qp_get (qp); ret =sock_create (AF_INET ,SOCK_STREAM ,IPPROTO_TCP , &s);if (ret <0 )
@@ -1154,10 +1153,9 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)return -ECONNRESET ; } - qp =find_qp_by_qpn (dev, params->qpn); + qp =erdma_qp_get_by_qpn (dev, params->qpn);if (!qp)return -ENOENT ; -erdma_qp_get (qp);down_write (&qp->state_lock);if (qp->attrs.iwarp.state >ERDMA_QPS_IWARP_RTR ) {
drivers/infiniband/hw/erdma/erdma_eq.c +2 -1
@@ -65,7 +65,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)erdma_cq_put (cq); }else { qpn =le32_to_cpu (aeqe->event_data0); - qp =find_qp_by_qpn (dev, qpn); + qp =erdma_qp_get_by_qpn (dev, qpn);if (!qp)continue ;
@@ -75,6 +75,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)if (qp->ibqp.event_handler) qp->ibqp.event_handler (&event, qp->ibqp.qp_context); +erdma_qp_put (qp); } }
drivers/infiniband/hw/erdma/erdma_verbs.c +5 -1
@@ -1321,6 +1321,7 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) udata, struct erdma_ucontext, ibucontext);struct erdma_cmdq_destroy_qp_req req;union erdma_mod_qp_params params; +unsigned long flags;int err;down_write (&qp->state_lock);
@@ -1348,6 +1349,10 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)"failed to destroy QP %u: %d\n" , QP_ID(qp), err); +xa_lock_irqsave (&dev->qp_xa, flags); +__xa_erase (&dev->qp_xa,QP_ID (qp)); +xa_unlock_irqrestore (&dev->qp_xa, flags); +erdma_qp_put (qp);wait_for_completion (&qp->safe_free);
@@ -1361,7 +1366,6 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)if (qp->cep)erdma_cep_put (qp->cep); -xa_erase (&dev->qp_xa,QP_ID (qp));return 0 ; }
drivers/infiniband/hw/erdma/erdma_verbs.h +15 -0
@@ -360,6 +360,21 @@ static inline struct erdma_qp *find_qp_by_qpn(struct erdma_dev *dev, int id)return (struct erdma_qp *)xa_load (&dev->qp_xa, id); } +static inline struct erdma_qp *erdma_qp_get_by_qpn (struct erdma_dev *dev, +int id) +{ +struct erdma_qp *qp; +unsigned long flags; + +xa_lock_irqsave (&dev->qp_xa, flags); + qp =xa_load (&dev->qp_xa, id); +if (qp && !kref_get_unless_zero (&qp->ref)) + qp =NULL ; +xa_unlock_irqrestore (&dev->qp_xa, flags); + +return qp; +} +static inline struct erdma_cq *erdma_cq_get_by_cqn (struct erdma_dev *dev,int id) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 907/1376 RDMA/srp: fix heap information leak on a truncated SRP_CRED_REQ
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 961ac0f0c5e414abdd6b33fae84b311d9fde0bd0 ]
srp_recv_done() passes wc->byte_len to srp_process_rsp(). It passes nothing to srp_process_cred_req() and srp_process_aer_req(), which read fixed-size fields from the receive buffer without checking that those fields were received.
The buffer size is max_ti_iu_len, which comes from the login response and is not validated. A target that advertises 8 and then sends an 8-byte SRP_CRED_REQ makes the initiator read req->tag from beyond the end of the buffer. req->tag is copied into the SRP_CRED_RSP and sent back, so those bytes reach the target. SRP_AER_REQ behaves the same way and also reads req->lun.
The leak is 8 bytes per response. max_ti_iu_len also decides which slab cache the buffer comes from. With 8 the buffer is a kmalloc-8 object and the read is entirely outside it:
BUG: KASAN: slab-out-of-bounds in srp_recv_done+0x172b/0x1aa0 Read of size 8 at addr ffff888104714da8 by task kworker/u8:3/50 which belongs to the cache kmalloc-8 of size 8 The buggy address is located 0 bytes to the right of allocated 8-byte region [ffff888104714da0, ffff888104714da8)
Without KASAN the returned bytes are whatever is next in the slab. One run returned ".strtab".
rsp->data[3] in srp_process_rsp() has the same problem: only resp_data_len is checked before it is read.
Drop a request that is shorter than the structure being parsed, and check byte_len before the tsk_mgmt read.
--- drivers/infiniband/ulp/srp/ib_srp.c | 45 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +30 -15
@@ -1943,7 +1943,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp, ch->req_lim +=be32_to_cpu (rsp->req_lim_delta);if (rsp->tag == ch->tsk_mgmt_tag) { ch->tsk_mgmt_status =-1 ; -if (be32_to_cpu (rsp->resp_data_len) >=4 ) +if (be32_to_cpu (rsp->resp_data_len) >=4 && + byte_len >=sizeof (*rsp) +4 ) ch->tsk_mgmt_status = rsp->data[3 ];complete (&ch->tsk_mgmt_done); }else {
@@ -2043,13 +2044,20 @@ static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta, }static void srp_process_cred_req (struct srp_rdma_ch *ch, -struct srp_cred_req *req) +struct srp_cred_req *req,u32 byte_len) { -struct srp_cred_rsp rsp = { - .opcode =SRP_CRED_RSP , - .tag = req->tag, - }; -s32 delta =be32_to_cpu (req->req_lim_delta); +struct srp_cred_rsp rsp = { .opcode =SRP_CRED_RSP }; +s32 delta; + +if (byte_len <sizeof (*req)) { +shost_printk (KERN_ERR , ch->target->scsi_host,PFX +"dropping truncated SRP_CRED_REQ (%u bytes received, %zu expected)\n" , + byte_len,sizeof (*req)); +return ; + } + + rsp.tag = req->tag; + delta =be32_to_cpu (req->req_lim_delta);if (srp_response_common (ch, delta, &rsp,sizeof (rsp))) shost_printk(KERN_ERR, ch->target->scsi_host, PFX
@@ -2057,14 +2065,21 @@ static void srp_process_cred_req(struct srp_rdma_ch *ch, }static void srp_process_aer_req (struct srp_rdma_ch *ch, -struct srp_aer_req *req) +struct srp_aer_req *req,u32 byte_len) {struct srp_target_port *target = ch->target; -struct srp_aer_rsp rsp = { - .opcode =SRP_AER_RSP , - .tag = req->tag, - }; -s32 delta =be32_to_cpu (req->req_lim_delta); +struct srp_aer_rsp rsp = { .opcode =SRP_AER_RSP }; +s32 delta; + +if (byte_len <sizeof (*req)) { +shost_printk (KERN_ERR , target->scsi_host,PFX +"dropping truncated SRP_AER_REQ (%u bytes received, %zu expected)\n" , + byte_len,sizeof (*req)); +return ; + } + + rsp.tag = req->tag; + delta =be32_to_cpu (req->req_lim_delta);shost_printk (KERN_ERR , target->scsi_host,PFX "ignoring AER for LUN %llu\n" ,scsilun_to_int (&req->lun));
@@ -2106,11 +2121,11 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)break ;case SRP_CRED_REQ : -srp_process_cred_req (ch, iu->buf); +srp_process_cred_req (ch, iu->buf, wc->byte_len);break ;case SRP_AER_REQ : -srp_process_aer_req (ch, iu->buf); +srp_process_aer_req (ch, iu->buf, wc->byte_len);break ;case SRP_T_LOGOUT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 908/1376 ARM: 9481/2: breakpoint: CFI breakpoints only on demand
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit 8ed9bff906cf8036531d1559f10e82733a52b41f ]
This removes the stub hw_breakpoint_cfi_handler() from ARM, making it not steal breakpoint type 0x03 (ARM_ENTRY_CFI_BREAKPOINT) unless CFI is actively used in the kernel.
When not instrumenting with CFI, or when a breakpoint is issued in userspace, we fall through to return 1 from hw_breakpoint_pending() "unhandled fault" so userspace can make use of this breakpoint.
Tested with LKDTM and this command line:
echo CFI_FORWARD_PROTO > /sys/kernel/debug/provoke-crash/DIRECT still works as expected.
--- arch/arm/kernel/hw_breakpoint.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
arch/arm/kernel/hw_breakpoint.c +6 -5
@@ -929,10 +929,6 @@ static void hw_breakpoint_cfi_handler(struct pt_regs *regs) break; } } -#else -static void hw_breakpoint_cfi_handler (struct pt_regs *regs) -{ -}#endif /*
@@ -964,9 +960,14 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,case ARM_ENTRY_SYNC_WATCHPOINT :watchpoint_handler (addr, fsr, regs);break ; +#ifdef CONFIG_CFI case ARM_ENTRY_CFI_BREAKPOINT : -hw_breakpoint_cfi_handler (regs); +if (user_mode (regs)) + ret =1 ;/* Don't handle userspace BKPT */ +else +hw_breakpoint_cfi_handler (regs);break ; +#endif default : ret =1 ;/* Unhandled fault. */ }
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0908/1376] ARM: 9481/2: breakpoint: CFI breakpoints only on demand
Quoted 48 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit
8ed9bff906cf8036531d1559f10e82733a52b41f]This removes the stub
hw_breakpoint_cfi_handler()from ARM, making it not steal breakpoint type0x03(ARM_ENTRY_CFI_BREAKPOINT) unless CFI is actively used in the kernel.When not instrumenting with CFI, or when a breakpoint is issued in userspace, we fall through to return 1 from
hw_breakpoint_pending()"unhandled fault" so userspace can make use of this breakpoint.Tested with LKDTM and this command line:
echoCFI_FORWARD_PROTO>/sys/kernel/debug/provoke-crash/DIRECTstill works as expected.Fixes c3f89986fde7 ("ARM: 9391/2: hw_breakpoint: Handle CFI breakpoints")Reported-by slipher <[email protected]>Suggested-by Mark Rutland <[email protected]>Signed-off-by Linus Walleij <[email protected]>Signed-off-by Russell King <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/arm/kernel/hw_breakpoint.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)arch/arm/kernel/hw_breakpoint.c +0
-4@@ -929,10 +929,6 @@ static void hw_breakpoint_cfi_handler(struct pt_regs *regs) break; } } -#else -static void hw_breakpoint_cfi_handler (struct pt_regs *regs) -{ -}#endif /*
arch/arm/kernel/hw_breakpoint.c static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, · line 968
Quoted 10 lines
arch/arm/kernel/hw_breakpoint.c +5
-1@@ -964,9 +960,14 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,case ARM_ENTRY_SYNC_WATCHPOINT :watchpoint_handler (addr, fsr, regs);break ; +#ifdef CONFIG_CFI case ARM_ENTRY_CFI_BREAKPOINT : -hw_breakpoint_cfi_handler (regs); +if (user_mode (regs)) + ret =1 ;/* Don't handle userspace BKPT */ +else +hw_breakpoint_cfi_handler (regs);
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The new ARM_ENTRY_CFI_BREAKPOINT case is under CONFIG_CFI, but this 6.12 tree defines and uses CONFIG_CFI_CLANG. CONFIG_CFI was introduced by a later upstream rename and is absent here. The handler itself still builds under CONFIG_CFI_CLANG, so a CFI-enabled destination omits the only dispatch case which can call it.
Upstream source code after the later Kconfig rename:
#ifdef CONFIG_CFI
case ARM_ENTRY_CFI_BREAKPOINT:Downstream 6.12.y handler code:
#ifdef CONFIG_CFI_CLANG
static void hw_breakpoint_cfi_handler(struct pt_regs *regs)
Maybe we should change that guard from CONFIG_CFI to CONFIG_CFI_CLANG before retaining the backport. Thoughts?
thanks,
Harshit
Quoted 5 lines
arch/arm/kernel/hw_breakpoint.c +1
-0break ; +#endif default : ret =1 ;/* Unhandled fault. */ }
Greg Kroah-Hartman
maintainerPATCH 909/1376 ARM: 9485/1: mm: acquire mmap write lock around show_pte() for user faults
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xie Yuanbin <[email protected]>
[ Upstream commit 1039bffd6ae9c75b42b7d148d6c1106134107b66 ]
When CONFIG_DEBUG_USER=y, and cmdline "user_debug=31" is set, a user fault may trigger show_pte() without any lock.
If another thread in the same process concurrently calls munmap(), the page table pages may be freed while show_pte() is still traversing them, causing a use-after-free in show_pte().
If CONFIG_ARM_LPAE=y, this may cause a kernel panic if the pages table of PMD are freed when show_pte() is running.
Acquire mmap_write_lock() around show_pte() for user faults to fix the contention.
For user faults, additionally restrict that show_pte() is called only when the addr is a user-space address (addr < TASK_SIZE). This is because the lock of tsk->mm only protects the virtual memory of user address space, furthermore, dumping the page tables of a kernel-space address for user faults is unnecessary and may have security implications.
Keep everything unchanged for kernel faults, because the kernel is already in the "oops" state, acquiring a lock may risk a deadlock.
--- arch/arm/mm/fault.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
arch/arm/mm/fault.c +14 -2
@@ -205,7 +205,11 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,pr_err ("8<--- cut here ---\n" );pr_err ("%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n" , tsk->comm, sig, addr, fsr); -show_pte (KERN_ERR , tsk->mm, addr); +if (likely (addr <TASK_SIZE )) { +mmap_write_lock (tsk->mm); +show_pte (KERN_ERR , tsk->mm, addr); +mmap_write_unlock (tsk->mm); + } show_regs(regs); }#endif
@@ -649,7 +653,15 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)pr_alert ("8<--- cut here ---\n" );pr_alert ("Unhandled fault: %s (0x%03x) at 0x%08lx\n" , inf->name, fsr, addr); -show_pte (KERN_ALERT , current->mm, addr); +if (likely (user_mode (regs))) { +if (addr <TASK_SIZE ) { +mmap_write_lock (current->mm); +show_pte (KERN_ALERT , current->mm, addr); +mmap_write_unlock (current->mm); + } + }else { +show_pte (KERN_ALERT , current->mm, addr); + }arm_notify_die ("" , regs, inf->sig, inf->code, (void __user *)addr, fsr,0 );
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0909/1376] ARM: 9485/1: mm: acquire mmap write lock around show_pte() for user faults
Quoted 48 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xie Yuanbin <[email protected]>
[ Upstream commit
1039bffd6ae9c75b42b7d148d6c1106134107b66]When
CONFIG_DEBUG_USER=y, and cmdline "user_debug=31" is set, a user fault may triggershow_pte()without any lock.
If another thread in the same process concurrently callsmunmap(), the page table pages may be freed whileshow_pte()is still traversing them, causing a use-after-free inshow_pte().If
CONFIG_ARM_LPAE=y, this may cause a kernel panic if the pages table of PMD are freed whenshow_pte()is running.Acquire
mmap_write_lock()aroundshow_pte()for user faults to fix the contention.For user faults, additionally restrict that
show_pte()is called only when the addr is a user-space address (addr <TASK_SIZE). This is because the lock oftsk->mmonly protects the virtual memory of user address space, furthermore, dumping the page tables of a kernel-space address for user faults is unnecessary and may have security implications.Keep everything unchanged for kernel faults, because the kernel is already in the "oops" state, acquiring a lock may risk a deadlock.
Co-developed-by Qi Xi <[email protected]>Fixes 6d021b724481 ("ARM: dump pgd, pmd and pte states on unhandled data abort faults")Reviewed-by Linus Walleij <[email protected]>Signed-off-by Qi Xi <[email protected]>Signed-off-by Xie Yuanbin <[email protected]>Signed-off-by Russell King <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/arm/mm/fault.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)arch/arm/mm/fault.c +0
-0
arch/arm/mm/fault.c __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig, · line 211
Quoted 8 lines
arch/arm/mm/fault.c +4
-1@@ -205,7 +205,11 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,pr_err ("8<--- cut here ---\n" );pr_err ("%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n" , tsk->comm, sig, addr, fsr); -show_pte (KERN_ERR , tsk->mm, addr); +if (likely (addr <TASK_SIZE )) { +mmap_write_lock (tsk->mm); +show_pte (KERN_ERR , tsk->mm, addr); +mmap_write_unlock (tsk->mm);
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream prerequisite code:
local_irq_enable();
mmap_write_lock(tsk->mm);Downstream 6.12.y code:
if (likely(addr < TASK_SIZE)) {
mmap_write_lock(tsk->mm);
show_pte(KERN_ERR, tsk->mm, addr);
}The two new mmap_write_lock() calls are sleepable. Upstream first enabled interrupts in both affected user-fault paths, but 6.12 lacks those changes. The backport can therefore call down_write() with IRQs disabled, producing atomic-sleep diagnostics or a stall if the mmap lock is contended.
The missing commits are 59e4f3b45b96a24fc9b7a89e5f8a2168b30f95af and e79ca91165d4fd18549c536abdb86101e889052f. I suggest applying adapted equivalents of both before retaining this patch. Thoughts?
thanks,
Harshit
Quoted 21 lines
arch/arm/mm/fault.c +10
-1+ }show_regs (regs); }#endif @@ -649,7 +653,15 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)pr_alert ("8<--- cut here ---\n" );pr_alert ("Unhandled fault: %s (0x%03x) at 0x%08lx\n" , inf->name, fsr, addr); -show_pte (KERN_ALERT , current->mm, addr); +if (likely (user_mode (regs))) { +if (addr <TASK_SIZE ) { +mmap_write_lock (current->mm); +show_pte (KERN_ALERT , current->mm, addr); +mmap_write_unlock (current->mm); + } + }else { +show_pte (KERN_ALERT , current->mm, addr); + }arm_notify_die ("" , regs, inf->sig, inf->code, (void __user *)addr, fsr,0 );
Sasha Levin
maintainerRe: [PATCH 6.12 0909/1376] ARM: 9485/1: mm: acquire mmap write lock around show_pte() for user faults
Quoted 3 lines
The missing commits are
59e4f3b45b96a24fc9b7a89e5f8a2168b30f95afande79ca91165d4fd18549c536abdb86101e889052f. I suggest applying adapted equivalents of both before retaining this patch. Thoughts?
e79ca91165d4 ("ARM: 9484/1: enable interrupts when unhandled user faults are triggered") is already queued for 5.15 and 5.10.
59e4f3b45b96 ("ARM: ensure interrupts are enabled in __do_user_fault()") cannot go in on its own on those trees. Without 7733bc7d299d ("ARM: fix hash_name() fault") and fd2dee1c6e22 ("ARM: fix branch predictor hardening") it leaves harden_branch_predictor() running preemptible, which is a Spectre v2 regression.
Xie Yuanbin has posted a 5.15 and 5.10 series that carries both prerequisites, so I would rather take that once he resends it.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 910/1376 ocfs2: synchronize heartbeat callbacks with o2net teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 3e326f3bf16506873777444608e8b715aab74a7a ]
Patch series "ocfs2: harden heartbeat teardown races".
This series fixes two OCFS2 heartbeat/o2net teardown races found by KASAN.
This patch (of 2):
Heartbeat callbacks stay registered while configfs local-node teardown enters o2net_stop_listening(). A node-down event can still run through o2net_disconnect_node() and o2net_set_nn_state() while teardown is destroying o2net_wq, so the later queue/flush operations can hit a dead workqueue. KASAN has caught this as a slab-use-after-free in __queue_work() with the call chain:
KASAN slab-use-after-free in __queue_work+0x56/0xa90
Read of size 4 Call trace: dump_stack_lvl+0x66/0xa0 print_report+0xce/0x630 __queue_work+0x56/0xa90 srso_alias_return_thunk+0x5/0xfbef5 __virt_addr_valid+0x19f/0x330 kasan_report+0xe0/0x110 __queue_delayed_work+0x58/0x1e0 queue_delayed_work_on+0xb4/0xc0 o2net_set_nn_state+0x467/0x840 o2net_disconnect_node+0x7b/0xe0 o2net_hb_node_down_cb+0x54/0x60 o2hb_run_event_list+0x236/0x2d0 o2hb_check_slot+0xad4/0xbc0 lock_release+0xc8/0x290 o2hb_check_slot+0x9ea/0xbc0 trace_hardirqs_on+0x18/0x130 o2hb_do_disk_heartbeat+0x646/0xb30 (fs/ocfs2/cluster/heartbeat.c:1079) __lock_acquire+0x466/0x2260 lockdep_hardirqs_on_prepare+0xea/0x1a0 ktime_get_with_offset+0xe9/0x230 o2hb_thread+0x14e/0x770 kthread+0x1ad/0x1f0 ret_from_fork+0x3c9/0x540 __switch_to+0x2e9/0x730 ret_from_fork_asm+0x1a/0x30 Allocated by task stack: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_noprof+0x292/0x760 __alloc_workqueue+0x736/0xc60 alloc_workqueue_noprof+0xb1/0x110 o2net_start_listening+0xe5/0x430 o2nm_node_local_store+0x184/0x310 configfs_write_iter+0x18a/0x210 vfs_write+0x469/0x810 ksys_write+0xd2/0x170 do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task stack: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 kfree+0x313/0x590 rcu_core+0x4f4/0x1320 handle_softirqs+0x156/0x660
queue_delayed_work_ono2net_set_nn_stateo2net_disconnect_nodeo2net_hb_node_down_cbo2hb_run_event_list
Keep heartbeat callbacks registered so quorum state still tracks node state, but stop them from driving o2net reconnect/disconnect work once local teardown starts. Mark the transport offline before destroying o2net_wq, wait for any in-flight heartbeat callback to finish, and delay bring-up replay until the new local node is published through o2nm_this_node().
The replay also has to stay serialized with heartbeat callback delivery. Otherwise a live-node snapshot can be copied, a real hb_down callback can install -ENOTCONN for a peer, and the stale replay can call o2net_hb_node_up() for that same peer and queue reconnect work even though heartbeat is already down.
The buggy scenario involves two paths, with each column showing the order within that path:
local-node teardown: heartbeat node-down callback:
1. configfs local-off enters 1. o2hb_run_event_list() invokes
o2net_stop_listening(). o2net_hb_node_down_cb().
2. teardown heads for 2. the callback reaches
destroy_workqueue(o2net_wq). o2net_disconnect_node() and
o2net_set_nn_state().
3. teardown destroys and NULLs 3. the callback flushes or queues
o2net_wq. work through o2net_wq.
--- fs/ocfs2/cluster/heartbeat.c | 43 ++++++++++++++---- fs/ocfs2/cluster/heartbeat.h | 5 ++ fs/ocfs2/cluster/nodemanager.c | 4 ++ fs/ocfs2/cluster/tcp.c | 83 +++++++++++++++++++++++++++------- fs/ocfs2/cluster/tcp.h | 1 + 5 files changed, 109 insertions(+), 27 deletions(-)
fs/ocfs2/cluster/heartbeat.c +33 -10
@@ -1476,13 +1476,38 @@ void o2hb_init(void)o2hb_debug_init (); } -/* if we're already in a callback then we're already serialized by the sem */ -static void o2hb_fill_node_map_from_callback (unsigned long *map, -unsigned int bits) +static void __o2hb_fill_node_map (unsigned long *map,unsigned int bits) {bitmap_copy (map, o2hb_live_node_bitmap, bits); } +void o2hb_callback_read_lock (void ) +{ +down_read (&o2hb_callback_sem); +} + +void o2hb_callback_read_unlock (void ) +{ +up_read (&o2hb_callback_sem); +} + +void o2hb_synchronize_callbacks (void ) +{ +down_write (&o2hb_callback_sem); +up_write (&o2hb_callback_sem); +} + +/* +* Callers must already hold o2hb_callback_sem for read or write so the copy +* stays serialized with callback delivery. +*/ +void o2hb_fill_node_map_locked (unsigned long *map,unsigned int bits) +{ +spin_lock (&o2hb_live_lock); +__o2hb_fill_node_map (map, bits); +spin_unlock (&o2hb_live_lock); +} +/* * get a map of all nodes that are heartbeating in any regions */
@@ -1490,11 +1515,9 @@ void o2hb_fill_node_map(unsigned long *map, unsigned int bits) {/* callers want to serialize this map and callbacks so that they * can trust that they don't miss nodes coming to the party */ -down_read (&o2hb_callback_sem); -spin_lock (&o2hb_live_lock); -o2hb_fill_node_map_from_callback (map, bits); -spin_unlock (&o2hb_live_lock); -up_read (&o2hb_callback_sem); +o2hb_callback_read_lock (); +o2hb_fill_node_map_locked (map, bits); +o2hb_callback_read_unlock (); }EXPORT_SYMBOL_GPL (o2hb_fill_node_map);
@@ -2566,7 +2589,7 @@ int o2hb_check_node_heartbeating_no_sem(u8 node_num)unsigned long testing_map[BITS_TO_LONGS (O2NM_MAX_NODES )];spin_lock (&o2hb_live_lock); -o2hb_fill_node_map_from_callback (testing_map,O2NM_MAX_NODES ); +__o2hb_fill_node_map (testing_map,O2NM_MAX_NODES );spin_unlock (&o2hb_live_lock);if (!test_bit (node_num, testing_map)) { mlog(ML_HEARTBEAT,
@@ -2583,7 +2606,7 @@ int o2hb_check_node_heartbeating_from_callback(u8 node_num) {unsigned long testing_map[BITS_TO_LONGS (O2NM_MAX_NODES )]; -o2hb_fill_node_map_from_callback (testing_map,O2NM_MAX_NODES ); +o2hb_fill_node_map_locked (testing_map,O2NM_MAX_NODES );if (!test_bit (node_num, testing_map)) { mlog(ML_HEARTBEAT, "node (%u) does not have heartbeating enabled.\n",
fs/ocfs2/cluster/heartbeat.h +5 -0
@@ -58,6 +58,11 @@ int o2hb_register_callback(const char *region_uuid, struct o2hb_callback_func *hc);void o2hb_unregister_callback (const char *region_uuid,struct o2hb_callback_func *hc); +void o2hb_callback_read_lock (void ); +void o2hb_callback_read_unlock (void ); +void o2hb_synchronize_callbacks (void ); +void o2hb_fill_node_map_locked (unsigned long *map, +unsigned int bits);void o2hb_fill_node_map (unsigned long *map,unsigned int bits);void o2hb_exit (void );
fs/ocfs2/cluster/nodemanager.c +4 -0
@@ -325,6 +325,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,struct o2nm_node *node =to_o2nm_node (item);struct o2nm_cluster *cluster;unsigned long tmp; +bool starting = false;char *p = (char *)page;ssize_t ret;
@@ -361,6 +362,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, ret =o2net_start_listening (node);if (ret) goto out; + starting = true; } if (!tmp && cluster->cl_has_local &&
@@ -374,6 +376,8 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,if (node->nd_local) { cluster->cl_has_local = tmp; cluster->cl_local_node = node->nd_num; +if (starting) +o2net_complete_start_listening (node); } ret = count;
fs/ocfs2/cluster/tcp.c +66 -17
137 lines not on this page · raw message
fs/ocfs2/cluster/tcp.h +1 -0
@@ -96,6 +96,7 @@ struct o2nm_node;int o2net_register_hb_callbacks (void );void o2net_unregister_hb_callbacks (void );int o2net_start_listening (struct o2nm_node *node); +void o2net_complete_start_listening (struct o2nm_node *node);void o2net_stop_listening (struct o2nm_node *node);void o2net_disconnect_node (struct o2nm_node *node);int o2net_num_connected_peers (void );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 911/1376 clk: rockchip: rk3576: fix source muxes for SPI0..SPI4
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Charkov <[email protected]>
[ Upstream commit 586ff159ec02533c17dd928641529cb0b52e9c62 ]
The TRM defines available source muxes for SPI0..SPI4 as
- b00: clk_gpll_div6_src
- b01: clk_gpll_div8_src
- b10: clk_cpll_div10_src
- b11: clk_xin_osc0_func
Which doesn't match what the current clock driver implements, making it impossible to derive some SPI clock rates such as 37.125 MHz (which requires clk_gpll_div8_src as the source mux).
Add a correct mux definition per TRM and point SPI0..SPI4 clocks at it.
--- drivers/clk/rockchip/clk-rk3576.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/clk/rockchip/clk-rk3576.c +6 -5
@@ -313,6 +313,7 @@ PNAME(mux_100m_24m_lclk0_p) = { "clk_cpll_div10", "xin24m", "lclk_asrc_src_0" }PNAME (mux_100m_24m_lclk1_p) = {"clk_cpll_div10" ,"xin24m" ,"lclk_asrc_src_1" };PNAME (mux_150m_100m_50m_24m_p) = {"clk_gpll_div8" ,"clk_cpll_div10" ,"clk_cpll_div20" ,"xin24m" };PNAME (mux_200m_100m_50m_24m_p) = {"clk_gpll_div6" ,"clk_cpll_div10" ,"clk_cpll_div20" ,"xin24m" }; +PNAME (mux_200m_150m_100m_24m_p) = {"clk_gpll_div6" ,"clk_gpll_div8" ,"clk_cpll_div10" ,"xin24m" };PNAME (mux_400m_200m_100m_24m_p) = {"clk_gpll_div3" ,"clk_gpll_div6" ,"clk_cpll_div10" ,"xin24m" };PNAME (mux_500m_250m_100m_24m_p) = {"clk_cpll_div2" ,"clk_cpll_div4" ,"clk_cpll_div10" ,"xin24m" };PNAME (mux_600m_400m_300m_24m_p) = {"clk_gpll_div2" ,"clk_gpll_div3" ,"clk_gpll_div4" ,"xin24m" };
@@ -702,19 +703,19 @@ static struct rockchip_clk_branch rk3576_clk_branches[] __initdata = { RK3576_CLKGATE_CON(16), 0, GFLAGS),GATE (PCLK_SPI4 ,"pclk_spi4" ,"pclk_bus_root" ,0 ,RK3576_CLKGATE_CON (16 ),1 ,GFLAGS ), -COMPOSITE_NODIV (CLK_SPI0 ,"clk_spi0" , mux_200m_100m_50m_24m_p,0 , +COMPOSITE_NODIV (CLK_SPI0 ,"clk_spi0" , mux_200m_150m_100m_24m_p,0 ,RK3576_CLKSEL_CON (70 ),13 ,2 ,MFLAGS ,RK3576_CLKGATE_CON (16 ),2 ,GFLAGS ), -COMPOSITE_NODIV (CLK_SPI1 ,"clk_spi1" , mux_200m_100m_50m_24m_p,0 , +COMPOSITE_NODIV (CLK_SPI1 ,"clk_spi1" , mux_200m_150m_100m_24m_p,0 ,RK3576_CLKSEL_CON (71 ),0 ,2 ,MFLAGS ,RK3576_CLKGATE_CON (16 ),3 ,GFLAGS ), -COMPOSITE_NODIV (CLK_SPI2 ,"clk_spi2" , mux_200m_100m_50m_24m_p,0 , +COMPOSITE_NODIV (CLK_SPI2 ,"clk_spi2" , mux_200m_150m_100m_24m_p,0 ,RK3576_CLKSEL_CON (71 ),2 ,2 ,MFLAGS ,RK3576_CLKGATE_CON (16 ),4 ,GFLAGS ), -COMPOSITE_NODIV (CLK_SPI3 ,"clk_spi3" , mux_200m_100m_50m_24m_p,0 , +COMPOSITE_NODIV (CLK_SPI3 ,"clk_spi3" , mux_200m_150m_100m_24m_p,0 ,RK3576_CLKSEL_CON (71 ),4 ,2 ,MFLAGS ,RK3576_CLKGATE_CON (16 ),5 ,GFLAGS ), -COMPOSITE_NODIV (CLK_SPI4 ,"clk_spi4" , mux_200m_100m_50m_24m_p,0 , +COMPOSITE_NODIV (CLK_SPI4 ,"clk_spi4" , mux_200m_150m_100m_24m_p,0 ,RK3576_CLKSEL_CON (71 ),6 ,2 ,MFLAGS ,RK3576_CLKGATE_CON (16 ),6 ,GFLAGS ), GATE(PCLK_WDT0, "pclk_wdt0", "pclk_bus_root", 0,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 912/1376 drm/sun4i: vi scaler: Fix coefficient selection
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 5c31990b21f0b535732deb2b658b78b07464f56c ]
Currently, vertical coefficients are selected based on horizontal scaling, which is wrong. Additionally, chroma coefficients should be selected based on format subsampling.
Fix all that.
--- drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c +12 -6
@@ -891,20 +891,26 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base, lan3coefftab32_left[offset + i]);regmap_write (map,SUN8I_SCALER_VSU_YHCOEFF1 (base, i), lan3coefftab32_right[offset + i]); + } + offset =sun8i_vi_scaler_coef_index (vstep) * +SUN8I_VI_SCALER_COEFF_COUNT ; +for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++) +regmap_write (map,SUN8I_SCALER_VSU_YVCOEFF (base, i), + lan2coefftab32[offset + i]); + + offset =sun8i_vi_scaler_coef_index (hstep / format->hsub) * +SUN8I_VI_SCALER_COEFF_COUNT ; +for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++) {regmap_write (map,SUN8I_SCALER_VSU_CHCOEFF0 (base, i), ch_left[offset + i]);regmap_write (map,SUN8I_SCALER_VSU_CHCOEFF1 (base, i), ch_right[offset + i]); } - - offset =sun8i_vi_scaler_coef_index (hstep) * + offset =sun8i_vi_scaler_coef_index (vstep / format->vsub) *SUN8I_VI_SCALER_COEFF_COUNT ; -for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++) { -regmap_write (map,SUN8I_SCALER_VSU_YVCOEFF (base, i), - lan2coefftab32[offset + i]); +for (i =0 ; i <SUN8I_VI_SCALER_COEFF_COUNT ; i++)regmap_write (map,SUN8I_SCALER_VSU_CVCOEFF (base, i), cy[offset + i]); - } }void sun8i_vi_scaler_enable (struct sun8i_mixer *mixer,int layer,bool enable)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 913/1376 of: property: add of_graph_get_next_port()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuninori Morimoto <[email protected]>
[ Upstream commit 02ac5f9d6caec96071103f7c62b5117526e47b64 ]
We have endpoint base functions
- of_graph_get_next_endpoint()
- of_graph_get_endpoint_count()
- for_each_endpoint_of_node()
Here, for_each_endpoint_of_node() loop finds each endpoints
ports {
port@0 {
(1) endpoint {...};
};
port@1 {
(2) endpoint {...};
};
...
};In above case, it finds endpoint as (1) -> (2) -> ...
Basically, user/driver knows which port is used for what, but not in all cases. For example on flexible/generic driver case, how many ports are used is not fixed.
For example Sound Generic Card driver which is very flexible/generic and used from many venders can't know how many ports are used, and used for what, because it depends on each vender SoC and/or its used board.
And more, the port can have multi endpoints. For example Generic Sound Card case, it supports many type of connection between CPU / Codec, and some of them uses multi endpoint in one port. see below.
ports {
(A) port@0 {
(1) endpoint@0 {...};
(2) endpoint@1 {...};
};
(B) port@1 {
(3) endpoint {...};
};
...
};Generic Sound Card want to handle each connection via "port" base instead of "endpoint" base. But, it is very difficult to handle each "port" via existing for_each_endpoint_of_node(). Because getting each "port" via of_get_parent() from each "endpoint" doesn't work. For example in above case, both (1) (2) endpoint has same "port" (= A).
Add "port" base functions.
Stable-dep-of: 62bac3202042 ("drm/sun4i: tcon-top: Keep mixer routes distinct")
--- drivers/of/property.c | 54 ++++++++++++++++++++++++++++++++++++++++ include/linux/of_graph.h | 28 +++++++++++++++++++++ 2 files changed, 82 insertions(+)
drivers/of/property.c +54 -0
@@ -630,6 +630,43 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) }EXPORT_SYMBOL (of_graph_get_port_by_id); +/** +* of_graph_get_next_port() - get next port node. +* @parent: pointer to the parent device node, or parent ports node +* @prev: previous port node, or NULL to get first +* +* Parent device node can be used as @parent whether device node has ports node +* or not. It will work same as ports@0 node. +* +* Return: A 'port' node pointer with refcount incremented. Refcount +* of the passed @prev node is decremented. +*/ +struct device_node *of_graph_get_next_port (const struct device_node *parent, +struct device_node *prev) +{ +if (!parent) +return NULL ; + +if (!prev) { + struct device_node *node __free(device_node) = +of_get_child_by_name (parent,"ports" ); + +if (node) + parent = node; + +return of_get_child_by_name (parent,"port" ); + } + +do { + prev =of_get_next_child (parent, prev); +if (!prev) +break ; + }while (!of_node_name_eq (prev,"port" )); + +return prev; +} +EXPORT_SYMBOL (of_graph_get_next_port); +/** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node
@@ -823,6 +860,23 @@ unsigned int of_graph_get_endpoint_count(const struct device_node *np) }EXPORT_SYMBOL (of_graph_get_endpoint_count); +/** +* of_graph_get_port_count() - get the number of port in a device or ports node +* @np: pointer to the device or ports node +* +* Return: count of port of this device or ports node +*/ +unsigned int of_graph_get_port_count (struct device_node *np) +{ +unsigned int num =0 ; + +for_each_of_graph_port (np, port) + num++; + +return num; +} +EXPORT_SYMBOL (of_graph_get_port_count); +/** * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint * @node: pointer to parent device_node containing graph port/endpoint
include/linux/of_graph.h +28 -0
@@ -11,6 +11,7 @@#ifndef __LINUX_OF_GRAPH_H#define __LINUX_OF_GRAPH_H +#include <linux/cleanup.h> #include <linux/types.h> #include <linux/errno.h>
@@ -37,14 +38,29 @@ struct of_endpoint {for (child =of_graph_get_next_endpoint (parent,NULL ); child !=NULL ; \ child =of_graph_get_next_endpoint (parent, child)) +/** +* for_each_of_graph_port - iterate over every port in a device or ports node +* @parent: parent device or ports node containing port +* @child: loop variable pointing to the current port node +* +* When breaking out of the loop, and continue to use the @child, you need to +* use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it. + */ +#define for_each_of_graph_port (parent, child) \ + for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\ + child != NULL; child = of_graph_get_next_port(parent, child)) +#ifdef CONFIG_OF bool of_graph_is_present (const struct device_node *node);int of_graph_parse_endpoint (const struct device_node *node,struct of_endpoint *endpoint);unsigned int of_graph_get_endpoint_count (const struct device_node *np); +unsigned int of_graph_get_port_count (struct device_node *np);struct device_node *of_graph_get_port_by_id (struct device_node *node,u32 id);struct device_node *of_graph_get_next_endpoint (const struct device_node *parent,struct device_node *previous); +struct device_node *of_graph_get_next_port (const struct device_node *parent, +struct device_node *port);struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg); struct device_node *of_graph_get_remote_endpoint(
@@ -73,6 +89,11 @@ static inline unsigned int of_graph_get_endpoint_count(const struct device_nodereturn 0 ; } +static inline unsigned int of_graph_get_port_count (struct device_node *np) +{ +return 0 ; +} +static inline struct device_node *of_graph_get_port_by_id (struct device_node *node,u32 id) {
@@ -86,6 +107,13 @@ static inline struct device_node *of_graph_get_next_endpoint(return NULL ; } +static inline struct device_node *of_graph_get_next_port ( +const struct device_node *parent, +struct device_node *previous) +{ +return NULL ; +} +static inline struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 914/1376 of: property: add of_graph_get_next_port_endpoint()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuninori Morimoto <[email protected]>
[ Upstream commit 58fe47d6ac7413172e1fa88324fb1b4c0eb2c0a2 ]
We already have of_graph_get_next_endpoint(), but it is not intuitive to use in some case.
(X) node {
(Y) ports {
(P0) port@0 { endpoint { remote-endpoint = ...; };};
(P10) port@1 { endpoint { remote-endpoint = ...; };
(P11) endpoint { remote-endpoint = ...; };};
(P2) port@2 { endpoint { remote-endpoint = ...; };};
};
};For example, if I want to handle port@1's 2 endpoints (= P10, P11), I want to use like below
P10 = of_graph_get_next_endpoint(port1, NULL); P11 = of_graph_get_next_endpoint(port1, P10);
But 1st one will be error, because of_graph_get_next_endpoint() requested 1st parameter is "node" (X) or "ports" (Y), not but "port". Below works well, but it will get P0
P0 = of_graph_get_next_endpoint(node, NULL); P0 = of_graph_get_next_endpoint(ports, NULL);
In other words, we can't handle P10/P11 directly via of_graph_get_next_endpoint().
There is another non intuitive behavior on of_graph_get_next_endpoint(). In case of if I could get P10 pointer for some way, and if I want to handle port@1 things by loop, I would like use it like below
/*
* "ep" is now P10, and handle port1 things here,
* but we don't know how many endpoints port1 have.
*
* Because "ep" is non NULL now, we can use port1
* as of_graph_get_next_endpoint(port1, xxx)
*/
do {
/* do something for port1 specific things here */
} while (ep = of_graph_get_next_endpoint(port1, ep))But it also not worked as I expected.
I expect it will be P10 -> P11 -> NULL,
but it will be P10 -> P11 -> P2, becauseof_graph_get_next_endpoint() will fetch "endpoint" beyond the "port". It is not useful for generic driver.
To handle endpoint more intuitive, create of_graph_get_next_port_endpoint()
of_graph_get_next_port_endpoint(port1, NULL); // P10 of_graph_get_next_port_endpoint(port1, P10); // P11 of_graph_get_next_port_endpoint(port1, P11); // NULL
Stable-dep-of: 62bac3202042 ("drm/sun4i: tcon-top: Keep mixer routes distinct")
--- drivers/of/property.c | 27 +++++++++++++++++++++++++++ include/linux/of_graph.h | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+)
drivers/of/property.c +27 -0
@@ -667,6 +667,33 @@ struct device_node *of_graph_get_next_port(const struct device_node *parent, }EXPORT_SYMBOL (of_graph_get_next_port); +/** +* of_graph_get_next_port_endpoint() - get next endpoint node in port. +* If it reached to end of the port, it will return NULL. +* @port: pointer to the target port node +* @prev: previous endpoint node, or NULL to get first +* +* Return: An 'endpoint' node pointer with refcount incremented. Refcount +* of the passed @prev node is decremented. +*/ +struct device_node *of_graph_get_next_port_endpoint (const struct device_node *port, +struct device_node *prev) +{ +while (1 ) { + prev =of_get_next_child (port, prev); +if (!prev) +break ; +if (WARN (!of_node_name_eq (prev,"endpoint" ), +"non endpoint node is used (%pOF)" , prev)) +continue ; + +break ; + } + +return prev; +} +EXPORT_SYMBOL (of_graph_get_next_port_endpoint); +/** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node
include/linux/of_graph.h +21 -0
@@ -50,6 +50,18 @@ struct of_endpoint { for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\ child !=NULL ; child =of_graph_get_next_port (parent, child)) +/** +* for_each_of_graph_port_endpoint - iterate over every endpoint in a port node +* @parent: parent port node +* @child: loop variable pointing to the current endpoint node +* +* When breaking out of the loop, and continue to use the @child, you need to +* use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it. + */ +#define for_each_of_graph_port_endpoint (parent, child) \ + for (struct device_node *child __free(device_node) = of_graph_get_next_port_endpoint(parent, NULL);\ + child != NULL; child = of_graph_get_next_port_endpoint(parent, child)) +#ifdef CONFIG_OF bool of_graph_is_present (const struct device_node *node); int of_graph_parse_endpoint(const struct device_node *node,
@@ -61,6 +73,8 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous);struct device_node *of_graph_get_next_port (const struct device_node *parent,struct device_node *port); +struct device_node *of_graph_get_next_port_endpoint (const struct device_node *port, +struct device_node *prev);struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg); struct device_node *of_graph_get_remote_endpoint(
@@ -114,6 +128,13 @@ static inline struct device_node *of_graph_get_next_port(return NULL ; } +static inline struct device_node *of_graph_get_next_port_endpoint ( +const struct device_node *parent, +struct device_node *previous) +{ +return NULL ; +} +static inline struct device_node *of_graph_get_endpoint_by_regs (const struct device_node *parent,int port_reg,int reg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 915/1376 drm/sun4i: tcon: Set output mux for DSI and LVDS
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 9c90199b39637ad94253c4fd8e7b1333ca1d3e0d ]
DSI and LVDS skip output mux setup, so TCON TOP cannot route the selected mixer. Configure them like other channel 0 outputs.
In practice this matters for D1, where channel 0 TCONs are fed through TCON TOP. The remaining set_mux implementations only handle TMDS and return an error for other encoder types, as before.
--- drivers/gpu/drm/sun4i/sun4i_tcon.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/sun4i/sun4i_tcon.c +2 -0
@@ -717,9 +717,11 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,case DRM_MODE_ENCODER_DSI :/* DSI is tied to special case of CPU interface */ sun4i_tcon0_mode_set_cpu (tcon, encoder, mode); +sun4i_tcon_set_mux (tcon,0 , encoder);break ;case DRM_MODE_ENCODER_LVDS :sun4i_tcon0_mode_set_lvds (tcon, encoder, mode); +sun4i_tcon_set_mux (tcon,0 , encoder);break ;case DRM_MODE_ENCODER_NONE :sun4i_tcon0_mode_set_rgb (tcon, encoder, mode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 916/1376 drm/sun4i: tcon: Drop TCON TOP device reference
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 8208832a38ff3d2560eb8a77a9d7a2f17d8ebcdc ]
of_find_device_by_node() takes a device reference. Drop it after mux configuration succeeds.
--- drivers/gpu/drm/sun4i/sun4i_tcon.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
drivers/gpu/drm/sun4i/sun4i_tcon.c +9 -10
@@ -1409,7 +1409,7 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon, {struct device_node *port, *remote;struct platform_device *pdev; -int id, ret; +int id, ret =0 ;/* find TCON TOP platform device and TCON id */
@@ -1432,21 +1432,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,if (IS_ENABLED (CONFIG_DRM_SUN8I_TCON_TOP ) && encoder->encoder_type ==DRM_MODE_ENCODER_TMDS ) { ret =sun8i_tcon_top_set_hdmi_src (&pdev->dev, id); -if (ret) { -put_device (&pdev->dev); -return ret; - } +if (ret) + goto out_put_device; }if (IS_ENABLED (CONFIG_DRM_SUN8I_TCON_TOP )) { ret =sun8i_tcon_top_de_config (&pdev->dev, tcon->id, id); -if (ret) { -put_device (&pdev->dev); -return ret; - } +if (ret) + goto out_put_device; } -return 0 ; +out_put_device: +put_device (&pdev->dev); + +return ret; }static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 917/1376 drm/sun4i: hdmi: Dont leak sync polarity bits into packet control
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit f5c3b1b0d228624786d22973a20c908c84e1a576 ]
sun4i_hdmi_enable() keeps using the same variable after it programmed the video timing polarity register with it. The leftover TX_CLK, HSYNC and VSYNC bits are then ORed into the packet control register, where each nibble selects the packet type sent in one slot.
As a result, slot 0 selects packet type 3 instead of the AVI infoframe whenever the mode has positive HSYNC polarity, and the TX_CLK bits set nibbles which the driver never programs.
Assign the packet types instead of ORing them into the stale value.
--- drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +1 -1
@@ -146,7 +146,7 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,drm_atomic_helper_connector_hdmi_update_infoframes (connector, state); - val |=SUN4I_HDMI_PKT_CTRL_TYPE (0 ,SUN4I_HDMI_PKT_AVI ); + val =SUN4I_HDMI_PKT_CTRL_TYPE (0 ,SUN4I_HDMI_PKT_AVI ); val |=SUN4I_HDMI_PKT_CTRL_TYPE (1 ,SUN4I_HDMI_PKT_END );writel (val, hdmi->base +SUN4I_HDMI_PKT_CTRL_REG (0 ));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 918/1376 drm/sun4i: crtc: Propagate layer initialization error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 7061ff05ed4a3cf16e83f7e3ad09cbd212508a32 ]
sun4i_crtc_init() returns plain NULL when layer initialization fails, while all its other error paths return an error pointer. The only caller, sun4i_tcon_bind(), checks the result with IS_ERR() and happily continues with tcon->crtc set to NULL. sun4i_rgb_init() and sun4i_lvds_init() then dereference it in drm_crtc_mask(), which oopses.
Return the error pointer instead.
--- drivers/gpu/drm/sun4i/sun4i_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun4i_crtc.c +1 -1
@@ -208,7 +208,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, planes =sunxi_engine_layers_init (drm, engine);if (IS_ERR (planes)) {dev_err (drm->dev,"Couldn't create the planes\n" ); -return NULL ; +return ERR_CAST (planes); }/* find primary and cursor planes for drm_crtc_init_with_planes */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 919/1376 drm/sun4i: tcon: Drop remote endpoint reference
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 3f77e4072630e2301efdbe521e7fca10311043ec ]
sun4i_tcon_of_get_id_from_port() never drops the reference taken by of_graph_get_remote_endpoint(). The function is not only called during bind, but also on every mode set through sun8i_r40_tcon_tv_set_mux(), so the leak accumulates.
--- drivers/gpu/drm/sun4i/sun4i_tcon.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/sun4i/sun4i_tcon.c +1 -0
@@ -972,6 +972,7 @@ static int sun4i_tcon_of_get_id_from_port(struct device_node *port)continue ; ret =of_property_read_u32 (remote,"reg" , ®); +of_node_put (remote);if (ret)continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 920/1376 drm/sun4i: dw-hdmi: Drop TCON TOP port reference
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit d2a242e5688a17b79c89cd966cd31820c5096d80 ]
When the HDMI controller is fed by TCON TOP, the port node used to enumerate the possible CRTCs is never released.
--- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +2 -0
@@ -83,6 +83,8 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm,of_node_put (remote_port); } } + +of_node_put (port); }else { crtcs =drm_of_find_possible_crtcs (drm, node); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 921/1376 drm/sun4i: hdmi-phy: Fix H6 8-bit MPLL config at 594 MHz
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jernej Skrabec <[email protected]>
[ Upstream commit 0ba6deddaae74f0539c0303bfb5f860adbe1a68b ]
The 8-bit entry of the last MPLL row (594 MHz) doesn't lock reliably on H6. 4K@60 RGB/YUV444, which is the mode that reaches this entry, doesn't come up.
Align the value with the vendor driver. Other entries are left alone, they are used by lower pixel clocks which work fine.
Tested with 4K@60 on a LG TV.
--- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +1 -1
@@ -91,7 +91,7 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = { }, }, { 594000000, { - { 0x1a40, 0x0003 }, + { 0x1a7c, 0x0003 }, { 0x3b4c, 0x0003 }, { 0x5a64, 0x0003 }, },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 922/1376 cpufreq: imx6q: fix devres accumulation across driver rebind
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 22c23c72c3b21fa3ec3db5070dfc0582794e0ef9 ]
imx6_soc_volt is allocated with devm_kcalloc(cpu_dev, ...), where cpu_dev is the CPU device from get_cpu_device(0). That device is never unbound, so its devres list is never released, and imx6q_cpufreq_remove() does not free the array either. Every probe therefore adds an allocation that stays for the lifetime of the system.
Allocate against the platform device instead. Its devres is released when the driver is unbound, which is exactly the lifetime the array wants:imx6q_set_target() reads it, and nothing may reach that after cpufreq_unregister_driver().
That makes the array actually go away on unbind, so also clear the file-scope pointer in remove and on the failed-probe path, rather than leave it pointing at memory devres is about to release.
Tested by rebinding the driver on qemu's mcimx6ul-evk.
--- drivers/cpufreq/imx6q-cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/cpufreq/imx6q-cpufreq.c +3 -1
@@ -401,7 +401,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) }/* Make imx6_soc_volt array's size same as arm opp number */ - imx6_soc_volt =devm_kcalloc (cpu_dev, num,sizeof (*imx6_soc_volt), + imx6_soc_volt =devm_kcalloc (&pdev->dev, num,sizeof (*imx6_soc_volt),GFP_KERNEL );if (imx6_soc_volt ==NULL ) { ret = -ENOMEM ;
@@ -486,6 +486,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)return 0 ; free_freq_table: + imx6_soc_volt =NULL ;dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table); out_free_opp:dev_pm_opp_of_remove_table (cpu_dev);
@@ -507,6 +508,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)static void imx6q_cpufreq_remove (struct platform_device *pdev) {cpufreq_unregister_driver (&imx6q_cpufreq_driver); + imx6_soc_volt =NULL ;dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table);dev_pm_opp_of_remove_table (cpu_dev);regulator_put (arm_reg);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 923/1376 cpufreq: imx6q: fix out-of-bounds write when probed more than once
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 8c3afcf27fa4582c1ab912503dc8a4ebb8dc0f82 ]
imx6_soc_volt is allocated fresh on every probe, sized to the number of ARM OPPs:
imx6_soc_volt = devm_kcalloc(cpu_dev, num, sizeof(*imx6_soc_volt), GFP_KERNEL);
but it is filled through soc_opp_count, which has static storage and is never reset. A second bind after an unbind keeps indexing from where the first one stopped, and writes past the end of the new array.
Unbinding and rebinding the driver on qemu's mcimx6ul-evk, under KASAN:
BUG: KASAN: slab-out-of-bounds in imx6q_cpufreq_probe+0x3b0/0xa34 Write of size 4 at addr c5e90480 by task binder/73 imx6q_cpufreq_probe from platform_probe+0x88/0xe4 platform_probe from really_probe+0x108/0x384 bind_store from kernfs_fop_write_iter+0x1b4/0x28c
The write lands one u32 past the end of the allocation.
soc_opp_count is only read a few lines below the loop that fills it, so it never needed static storage. Make it a local.
--- drivers/cpufreq/imx6q-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cpufreq/imx6q-cpufreq.c +1 -1
@@ -55,7 +55,6 @@ static unsigned int max_freq;static unsigned int transition_latency;static u32 *imx6_soc_volt; -static u32 soc_opp_count;static int imx6q_set_target (struct cpufreq_policy *policy,unsigned int index) {
@@ -331,6 +330,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)const struct property *prop;const __be32 *val;u32 nr, i, j; +u32 soc_opp_count =0 ; cpu_dev =get_cpu_device (0 );if (!cpu_dev) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 924/1376 IB/isert: delay the final Login Response until the session is registered
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 464f5afa92d071a226f88424803b0fcf88093ede ]
isert_put_login_tx() puts the final Login Response on the wire before __transport_register_session(), which iscsi_post_login_handler() reaches only after iscsi_target_do_login() returns. An initiator that issues a SCSI command as soon as it sees that response can have it executed against an se_session whose se_tpg is still NULL, and the ib-comp-wq worker oopses on the NULL dereference.
Oops: general protection fault, probably for non-canonical address 0xdffffc000000000f: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000078-0x000000000000007f] CPU: 0 UID: 0 PID: 178 Comm: kworker/0:1H Not tainted 7.2.0-rc5-V2CTL-gf5098b6bae76 #10 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: ib-comp-wq ib_cq_poll_work RIP: 0010:target_submit+0xbe/0x390 Code: fa 48 c1 ea 03 80 3c 02 00 0f 85 89 02 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 64 24 18 49 8d 7c 24 78 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 5a 02 00 00 48 8d 7b 78 4d 8b 6c 24 78 48 b8 00 RSP: 0018:ffff8881058cfa78 EFLAGS: 00010206 RAX: dffffc0000000000 RBX: ffff88810c78c6f0 RCX: ffffffff964bb363 RDX: 000000000000000f RSI: 00000000fffffe00 RDI: 0000000000000078 RBP: 1ffff11020b19f52 R08: 0000000000000001 R09: ffffed1020b19f52 R10: 0000000000000003 R11: ffff88810596c000 R12: 0000000000000000 R13: ffff88810c61b000 R14: ffff88810c6a3400 R15: ffff88810c61b044 FS: 0000000000000000(0000) GS:ffff8881822b2000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f1f1b83c000 CR3: 000000006fe72001 CR4: 0000000000770ef0 PKRU: 55555554 Call Trace: <TASK> ? __pfx__raw_spin_lock_bh+0x10/0x10 ? __pfx_target_submit+0x10/0x10 ? mutex_lock+0x81/0xe0 ? __pfx_mutex_lock+0x10/0x10 ? iscsit_execute_cmd+0x650/0x850 iscsit_sequence_cmd+0x186/0x3d0 iscsit_process_scsi_cmd+0x87/0x300 isert_recv_done+0x1002/0x2390 ? __pfx_isert_recv_done+0x10/0x10 ? rxe_poll_cq+0x253/0x3d0 ? finish_task_switch.isra.0+0x1dc/0xa70 __ib_process_cq+0xe1/0x390 ib_cq_poll_work+0x46/0x150 process_one_work+0x633/0x1030 ? assign_work+0x11d/0x370 worker_thread+0x45b/0xd10 ? __pfx_worker_thread+0x10/0x10 ? __pfx_worker_thread+0x10/0x10 kthread+0x2c6/0x3b0 ? recalc_sigpending+0x15c/0x1e0 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x36e/0x5a0 ? __pfx_ret_from_fork+0x10/0x10 ? __switch_to+0x572/0xdd0 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]---
Delay the final Login Response instead. isert_get_rx_pdu() runs from iscsi_target_rx_thread() after conn->rx_login_comp, completed by iscsi_post_login_handler() after __transport_register_session(); iscsi-TCP and cxgbit already take PDUs from that thread, isert alone does not. The buffers are still posted first, so the initiator's first command does not meet an empty receive queue and nothing depends on RNR flow control, and the header and payload live in isert_conn, not in the struct iscsi_login that iscsi_target_nego_release() frees first.
Over rxe, 400 login cycles per run, the oops appeared in 10 of 20 unpatched runs and in none of 20 runs with this patch. An initiator that never waits is handled by the next patch.
Not tested: iWARP, discovery sessions over iSER, and real HCAs.
--- drivers/infiniband/ulp/isert/ib_isert.c | 20 ++++++++++++++++++-- drivers/infiniband/ulp/isert/ib_isert.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-)
drivers/infiniband/ulp/isert/ib_isert.c +18 -2
@@ -59,6 +59,8 @@ static void isert_recv_done(struct ib_cq *cq, struct ib_wc *wc);static void isert_send_done (struct ib_cq *cq,struct ib_wc *wc);static void isert_login_recv_done (struct ib_cq *cq,struct ib_wc *wc);static void isert_login_send_done (struct ib_cq *cq,struct ib_wc *wc); +static void isert_unmap_tx_desc (struct iser_tx_desc *tx_desc, +struct ib_device *ib_dev);static int isert_sg_tablesize_set (const char *val,const struct kernel_param *kp) {
@@ -498,6 +500,8 @@ isert_connect_release(struct isert_conn *isert_conn)if (isert_conn->qp)isert_destroy_qp (isert_conn); +isert_unmap_tx_desc (&isert_conn->login_tx_desc, device->ib_device); +if (isert_conn->login_desc)isert_free_login_buf (isert_conn);
@@ -958,14 +962,17 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login,mutex_lock (&isert_conn->mutex); isert_conn->state =ISER_CONN_FULL_FEATURE ;mutex_unlock (&isert_conn->mutex); - goto post_send; + +/* Sent from isert_get_rx_pdu() after registration. */ + isert_conn->login_rsp_pending = true; +return 0 ; } ret =isert_login_post_recv (isert_conn);if (ret)return ret; } -post_send: + ret =isert_login_post_send (isert_conn, tx_desc);if (ret)return ret;
@@ -2625,8 +2632,17 @@ static void isert_free_conn(struct iscsit_conn *conn)static void isert_get_rx_pdu (struct iscsit_conn *conn) { +struct isert_conn *isert_conn = conn->context;struct completion comp; +/* The session is registered by now; see isert_put_login_tx(). */ +if (isert_conn->login_rsp_pending) { + isert_conn->login_rsp_pending = false; +if (isert_login_post_send (isert_conn, + &isert_conn->login_tx_desc)) +return ; + } +init_completion (&comp);wait_for_completion_interruptible (&comp);
drivers/infiniband/ulp/isert/ib_isert.h +1 -0
@@ -178,6 +178,7 @@ struct isert_conn {struct completion login_comp;struct completion login_req_comp;struct iser_tx_desc login_tx_desc; +bool login_rsp_pending;struct rdma_cm_id *cm_id;struct ib_qp *qp;struct ib_cq *cq;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 925/1376 IB/isert: post the full-feature receive buffers after session registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 5247dde9daac7e107853b6fea043f7f47be033f7 ]
isert_put_login_tx() posts the full-feature receive buffers before __transport_register_session() runs, so an initiator that does not wait for the final Login Response can still have a SCSI command executed against an se_session whose se_tpg is NULL - the same oops as the previous patch, at target_submit+0xbe.
Post them from isert_get_rx_pdu(), which the previous patch already uses to send that response, and post them before that send: the receive queue is filled at the moment the initiator is told it may use it. Allocating there keeps the existing property that a memory allocation failure cannot happen once the final Login Response is on the wire.
The receive queue is already empty between the final Login Request and isert_post_recvm(); this moves the second point later, from a median of 92 us to 172 us over 1200 logins. Only an initiator that sends before it has been told to can reach that window, and on IB and RoCE its send is retried there until the buffers appear - isert_rdma_accept() asks for rnr_retry_count = 7. iWARP has no RNR flow control, so there the same send terminates the connection instead.
Measured over rxe, 400 login cycles per run, with an initiator that does not wait: an instrumented build counted no entries to isert_recv_done() before the buffers are posted in 10 runs, where that initiator oopsed 8 of 10 unpatched runs and 5 of 10 with only the previous patch.
Not tested: iWARP, discovery sessions over iSER, and real HCAs.
--- drivers/infiniband/ulp/isert/ib_isert.c | 41 ++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-)
drivers/infiniband/ulp/isert/ib_isert.c +20 -21
@@ -949,21 +949,7 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login, }if (!login->login_failed) {if (login->login_complete) { - ret =isert_alloc_rx_descriptors (isert_conn); -if (ret) -return ret; - - ret =isert_post_recvm (isert_conn, -ISERT_QP_MAX_RECV_DTOS ); -if (ret) -return ret; - -/* Now we are in FULL_FEATURE phase */ -mutex_lock (&isert_conn->mutex); - isert_conn->state =ISER_CONN_FULL_FEATURE ; -mutex_unlock (&isert_conn->mutex); - -/* Sent from isert_get_rx_pdu() after registration. */ +/* Posted and sent from isert_get_rx_pdu(). */ isert_conn->login_rsp_pending = true;return 0 ; }
@@ -2635,13 +2621,26 @@ static void isert_get_rx_pdu(struct iscsit_conn *conn)struct isert_conn *isert_conn = conn->context;struct completion comp; +/* The login timeout timer can fail the login after isert_put_login_tx(). */ +if (!isert_conn->login_rsp_pending) +return ; + + isert_conn->login_rsp_pending = false; +/* The session is registered by now; see isert_put_login_tx(). */ -if (isert_conn->login_rsp_pending) { - isert_conn->login_rsp_pending = false; -if (isert_login_post_send (isert_conn, - &isert_conn->login_tx_desc)) -return ; - } +if (isert_alloc_rx_descriptors (isert_conn)) +return ; + +if (isert_post_recvm (isert_conn,ISERT_QP_MAX_RECV_DTOS )) +return ; + +/* Now we are in FULL_FEATURE phase */ +mutex_lock (&isert_conn->mutex); + isert_conn->state =ISER_CONN_FULL_FEATURE ; +mutex_unlock (&isert_conn->mutex); + +if (isert_login_post_send (isert_conn, &isert_conn->login_tx_desc)) +return ;init_completion (&comp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 926/1376 RDMA/siw: Fix use-after-free in siw_accept()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
[ Upstream commit a9394971825933074032794a5feee5211509c774 ]
siw_accept() looks up the QP supplied by userspace. If that QP is already in RTS, the function jumps to error cleanup before associating the incoming CEP with it.
The cleanup tests whether qp->cep is non-NULL and assumes the current call installed the association. However, qp->cep can point to the CEP of an existing connection. The cleanup then drops a reference from the incoming cep, not qp->cep. Once the incoming endpoint loses its remaining references, this can free it before the subsequent cep->qp store, causing a use-after-free. It also clears the existing QP association.
Only release the association reference when qp->cep is the incoming CEP. This preserves an existing association and avoids accessing the freed endpoint.
--- drivers/infiniband/sw/siw/siw_cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/sw/siw/siw_cm.c +1 -1
@@ -1701,7 +1701,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) cep->state =SIW_EPSTATE_CLOSED ;siw_free_cm_id (cep); -if (qp->cep) { +if (qp->cep == cep) {siw_cep_put (cep); qp->cep =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 927/1376 module: replace use of system_wq with system_dfl_wq
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Crivellari <[email protected]>
[ Upstream commit 581ac2d4a58b81669cc6abf645a558bce5cf14ab ]
Currently if a user enqueues a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND.
This lack of consistency cannot be addressed without refactoring the API.
This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue flag in:
commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")
Switch to using system_dfl_wq, the new unbound workqueue, because the users do not benefit from a per-cpu workqueue.
Stable-dep-of: 5eecb11b543f ("module/dups: Fix use-after-free in kmod_dup_req lifetime handling")
--- kernel/module/dups.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/module/dups.c +2 -2
@@ -113,7 +113,7 @@ static void kmod_dup_request_complete(struct work_struct *work)* let this linger forever as this is just a boot optimization for * possible abuses of vmalloc() incurred by finit_module() thrashing. */ -queue_delayed_work (system_wq, &kmod_req->delete_work,60 *HZ ); +queue_delayed_work (system_dfl_wq, &kmod_req->delete_work,60 *HZ ); }bool kmod_dup_request_exists_wait (char *module_name,bool wait,int *dup_ret)
@@ -240,7 +240,7 @@ void kmod_dup_request_announce(char *module_name, int ret)* There is no rush. But we also don't want to hold the * caller up forever or introduce any boot delays. */ -queue_work (system_wq, &kmod_req->complete_work); +queue_work (system_dfl_wq, &kmod_req->complete_work); out:mutex_unlock (&kmod_dup_mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 928/1376 module: use strscpy() to copy module names in stats and dup tracking
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naveen Kumar Chaudhary <[email protected]>
[ Upstream commit 93c29ebd1622fb0670701e1c1b3a978a5cac08b7 ]
Both try_add_failed_module() and kmod_dup_request_exists_wait() use memcpy() with strlen() to copy module names into fixed-size char[MODULE_NAME_LEN] buffers. Neither performs a bounds check on the copy. Current callers always pass names originating from mod->name (itself char[MODULE_NAME_LEN]), so this is not exploitable today. However both functions accept a plain const char * with no documented length contract, making them latent buffer overflows if a future caller passes a longer string.
Replace memcpy() with strscpy() in both sites, which bounds the copy to MODULE_NAME_LEN and always NUL-terminates.
Stable-dep-of: 5eecb11b543f ("module/dups: Fix use-after-free in kmod_dup_req lifetime handling")
--- kernel/module/dups.c | 2 +- kernel/module/stats.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
kernel/module/dups.c +1 -1
@@ -129,7 +129,7 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)if (!new_kmod_req)return false; -memcpy (new_kmod_req->name, module_name,strlen (module_name)); +strscpy (new_kmod_req->name, module_name);INIT_WORK (&new_kmod_req->complete_work, kmod_dup_request_complete);INIT_DELAYED_WORK (&new_kmod_req->delete_work, kmod_dup_request_delete);init_completion (&new_kmod_req->first_req_done);
kernel/module/stats.c +1 -1
@@ -253,7 +253,7 @@ int try_add_failed_module(const char *name, enum fail_dup_mod_reason reason) mod_fail =kzalloc (sizeof (*mod_fail),GFP_KERNEL );if (!mod_fail)return -ENOMEM ; -memcpy (mod_fail->name, name,strlen (name)); +strscpy (mod_fail->name, name);__set_bit (reason, &mod_fail->dup_fail_mask);atomic_long_inc (&mod_fail->count);list_add_rcu (&mod_fail->list, &dup_failed_modules);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 929/1376 module/dups: Inform duplicate requests about the result directly
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Pavlu <[email protected]>
[ Upstream commit d258ed8a86bb46bbbbc84fb914478259a1e694a4 ]
When kmod_dup_request_announce() announces the completion of a request_module() call to duplicate waiters, it queues a work item to invoke kmod_dup_request_complete(), and only that function calls complete_all().
This adds an arbitrary delay that is unnecessary and provides little benefit. Call complete_all() directly from kmod_dup_request_announce() instead.
Stable-dep-of: 5eecb11b543f ("module/dups: Fix use-after-free in kmod_dup_req lifetime handling")
--- kernel/module/dups.c | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-)
kernel/module/dups.c +9 -34
@@ -48,7 +48,6 @@ struct kmod_dup_req {struct list_head list;char name[MODULE_NAME_LEN ];struct completion first_req_done; -struct work_struct complete_work;struct delayed_work delete_work;int dup_ret; };
@@ -93,29 +92,6 @@ static void kmod_dup_request_delete(struct work_struct *work)kfree (kmod_req); } -static void kmod_dup_request_complete (struct work_struct *work) -{ -struct kmod_dup_req *kmod_req; - - kmod_req = container_of(work, struct kmod_dup_req, complete_work); - -/* -* This will ensure that the kernel will let all the waiters get -* informed its time to check the return value. It's time to -* go home. -*/ -complete_all (&kmod_req->first_req_done); - -/* -* Now that we have allowed prior request_module() calls to go on -* with life, let's schedule deleting this entry. We don't have -* to do it right away, but we *eventually* want to do it so to not -* let this linger forever as this is just a boot optimization for -* possible abuses of vmalloc() incurred by finit_module() thrashing. -*/ -queue_delayed_work (system_dfl_wq, &kmod_req->delete_work,60 *HZ ); -} -bool kmod_dup_request_exists_wait (char *module_name,bool wait,int *dup_ret) {struct kmod_dup_req *kmod_req, *new_kmod_req;
@@ -130,7 +106,6 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)return false;strscpy (new_kmod_req->name, module_name); -INIT_WORK (&new_kmod_req->complete_work, kmod_dup_request_complete);INIT_DELAYED_WORK (&new_kmod_req->delete_work, kmod_dup_request_delete);init_completion (&new_kmod_req->first_req_done);
@@ -230,17 +205,17 @@ void kmod_dup_request_announce(char *module_name, int ret) kmod_req->dup_ret = ret; +/* Inform all duplicate waiters to check the return value. */ +complete_all (&kmod_req->first_req_done); +/* -* If we complete() here we may allow duplicate threads -* to continue before the first one that submitted the -* request. We're in no rush also, given that each and -* every bounce back to userspace is slow we avoid that -* with a slight delay here. So queueue up the completion -* and let duplicates suffer, just wait a tad bit longer. -* There is no rush. But we also don't want to hold the -* caller up forever or introduce any boot delays. +* Now that we have allowed prior request_module() calls to go on +* with life, let's schedule deleting this entry. We don't have +* to do it right away, but we *eventually* want to do it so to not +* let this linger forever as this is just a boot optimization for +* possible abuses of vmalloc() incurred by finit_module() thrashing. */ -queue_work (system_dfl_wq, &kmod_req->complete_work); +queue_delayed_work (system_dfl_wq, &kmod_req->delete_work,60 *HZ ); out:mutex_unlock (&kmod_dup_mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 930/1376 module/dups: Fix use-after-free in kmod_dup_req lifetime handling
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Pavlu <[email protected]>
[ Upstream commit 5eecb11b543f9f417bcf0dea239ff99c6af65dbd ]
The kmod dups code uses RCU to ensure that a kmod_dup_req instance is freed only after it is no longer referenced. When releasing an instance, the kmod_dup_request_delete() function removes the kmod_dup_req from the dup_kmod_reqs list, waits via synchronize_rcu() and finally frees it. However, this doesn't work correctly because parallel users referencing the instance in kmod_dup_request_exists_wait() don't enter an RCU read-side critical section. This can result in a use-after-free.
The kmod_dup_request_exists_wait() function may need to hold a valid reference to a kmod_dup_req instance across a blocking wait until the corresponding modprobe command completes. This makes it unsuitable for RCU.
Fix the issue by changing the lifecycle management of kmod_dup_req to use reference counting.
--- kernel/module/dups.c | 56 +++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 16 deletions(-)
kernel/module/dups.c +40 -16
@@ -30,6 +30,7 @@#include <linux/ptrace.h> #include <linux/async.h> #include <linux/uaccess.h> +#include <linux/refcount.h> #include "internal.h"
@@ -38,13 +39,12 @@static bool enable_dups_trace =IS_ENABLED (CONFIG_MODULE_DEBUG_AUTOLOAD_DUPS_TRACE );module_param (enable_dups_trace, bool_enable_only,0644 ); -/* -* Protects dup_kmod_reqs list, adds / removals with RCU. -*/ +/* A mutex-protected list of active kmod requests. */ static DEFINE_MUTEX (kmod_dup_mutex);static LIST_HEAD (dup_kmod_reqs);struct kmod_dup_req { +refcount_t refcount;struct list_head list;char name[MODULE_NAME_LEN ];struct completion first_req_done;
@@ -52,12 +52,24 @@ struct kmod_dup_req {int dup_ret; }; +static void get_kmod_req (struct kmod_dup_req *kmod_req) +{ +refcount_inc (&kmod_req->refcount); +} + +static void put_kmod_req (struct kmod_dup_req *kmod_req) +{ +if (refcount_dec_and_test (&kmod_req->refcount)) +kfree (kmod_req); +} +static struct kmod_dup_req *kmod_dup_request_lookup (char *module_name) {struct kmod_dup_req *kmod_req; -list_for_each_entry_rcu (kmod_req, &dup_kmod_reqs, list, -lockdep_is_held (&kmod_dup_mutex)) { +lockdep_assert_held (&kmod_dup_mutex); + +list_for_each_entry (kmod_req, &dup_kmod_reqs, list) {if (strlen (kmod_req->name) ==strlen (module_name) && !memcmp (kmod_req->name, module_name,strlen (module_name))) {return kmod_req;
@@ -86,10 +98,10 @@ static void kmod_dup_request_delete(struct work_struct *work)* just returning 0. */ mutex_lock (&kmod_dup_mutex); -list_del_rcu (&kmod_req->list); -synchronize_rcu (); +list_del (&kmod_req->list);mutex_unlock (&kmod_dup_mutex); -kfree (kmod_req); + +put_kmod_req (kmod_req); }bool kmod_dup_request_exists_wait (char *module_name,bool wait,int *dup_ret)
@@ -105,6 +117,7 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)if (!new_kmod_req)return false; +refcount_set (&new_kmod_req->refcount,1 );strscpy (new_kmod_req->name, module_name);INIT_DELAYED_WORK (&new_kmod_req->delete_work, kmod_dup_request_delete);init_completion (&new_kmod_req->first_req_done);
@@ -136,10 +149,12 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)* keep tab on duplicates later. */ pr_debug ("New request_module() for %s\n" , module_name); -list_add_rcu (&new_kmod_req->list, &dup_kmod_reqs); +list_add (&new_kmod_req->list, &dup_kmod_reqs);mutex_unlock (&kmod_dup_mutex);return false; } + +get_kmod_req (kmod_req);mutex_unlock (&kmod_dup_mutex);/* We are dealing with a duplicate request now */
@@ -169,7 +184,7 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)* calls bail out right away. */ *dup_ret =0 ; -return true; + goto out; }/*
@@ -184,12 +199,14 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret) TASK_KILLABLE);if (ret) { *dup_ret = ret; -return true; + goto out; }/* Now the duplicate request has the same exact return value as the first request */ *dup_ret = kmod_req->dup_ret; +out: +put_kmod_req (kmod_req);return true; }
@@ -199,15 +216,25 @@ void kmod_dup_request_announce(char *module_name, int ret)mutex_lock (&kmod_dup_mutex); +/* +* Look for a kmod_dup_req previously added in +* kmod_dup_request_exists_wait(). Note that a request_module_nowait() +* without its own kmod_dup_req entry can announce a result of +* a concurrent request_module() call. +*/ kmod_req =kmod_dup_request_lookup (module_name); -if (!kmod_req) - goto out; +if (!kmod_req ||completion_done (&kmod_req->first_req_done)) { +mutex_unlock (&kmod_dup_mutex); +return ; + } kmod_req->dup_ret = ret;/* Inform all duplicate waiters to check the return value. */ complete_all (&kmod_req->first_req_done); +mutex_unlock (&kmod_dup_mutex); +/* * Now that we have allowed prior request_module() calls to go on * with life, let's schedule deleting this entry. We don't have
@@ -216,7 +243,4 @@ void kmod_dup_request_announce(char *module_name, int ret)* possible abuses of vmalloc() incurred by finit_module() thrashing. */ queue_delayed_work (system_dfl_wq, &kmod_req->delete_work,60 *HZ ); - -out: -mutex_unlock (&kmod_dup_mutex); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 931/1376 RDMA/erdma: restrict the driver to little-endian systems
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit a12d9145145b21c50531afb6e3f711b1f34e1465 ]
The eRDMA device interface requires explicit byte ordering, but several DMA-visible values that should be little-endian remain native-endian. Command request payloads are copied verbatim, data-path SQE headers are written without cpu_to_le64(), and kernel doorbell records are assigned plain u64 values. The command completion path also reads a little-endian SQE header without conversion.
These paths are byte-swapped on big-endian kernels and can break command processing during probe. Since complete big-endian support requires converting every device-visible structure, depend on !CPU_BIG_ENDIAN.
--- drivers/infiniband/hw/erdma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/erdma/Kconfig +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config INFINIBAND_ERDMA tristate "Alibaba Elastic RDMA Adapter (ERDMA) support" - depends on PCI_MSI && 64BIT + depends on PCI_MSI && 64BIT && !CPU_BIG_ENDIAN depends on INFINIBAND_ADDR_TRANS depends on INFINIBAND_USER_ACCESS help
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 932/1376 wifi: mac80211: skip default WMM setup for AP_VLAN links
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 4d8cfff012aaa971d50b01823b1015c1073c3ff6 ]
AP_VLAN interfaces are never passed to the driver, so setting default WMM parameters on their links trips the check-sdata-in-driver warning in drv_conf_tx(), as well as in the BSS_CHANGED_QOS link info notification. Skip it, matching the existing AP_VLAN handling in this function.
--- net/mac80211/link.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/mac80211/link.c +2 -1
@@ -340,7 +340,8 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, link = links[link_id];ieee80211_link_init (sdata, link_id, &link->data, &link->conf);ieee80211_link_setup (&link->data); -ieee80211_set_wmm_default (&link->data, true, non_sta); +if (sdata->vif.type !=NL80211_IFTYPE_AP_VLAN ) +ieee80211_set_wmm_default (&link->data, true, non_sta); }if (new_links ==0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 933/1376 arm64: hibernate: mask DAIF before restoring hibernated kernel
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ada Couprie Diaz <[email protected]>
[ Upstream commit 684bde100117931f4c51c644a95f42f2dab041bc ]
The arm64 hibernate code manages the exception masking in an unsound way, leading to potential crashes and/or warnings during resume.
When a hibernation image is saved in swsusp_arch_suspend(), all DAIF exceptions are masked (by virtue of local_daif_save()), and the suspended image is saved assuming that all DAIF exceptions will remain masked when the image is restored.
When a hibernation image is resumed by swsusp_arch_resume(), only interrupts are masked (by virtue of local_irq_disable() in resume_target_kernel()). When pseudo-NMI is enabled the DAIF.IF bits will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be clear.
This means that there are two problems:
(1) It is possible to take Debug, SError, or pseudo-NMI exceptions during the resume process. This is unsafe, as during the resume process both the old ane new kernels will tranisently be in an inconsistent state, and swsusp_arch_suspend_exit() won't retain an executable mapping of any exception vectors.
Any exception taken here will be fatal and silent.
(2) When re-entering the resumed kernel, some DAIF bits will be clear unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions to be taken for a short period while the resumed kernel is not yet in a consistent state.
This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.
Avoid these issues by masking all DAIF exceptions during resume.
--- arch/arm64/kernel/hibernate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/arm64/kernel/hibernate.c +12 -0
@@ -459,9 +459,21 @@ int __nocfi swsusp_arch_resume(void)if (el2_reset_needed ())__hyp_set_vectors (el2_vectors); +/* +* It is necessary to mask all DAIF exceptions here as: +* +* - The copy of swsusp_arch_suspend_exit() in the hibernation +* text cannot handle taking any exceptions. +* +* - The suspended kernel masked all DAIF exceptions in +* swsusp_arch_resume(), and expects to be re-entered in the +* same state : with all DAIF exceptions masked. +*/ +local_daif_save ();hibernate_exit (virt_to_phys (tmp_pg_dir), resume_hdr.ttbr1_el1, resume_hdr.reenter_kernel, restore_pblist, resume_hdr.__hyp_stub_vectors,virt_to_phys (zero_page)); +unreachable ();return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 934/1376 arm64: hibernate: Restore DAIF state on error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Murzin <[email protected]>
[ Upstream commit 541549827889d0380fd73f8aacb5de6ef7a5a1ac ]
Sashiko AI has reported that if swsusp_mte_save_tags() for some reason fails we return from swsusp_arch_suspend() with DAIF being masked - that is not what we'd expect. Restore the saved DAIF state before returning from the error path.
--- arch/arm64/kernel/hibernate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm64/kernel/hibernate.c +3 -1
@@ -342,8 +342,10 @@ int swsusp_arch_suspend(void)crash_prepare_suspend (); ret =swsusp_mte_save_tags (); -if (ret) +if (ret) { +local_daif_restore (flags);return ret; + } sleep_cpu =smp_processor_id (); ret =swsusp_save ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 935/1376 mfd: rave-sp: validate received frame payload lengths
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 0be718b5451bd83865d6e2a8d750ca7886c4772a ]
A received RAVE-SP frame contains protocol data followed by a variant-specific one- or two-byte checksum. rave_sp_receive_frame() derives a checksum pointer before proving that the frame contains the checksum, then passes the checksum-inclusive length to handlers that index the command, acknowledgment ID and event-data bytes or derive a reply payload length.
Name those protocol field offsets, prove the checksum extent before deriving the protocol-data length, pass only that data length to the handlers, and require the complete event or reply prefix before consuming it.
--- drivers/mfd/rave-sp.c | 64 +++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 20 deletions(-)
drivers/mfd/rave-sp.c +44 -20
@@ -63,6 +63,12 @@#define RAVE_SP_TX_BUFFER_SIZE \ (RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE) +enum rave_sp_frame_offset { +RAVE_SP_FRAME_CODE_OFFSET , +RAVE_SP_FRAME_ACK_ID_OFFSET , +RAVE_SP_FRAME_DATA_OFFSET , +}; +/** * enum rave_sp_deframer_state - Possible state for de-framer *
@@ -352,7 +358,7 @@ int rave_sp_exec(struct rave_sp *sp,int command, ret =0 ;u8 ackid; - command = sp->variant->cmd.translate (data[0 ]); + command = sp->variant->cmd.translate (data[RAVE_SP_FRAME_CODE_OFFSET ]);if (command <0 )return command;
@@ -366,8 +372,8 @@ int rave_sp_exec(struct rave_sp *sp, sp->reply = &reply;mutex_unlock (&sp->reply_lock); - data[0 ] = command; - data[1 ] = ackid; + data[RAVE_SP_FRAME_CODE_OFFSET ] = command; + data[RAVE_SP_FRAME_ACK_ID_OFFSET ] = ackid;rave_sp_write (sp, data, data_size);
@@ -388,16 +394,23 @@ EXPORT_SYMBOL_GPL(rave_sp_exec);static void rave_sp_receive_event (struct rave_sp *sp,const unsigned char *data,size_t length) { -u8 cmd[] = { - [0 ] =rave_sp_reply_code (data[0 ]), - [1 ] = data[1 ], - }; +unsigned long action; +u8 cmd[RAVE_SP_FRAME_DATA_OFFSET ]; + +if (length <RAVE_SP_FRAME_DATA_OFFSET +1 ) { +dev_warn (&sp->serdev->dev,"Dropping short event frame\n" ); +return ; + } + + cmd[RAVE_SP_FRAME_CODE_OFFSET ] = +rave_sp_reply_code (data[RAVE_SP_FRAME_CODE_OFFSET ]); + cmd[RAVE_SP_FRAME_ACK_ID_OFFSET ] = data[RAVE_SP_FRAME_ACK_ID_OFFSET ];rave_sp_write (sp, cmd,sizeof (cmd)); -blocking_notifier_call_chain (&sp->event_notifier_list, -rave_sp_action_pack (data[0 ], data[2 ]), -NULL ); + action =rave_sp_action_pack (data[RAVE_SP_FRAME_CODE_OFFSET ], + data[RAVE_SP_FRAME_DATA_OFFSET ]); +blocking_notifier_call_chain (&sp->event_notifier_list, action,NULL ); } static void rave_sp_receive_reply(struct rave_sp *sp,
@@ -405,27 +418,35 @@ static void rave_sp_receive_reply(struct rave_sp *sp, {struct device *dev = &sp->serdev->dev;struct rave_sp_reply *reply; -const size_t payload_length = length -2 ; +size_t payload_length; + +if (length <RAVE_SP_FRAME_DATA_OFFSET ) { +dev_warn (dev,"Dropping short reply frame\n" ); +return ; + } + payload_length = length -RAVE_SP_FRAME_DATA_OFFSET ;mutex_lock (&sp->reply_lock); reply = sp->reply;if (reply) { -if (reply->code == data[0 ] && reply->ackid == data[1 ] && +if (reply->code == data[RAVE_SP_FRAME_CODE_OFFSET ] && + reply->ackid == data[RAVE_SP_FRAME_ACK_ID_OFFSET ] && payload_length >= reply->length) {/* * We are relying on memcpy(dst, src, 0) to be a no-op * when handling commands that have a no-payload reply */ -memcpy (reply->data, &data[2 ], reply->length); +memcpy (reply->data, &data[RAVE_SP_FRAME_DATA_OFFSET ], + reply->length);complete (&reply->received); sp->reply =NULL ; }else {dev_err (dev,"Ignoring incorrect reply\n" );dev_dbg (dev,"Code: expected = 0x%08x received = 0x%08x\n" , - reply->code, data[0 ]); + reply->code, data[RAVE_SP_FRAME_CODE_OFFSET ]);dev_dbg (dev,"ACK ID: expected = 0x%08x received = 0x%08x\n" , - reply->ackid, data[1 ]); + reply->ackid, data[RAVE_SP_FRAME_ACK_ID_OFFSET ]);dev_dbg (dev,"Length: expected = %zu received = %zu\n" , reply->length, payload_length); }
@@ -439,10 +460,10 @@ static void rave_sp_receive_frame(struct rave_sp *sp, size_t length) {const size_t checksum_length = sp->variant->checksum->length; -const size_t payload_length = length - checksum_length; -const u8 *crc_reported = &data[payload_length];struct device *dev = &sp->serdev->dev;u8 crc_calculated[RAVE_SP_CHECKSUM_SIZE ]; +const u8 *crc_reported; +size_t payload_length;if (unlikely (checksum_length >sizeof (crc_calculated))) {dev_warn (dev,"Checksum too long, dropping\n" );
@@ -457,6 +478,9 @@ static void rave_sp_receive_frame(struct rave_sp *sp,return ; } + payload_length = length - checksum_length; + crc_reported = &data[payload_length]; + sp->variant->checksum->subroutine (data, payload_length, crc_calculated);
@@ -465,10 +489,10 @@ static void rave_sp_receive_frame(struct rave_sp *sp,return ; } -if (rave_sp_id_is_event (data[0 ])) -rave_sp_receive_event (sp, data, length); +if (rave_sp_id_is_event (data[RAVE_SP_FRAME_CODE_OFFSET ])) +rave_sp_receive_event (sp, data, payload_length);else -rave_sp_receive_reply (sp, data, length); +rave_sp_receive_reply (sp, data, payload_length); } static size_t rave_sp_receive_buf(struct serdev_device *serdev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 936/1376 mfd: iqs62x: Reject zero-length firmware records
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 08ea045e0b82cbcadb7a2efc43a23561489a00f2 ]
struct iqs62x_fw_rec includes the first data byte in its fixed-size header, so the parser advances by len - 1 bytes after that header. A zero len makes the size_t cursor update move back by one byte, so the next record overlaps the current record instead of following a valid declared extent.
Reject zero-length records and express the remaining-size check without an offset addition.
--- drivers/mfd/iqs62x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mfd/iqs62x.c +1 -1
@@ -237,7 +237,7 @@ static int iqs62x_firmware_parse(struct iqs62x_core *iqs62x, fw_rec = (struct iqs62x_fw_rec *)(fw->data + pos); pos +=sizeof (*fw_rec); -if (pos + fw_rec->len -1 > fw->size) { +if (!fw_rec->len || fw_rec->len -1 > fw->size - pos) { ret = -EINVAL ;break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 937/1376 drm/amdgpu/gfx6: Fixup emit_cntxcntl()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 1edb323406aaf05739804d2faa2561f2d43bcd09 ]
Set bits on dword 2 like GFX7-8 except load_global_uconfig which doesn't exist on GFX6.
Emit VS_PARTIAL_FLUSH before VGT_FLUSH like GFX7-8.
For reference see old PAL which explains the bit fields in this register and that load_global_uconfig doesn't exist on GFX6 and also see gfx_v7_ring_emit_cntxcntl() for the GFX7 code which this commit follows.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +21 -7
@@ -1859,11 +1859,13 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)return r; } -static void gfx_v6_0_ring_emit_vgt_flush (struct amdgpu_ring *ring) +static void gfx_v6_0_ring_emit_event_write (struct amdgpu_ring *ring, +uint32_t event_type, +uint32_t event_index) {amdgpu_ring_write (ring,PACKET3 (PACKET3_EVENT_WRITE ,0 )); -amdgpu_ring_write (ring,EVENT_TYPE (VGT_FLUSH ) | -EVENT_INDEX (0 )); +amdgpu_ring_write (ring,EVENT_TYPE (event_type) | +EVENT_INDEX (event_index)); } static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
@@ -3000,10 +3002,22 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)static void gfx_v6_ring_emit_cntxcntl (struct amdgpu_ring *ring,uint32_t flags) { -if (flags &AMDGPU_HAVE_CTX_SWITCH ) -gfx_v6_0_ring_emit_vgt_flush (ring); +u32 dw2 =0x80000000 ;/* set load_enable otherwise this package is just NOPs */ + +if (flags &AMDGPU_HAVE_CTX_SWITCH ) { +gfx_v6_0_ring_emit_event_write (ring,VS_PARTIAL_FLUSH ,4 ); +gfx_v6_0_ring_emit_event_write (ring,VGT_FLUSH ,0 ); + +/* set load_global_config (load_global_uconfig doesn't exist on GFX6) */ + dw2 |=0x1 ; +/* set load_cs_sh_regs */ + dw2 |=0x01000000 ; +/* set load_per_context_state & load_gfx_sh_regs */ + dw2 |=0x10002 ; + } +amdgpu_ring_write (ring,PACKET3 (PACKET3_CONTEXT_CONTROL ,1 )); -amdgpu_ring_write (ring,0x80000000 ); +amdgpu_ring_write (ring, dw2);amdgpu_ring_write (ring,0 ); }
@@ -3539,7 +3553,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ 7 +4 +/* gfx_v6_0_ring_emit_pipeline_sync */ SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +6 +/* gfx_v6_0_ring_emit_vm_flush */ -3 +2 +/* gfx_v6_ring_emit_cntxcntl including vgt flush */ +3 +2 +2 +/* gfx_v6_ring_emit_cntxcntl including VGT flush */ 5, /* SURFACE_SYNC */ .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 938/1376 ext4: fix spurious message about orphan cleanup on RO fs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
[ Upstream commit 5aa98f874c013bcce9bb84ffded2f0ef886e4e33 ]
When orphan_file feature is enabled, ext4_orphan_cleanup() was always walking through the orphan file looking for orphan inodes. This is mostly harmless but for read-only filesystem it results in spurious "orphan cleanup on readonly fs" message and in other cornercases it could result in similar somewhat misleading messages. Skip orphan cleanup if the orphan file is empty to avoid confusing messages.
--- fs/ext4/orphan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/orphan.c +1 -1
@@ -388,7 +388,7 @@ void ext4_orphan_cleanup(struct super_block *sb, struct ext4_super_block *es)struct ext4_orphan_info *oi = &EXT4_SB (sb)->s_orphan_info;int inodes_per_ob =ext4_inodes_per_orphan_block (sb); -if (!es->s_last_orphan && !oi->of_blocks) { +if (!es->s_last_orphan &&ext4_orphan_file_empty (sb)) {ext4_debug ("no orphan inodes to clean up\n" );return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 939/1376 arm64: dts: ti: k3-am64: Fix MDIO clock reference for ICSSG0 node
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Meghana Malladi <[email protected]>
[ Upstream commit 197df050a10fe216971b45a79f07195c86a02236 ]
MDIO clock index changed from 62:3 to 81:0 to match proper clock definition in the SoC device tree. Clock Id 81:0 belongs to ICSSG0 core clock, where as 62 belongs to EQEP2 device.
See: https://software-dl.ti.com/tisci/esd/latest/5_soc_doc/am64x/clocks.html
--- arch/arm64/boot/dts/ti/k3-am64-main.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/ti/k3-am64-main.dtsi +1 -1
@@ -1349,7 +1349,7 @@ tx_pru0_1: txpru@c000 { icssg0_mdio: mdio@32400 { compatible = "ti,davinci_mdio"; reg = <0x32400 0x100>; - clocks = <&k3_clks 62 3>; + clocks = <&k3_clks 81 0>; clock-names = "fck"; #address-cells = <1>; #size-cells = <0>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 940/1376 phy: sunplus: fix error handling in sp_uphy_init()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 8b2683bc4cc18c581b7cd24f227cbe61abca7f4d ]
Fix the error paths of sp_uphy_init() to undo exactly what each stage
did: return directly if clk_prepare_enable() fails, release only the clock if reset_control_deassert() fails, and jump to err_reset if update_disc_vol() fails so the clock and reset are not leaked.
--- drivers/phy/sunplus/phy-sunplus-usb2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/phy/sunplus/phy-sunplus-usb2.c +3 -3
@@ -116,11 +116,11 @@ static int sp_uphy_init(struct phy *phy) ret =clk_prepare_enable (usbphy->phy_clk);if (ret) - goto err_clk; +return ret; ret =reset_control_deassert (usbphy->rstc);if (ret) - goto err_reset; + goto err_clk;/* Default value modification */ writel (HIGH_MASK_BITS |0x4002 , usbphy->moon4_regs +UPHY_CONTROL0 );
@@ -129,7 +129,7 @@ static int sp_uphy_init(struct phy *phy)/* disconnect voltage */ ret =update_disc_vol (usbphy);if (ret <0 ) -return ret; + goto err_reset;/* board uphy 0 internal register modification for tid certification */ val =readl (usbphy->phy_regs +CONFIG9 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 941/1376 phy: rockchip: phy-rockchip-inno-csidphy: fix rk1808 hsfreq table
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerald Loacker <[email protected]>
[ Upstream commit 4fae43e33a7c10951fbdc6baf409d51bd66aaefb ]
The rk1808 hsfreq table capped at 2499 Mbps, preventing a data rate of exactly 2500 Mbps. Extend the final entry to 2500 Mbps to support this rate.
This is essential for RK3588 reusing this array and fully supporting rates up to 2500 Mbps.
--- drivers/phy/rockchip/phy-rockchip-inno-csidphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +1 -1
@@ -157,7 +157,7 @@ static const struct hsfreq_range rk1808_mipidphy_hsfreq_ranges[] = { { 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e}, { 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e}, {1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37}, - {2199, 0x3c}, {2399, 0x41}, {2499, 0x46} + {2199, 0x3c}, {2399, 0x41}, {2500, 0x46} }; static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 942/1376 perf trace-event: Fix buffer overflow in read_string()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tanushree Shah <[email protected]>
[ Upstream commit 1121a7af1833f8b5723f1e32685b461614353d5d ]
read_string() writes into buf[BUFSIZ] one byte at a time without checking 'size' against the buffer bound before each write. A string longer than BUFSIZ in the input overflows the stack buffer.
Add a bounds check before each write to prevent overflow. On overflow the function returns NULL, matching its other error paths.
--- tools/perf/util/trace-event-read.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/perf/util/trace-event-read.c +5 -0
@@ -127,6 +127,11 @@ static char *read_string(void) } } +if (size >= (int )sizeof (buf) -1 ) { +pr_debug ("string too long (max %zu bytes)" ,sizeof (buf) -1 ); + goto out; + } + buf[size++] = c;if (!c)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 943/1376 drm/amdgpu/gfx6: Fixup emitting SWITCH_BUFFER packets
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 7aac4242a11991d530eee3e141d6e445d5f11c22 ]
Implement the emit_switch_buffer() function instead of emitting them duing emit_ib, emit_pipeline_sync and emit_vm_flush.
Note that it isn't necessary to emit these in both emit_pipeline_sync() and emit_vm_flush() because amdgpu_vm_flush() already calls these when calling either of those functions.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 38 ++++++++++----------------- 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +14 -24
@@ -1904,12 +1904,6 @@ static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,unsigned vmid =AMDGPU_JOB_GET_VMID (job);u32 header, control =0 ; -/* insert SWITCH_BUFFER packet before first IB in the ring frame */ -if (flags &AMDGPU_HAVE_CTX_SWITCH ) { -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); - } -if (ib->flags &AMDGPU_IB_FLAG_CE ) header =PACKET3 (PACKET3_INDIRECT_BUFFER_CONST ,2 );else
@@ -2344,14 +2338,6 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)amdgpu_ring_write (ring, seq);amdgpu_ring_write (ring,0xffffffff );amdgpu_ring_write (ring,4 );/* poll interval */ - -if (usepfp) { -/* synce CE with ME to prevent CE fetch CEIB before context switch done */ -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); - } } static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
@@ -2375,12 +2361,6 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,/* sync PFP to ME, otherwise we might get invalid PFP reads */ amdgpu_ring_write (ring,PACKET3 (PACKET3_PFP_SYNC_ME ,0 ));amdgpu_ring_write (ring,0x0 ); - -/* synce CE with ME to prevent CE fetch CEIB before context switch done */ -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); -amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); -amdgpu_ring_write (ring,0 ); } }
@@ -3000,6 +2980,12 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)return clock; } +static void gfx_v6_0_ring_emit_sb (struct amdgpu_ring *ring) +{ +amdgpu_ring_write (ring,PACKET3 (PACKET3_SWITCH_BUFFER ,0 )); +amdgpu_ring_write (ring,0 ); +} +static void gfx_v6_ring_emit_cntxcntl (struct amdgpu_ring *ring,uint32_t flags) {u32 dw2 =0x80000000 ;/* set load_enable otherwise this package is just NOPs */
@@ -3551,11 +3537,12 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = { .emit_frame_size =5 +5 +/* hdp flush / invalidate */ 14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ -7 +4 +/* gfx_v6_0_ring_emit_pipeline_sync */ -SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +6 +/* gfx_v6_0_ring_emit_vm_flush */ +7 +/* gfx_v6_0_ring_emit_pipeline_sync */ +SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +2 +/* gfx_v6_0_ring_emit_vm_flush */ +3 *2 +/* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 3 +2 +2 +/* gfx_v6_ring_emit_cntxcntl including VGT flush */ 5, /* SURFACE_SYNC */ - .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ + .emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib, .emit_fence = gfx_v6_0_ring_emit_fence, .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
@@ -3563,6 +3550,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = { .test_ring = gfx_v6_0_ring_test_ring, .test_ib = gfx_v6_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .emit_switch_buffer = gfx_v6_0_ring_emit_sb, .emit_cntxcntl = gfx_v6_ring_emit_cntxcntl, .emit_wreg = gfx_v6_0_ring_emit_wreg, .emit_mem_sync = gfx_v6_0_emit_mem_sync,
@@ -3580,8 +3568,9 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {7 +/* gfx_v6_0_ring_emit_pipeline_sync */ SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +/* gfx_v6_0_ring_emit_vm_flush */ 14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ +3 *2 +/* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 5, /* SURFACE_SYNC */ - .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ + .emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib, .emit_fence = gfx_v6_0_ring_emit_fence, .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
@@ -3589,6 +3578,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = { .test_ring = gfx_v6_0_ring_test_ring, .test_ib = gfx_v6_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .emit_switch_buffer = gfx_v6_0_ring_emit_sb, .emit_wreg = gfx_v6_0_ring_emit_wreg, .emit_mem_sync = gfx_v6_0_emit_mem_sync, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 944/1376 drm/amdgpu/gfx6: Use PFP on the compute queues too
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 60f20946cd318518ddc2c0da12103c666b2b9564 ]
On GFX6, the compute rings use the same CP path as the graphics ring. The only difference is that they don't support draw commands. (As opposed to GFX7 and newer which have a separate command parser that is called MEC for compute queues.)
This means that we have to take into consideration that the PFP also exists on compute queues on GFX6:
Use PFP for register writes on both graphics and compute queues.
In the pipeline sync, use the PFP to wait for the previous fence (and not the ME) to prevent the PFP from starting to execute the next submission while the ME is still in the previous submission.
After a VM flush, emit PFP_SYNC_ME on compute queues as well.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +4 -4
@@ -2325,7 +2325,7 @@ static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)static void gfx_v6_0_ring_emit_pipeline_sync (struct amdgpu_ring *ring) { -int usepfp = (ring->funcs->type ==AMDGPU_RING_TYPE_GFX ); +int usepfp =1 ;uint32_t seq = ring->fence_drv.sync_seq;uint64_t addr = ring->fence_drv.gpu_addr;
@@ -2343,7 +2343,7 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)static void gfx_v6_0_ring_emit_vm_flush (struct amdgpu_ring *ring,unsigned vmid,uint64_t pd_addr) { -int usepfp = (ring->funcs->type ==AMDGPU_RING_TYPE_GFX ); +int usepfp =1 ;amdgpu_gmc_emit_flush_gpu_tlb (ring, vmid, pd_addr);
@@ -2367,7 +2367,7 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,static void gfx_v6_0_ring_emit_wreg (struct amdgpu_ring *ring,uint32_t reg,uint32_t val) { -int usepfp = (ring->funcs->type ==AMDGPU_RING_TYPE_GFX ); +int usepfp =1 ;amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
@@ -3566,7 +3566,7 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = { .emit_frame_size =5 +5 +/* hdp flush / invalidate */ 7 +/* gfx_v6_0_ring_emit_pipeline_sync */ -SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +/* gfx_v6_0_ring_emit_vm_flush */ +SI_FLUSH_GPU_TLB_NUM_WREG *5 +7 +2 +/* gfx_v6_0_ring_emit_vm_flush */ 14 +14 +14 +/* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ 3 *2 +/* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 5, /* SURFACE_SYNC */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 945/1376 scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manish Rangankar <[email protected]>
[ Upstream commit 5cbc49d5c4cd20c18041e86958103045216d2190 ]
qla2x00_sysfs_read_vpd() called ha->isp_ops->read_optrom() a second time after releasing optrom_mutex. The repeated read is redundant and, unlike the first, runs without optrom_mutex held, exposing flash access to concurrent optrom operations. Drop the duplicate call.
--- drivers/scsi/qla2xxx/qla_attr.c | 1 - 1 file changed, 1 deletion(-)
drivers/scsi/qla2xxx/qla_attr.c +0 -1
@@ -580,7 +580,6 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, ha->isp_ops->read_optrom (vha, ha->vpd, faddr, ha->vpd_size);mutex_unlock (&ha->optrom_mutex); - ha->isp_ops->read_optrom (vha, ha->vpd, faddr, ha->vpd_size); skip:return memory_read_from_buffer (buf, count, &off, ha->vpd, ha->vpd_size); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 946/1376 firmware_loader: do not queue completed sysfs fallback requests
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit b48373c901951fad1a26bd7c33ad91172b3945b5 ]
fw_load_sysfs_fallback() calls device_add() before adding the fw_priv to pending_fw_head. device_add() publishes the fallback loading interface, so a userspace helper which discovers the device by scanning sysfs can write 0 to the loading attribute and complete the request before it is queued as pending.
In that interleaving firmware_loading_store() calls fw_state_done() while pending_list still points to itself, so it cannot remove an entry from pending_fw_head. The subsequent unconditional list_add() then queues an already-completed fw_priv. Once the request is released, pending_fw_head can retain a pointer to freed memory and the next fallback request can fault while validating the list.
Only in-flight fallback requests need suspend or reboot abort handling. If the request is already DONE after device_add(), return success from the fallback path without sending another uevent, waiting again, or queueing it as pending. This preserves the invariant that pending_fw_head contains only active fallback requests.
--- drivers/base/firmware_loader/fallback.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/base/firmware_loader/fallback.c +10 -0
@@ -95,6 +95,16 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout) retval = -EINTR ; goto out; } + +/* +* device_add() exposes the loading interface before pending_list is +* linked into pending_fw_head, so fw_state_done() may run first. +*/ +if (fw_state_is_done (fw_priv)) { +mutex_unlock (&fw_lock); + goto out; + } +list_add (&fw_priv->pending_list, &pending_fw_head);mutex_unlock (&fw_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 947/1376 pinctrl: rockchip: Reset the pin count when recalculating SoC data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Simon Glass <[email protected]>
[ Upstream commit 5b695c191cc85f0fd62eec885b55d01468dc9f2c ]
rockchip_pinctrl_get_soc_data() mutates the static per-SoC data. The iomux and drive offsets are recalculated idempotently, since a rerun anchors at the values calculated before, but the total pin count only
accumulates: each run adds every bank's pins again. When the probe is deferred and runs a second time, nr_pins doubles and every bank's pin_base shifts, so later pin lookups resolve to the wrong bank and the wrong registers.
Reset the pin count at the start of the calculation, so that a rerun produces the same values.
This is verified on a Luckfox Pico Mini B (RV1103, with the pending RV1106 series applied) by forcing the probe to defer once: without this patch the second probe calculates nr_pins=304 instead of 152 and no GPIO bank comes up; with it the recalculation matches the first run and all banks work.
--- drivers/pinctrl/pinctrl-rockchip.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/pinctrl/pinctrl-rockchip.c +10 -0
@@ -3409,6 +3409,16 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( pmu_offs = ctrl->pmu_mux_offset; drv_pmu_offs = ctrl->pmu_drv_offset; drv_grf_offs = ctrl->grf_drv_offset; + +/* +* This function mutates the static per-SoC data. Most of it is +* idempotent: recalculated iomux and drv offsets anchor at the +* values calculated by a previous run. The pin count is not, so +* reset it here; otherwise it accumulates when the probe runs +* again after a probe deferral, shifting every bank's pin_base. +*/ + ctrl->nr_pins =0 ; + bank = ctrl->pin_banks;for (i =0 ; i < ctrl->nr_banks; ++i, ++bank) {int bank_pins =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 948/1376 hugetlbfs: release subpool on fill_super failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 308ab73e97c87bd0e142b11758faab7f88d82854 ]
hugetlbfs_fill_super() allocates a hugepage subpool when size or min_size mount options are specified. hugepage_new_subpool() may also reserve huge pages for min_size.
If root dentry creation fails after the subpool is created, the failure path frees the subpool with kfree(). This bypasses hugepage_put_subpool() and can leave min_size reservations charged.
Use hugepage_put_subpool() on the failure path, matching the normal put_super path.
--- fs/hugetlbfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/hugetlbfs/inode.c +2 -1
@@ -1506,7 +1506,8 @@ hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out_free;return 0 ; out_free: -kfree (sbinfo->spool); +if (sbinfo->spool) +hugepage_put_subpool (sbinfo->spool);kfree (sbinfo);return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 949/1376 soc: fsl: qe: check platform_driver_register() in qe_ic_of_init()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
[ Upstream commit fbdba2a67fa7c0e7570bcbf9f28b782d6100270d ]
qe_ic_of_init() ignored the return value of platform_driver_register() and always returned success. Propagate the error to the initcall.
--- drivers/soc/fsl/qe/qe_ic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/soc/fsl/qe/qe_ic.c +1 -2
@@ -481,7 +481,6 @@ static struct platform_driver qe_ic_driver =static int __init qe_ic_of_init (void ) { -platform_driver_register (&qe_ic_driver); -return 0 ; +return platform_driver_register (&qe_ic_driver); }subsys_initcall (qe_ic_of_init);
Signature · 1 line
2.53.0